Merge pull request #53 from SyncrowIOT/routines

Routines
This commit is contained in:
Abdullah
2024-11-28 11:53:43 +03:00
committed by GitHub
27 changed files with 1281 additions and 503 deletions

View File

@ -18,13 +18,13 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => DeviceManagementBloc()..add(FetchDevices()),
),
BlocProvider(
create: (context) =>
SwitchTabsBloc()..add(const TriggerSwitchTabsEvent(false)),
),
BlocProvider(
create: (context) => DeviceManagementBloc()..add(FetchDevices()),
),
],
child: WebScaffold(
appBarTitle: FittedBox(
@ -101,12 +101,11 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
builder: (context, deviceState) {
if (deviceState is DeviceManagementLoading) {
return const Center(child: CircularProgressIndicator());
} else if (deviceState is DeviceManagementLoaded ||
deviceState is DeviceManagementFiltered) {
final devices = (deviceState as dynamic).devices ??
(deviceState as DeviceManagementFiltered).filteredDevices;
return DeviceManagementBody(devices: devices);
} else if (deviceState is DeviceManagementLoaded) {
return DeviceManagementBody(devices: deviceState.devices);
} else if (deviceState is DeviceManagementFiltered) {
return DeviceManagementBody(
devices: deviceState.filteredDevices);
} else {
return const Center(child: Text('Error fetching Devices'));
}

View File

@ -18,14 +18,6 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
final TextEditingController unitNameController = TextEditingController();
final TextEditingController productNameController = TextEditingController();
@override
void dispose() {
communityController.dispose();
unitNameController.dispose();
productNameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return isExtraLargeScreenSize(context)

View File

@ -6,6 +6,7 @@ import 'package:flutter/material.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/device_functions.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/services/routines_api.dart';
@ -13,6 +14,7 @@ part 'routine_event.dart';
part 'routine_state.dart';
const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
const communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
RoutineBloc() : super(const RoutineState()) {
@ -30,6 +32,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
on<CreateAutomationEvent>(_onCreateAutomation);
on<SetRoutineName>(_onSetRoutineName);
on<ResetRoutineState>(_onResetRoutineState);
on<GetSceneDetails>(_onGetSceneDetails);
on<GetAutomationDetails>(_onGetAutomationDetails);
// on<InitializeRoutineState>(_onInitializeRoutineState);
on<DeleteScene>(_deleteScene);
on<DeleteAutomation>(_deleteAutomation);
// on<RemoveFunction>(_onRemoveFunction);
// on<ClearFunctions>(_onClearFunctions);
}
@ -38,8 +45,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final updatedIfItems = List<Map<String, dynamic>>.from(state.ifItems);
// Find the index of the item in teh current itemsList
int index =
updatedIfItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
int index = updatedIfItems.indexWhere(
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
// Replace the map if the index is valid
if (index != -1) {
updatedIfItems[index] = event.item;
@ -48,18 +55,21 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
if (event.isTabToRun) {
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
emit(state.copyWith(
ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
} else {
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
emit(state.copyWith(
ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
}
}
void _onAddToThenContainer(AddToThenContainer event, Emitter<RoutineState> emit) {
void _onAddToThenContainer(
AddToThenContainer event, Emitter<RoutineState> emit) {
final currentItems = List<Map<String, dynamic>>.from(state.thenItems);
// Find the index of the item in teh current itemsList
int index =
currentItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
int index = currentItems.indexWhere(
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
// Replace the map if the index is valid
if (index != -1) {
currentItems[index] = event.item;
@ -70,22 +80,26 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
emit(state.copyWith(thenItems: currentItems));
}
void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter<RoutineState> emit) {
void _onAddFunctionsToRoutine(
AddFunctionToRoutine event, Emitter<RoutineState> emit) {
try {
if (event.functions.isEmpty) return;
List<DeviceFunctionData> selectedFunction = List<DeviceFunctionData>.from(event.functions);
List<DeviceFunctionData> selectedFunction =
List<DeviceFunctionData>.from(event.functions);
Map<String, List<DeviceFunctionData>> currentSelectedFunctions =
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
List<DeviceFunctionData> currentFunctions =
List<DeviceFunctionData>.from(currentSelectedFunctions[event.uniqueCustomId] ?? []);
List<DeviceFunctionData>.from(
currentSelectedFunctions[event.uniqueCustomId] ?? []);
List<String> functionCode = [];
for (int i = 0; i < selectedFunction.length; i++) {
for (int j = 0; j < currentFunctions.length; j++) {
if (selectedFunction[i].functionCode == currentFunctions[j].functionCode) {
if (selectedFunction[i].functionCode ==
currentFunctions[j].functionCode) {
currentFunctions[j] = selectedFunction[i];
if (!functionCode.contains(currentFunctions[j].functionCode)) {
functionCode.add(currentFunctions[j].functionCode);
@ -95,13 +109,15 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
for (int i = 0; i < functionCode.length; i++) {
selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]);
selectedFunction
.removeWhere((code) => code.functionCode == functionCode[i]);
}
currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions)
..addAll(selectedFunction);
currentSelectedFunctions[event.uniqueCustomId] =
List.from(currentFunctions)..addAll(selectedFunction);
} else {
currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions);
currentSelectedFunctions[event.uniqueCustomId] =
List.from(event.functions);
}
emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
@ -110,11 +126,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
}
Future<void> _onLoadScenes(LoadScenes event, Emitter<RoutineState> emit) async {
Future<void> _onLoadScenes(
LoadScenes event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true, errorMessage: null));
try {
final scenes = await SceneApi.getScenesByUnitId(event.unitId);
final scenes =
await SceneApi.getScenesByUnitId(event.unitId, event.communityId);
emit(state.copyWith(
scenes: scenes,
isLoading: false,
@ -129,7 +147,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
}
Future<void> _onLoadAutomation(LoadAutomation event, Emitter<RoutineState> emit) async {
Future<void> _onLoadAutomation(
LoadAutomation event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true, errorMessage: null));
try {
@ -157,14 +176,16 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
}
FutureOr<void> _onSearchRoutines(SearchRoutines event, Emitter<RoutineState> emit) async {
FutureOr<void> _onSearchRoutines(
SearchRoutines event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true, errorMessage: null));
await Future.delayed(const Duration(seconds: 1));
emit(state.copyWith(isLoading: false, errorMessage: null));
emit(state.copyWith(searchText: event.query));
}
FutureOr<void> _onAddSelectedIcon(AddSelectedIcon event, Emitter<RoutineState> emit) {
FutureOr<void> _onAddSelectedIcon(
AddSelectedIcon event, Emitter<RoutineState> emit) {
emit(state.copyWith(selectedIcon: event.icon));
}
@ -173,7 +194,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
return actions.first['deviceId'] == 'delay';
}
Future<void> _onCreateScene(CreateSceneEvent event, Emitter<RoutineState> emit) async {
Future<void> _onCreateScene(
CreateSceneEvent event, Emitter<RoutineState> emit) async {
try {
// Check if first action is delay
if (_isFirstActionDelay(state.thenItems)) {
@ -233,7 +255,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final result = await SceneApi.createScene(createSceneModel);
if (result['success']) {
emit(_resetState());
add(const LoadScenes(spaceId));
add(const LoadScenes(spaceId, communityId));
} else {
emit(state.copyWith(
isLoading: false,
@ -248,7 +270,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
}
Future<void> _onCreateAutomation(CreateAutomationEvent event, Emitter<RoutineState> emit) async {
Future<void> _onCreateAutomation(
CreateAutomationEvent event, Emitter<RoutineState> emit) async {
try {
if (state.routineName == null || state.routineName!.isEmpty) {
emit(state.copyWith(
@ -348,21 +371,34 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
}
FutureOr<void> _onRemoveDragCard(RemoveDragCard event, Emitter<RoutineState> emit) {
FutureOr<void> _onRemoveDragCard(
RemoveDragCard event, Emitter<RoutineState> emit) {
if (event.isFromThen) {
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
final selectedFunctions =
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
thenItems.removeAt(event.index);
selectedFunctions.remove(event.key);
emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions));
emit(state.copyWith(
thenItems: thenItems, selectedFunctions: selectedFunctions));
} else {
final ifItems = List<Map<String, dynamic>>.from(state.ifItems);
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
final selectedFunctions =
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
ifItems.removeAt(event.index);
selectedFunctions.remove(event.key);
emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions));
if (ifItems.isEmpty && state.thenItems.isEmpty) {
emit(state.copyWith(
ifItems: ifItems,
selectedFunctions: selectedFunctions,
isAutomation: false,
isTabToRun: false));
} else {
emit(state.copyWith(
ifItems: ifItems, selectedFunctions: selectedFunctions));
}
}
}
@ -373,14 +409,134 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
));
}
FutureOr<void> _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
FutureOr<void> _onEffectiveTimeEvent(
EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
emit(state.copyWith(effectiveTime: event.effectiveTime));
}
FutureOr<void> _onSetRoutineName(SetRoutineName event, Emitter<RoutineState> emit) {
FutureOr<void> _onSetRoutineName(
SetRoutineName event, Emitter<RoutineState> emit) {
emit(state.copyWith(routineName: event.name));
}
Future<void> _onGetSceneDetails(
GetSceneDetails event, Emitter<RoutineState> emit) async {
try {
emit(state.copyWith(
isLoading: true,
isTabToRun: event.isTabToRun,
isUpdate: true,
sceneId: event.sceneId,
isAutomation: false));
final sceneDetails = await SceneApi.getSceneDetails(event.sceneId);
add(InitializeRoutineState(sceneDetails));
} catch (e) {
emit(state.copyWith(
isLoading: false,
errorMessage: 'Failed to load scene details',
));
}
}
Future<void> _onGetAutomationDetails(
GetAutomationDetails event, Emitter<RoutineState> emit) async {
try {
emit(state.copyWith(
isLoading: true,
isAutomation: event.isAutomation,
automationId: event.automationId,
isTabToRun: false,
isUpdate: true,
));
final automationDetails =
await SceneApi.getAutomationDetails(event.automationId);
add(InitializeRoutineState(automationDetails));
} catch (e) {
emit(state.copyWith(
isLoading: false,
errorMessage: 'Failed to load automation details',
));
}
}
// 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() {
return const RoutineState(
ifItems: [],
@ -396,13 +552,44 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
selectedIcon: null,
isTabToRun: false,
isAutomation: false,
selectedAutomationOperator: 'AND',
selectedAutomationOperator: 'or',
effectiveTime: null,
routineName: null,
);
}
FutureOr<void> _onResetRoutineState(ResetRoutineState event, Emitter<RoutineState> emit) {
FutureOr<void> _onResetRoutineState(
ResetRoutineState event, Emitter<RoutineState> emit) {
emit(_resetState());
}
FutureOr<void> _deleteScene(DeleteScene event, Emitter<RoutineState> emit) {
try {
// emit(state.copyWith(isLoading: true));
SceneApi.deleteScene(unitUuid: spaceId, sceneId: event.sceneId);
add(const LoadScenes(spaceId, communityId));
//emit(_resetState());
} catch (e) {
emit(state.copyWith(
isLoading: false,
errorMessage: 'Failed to delete scene',
));
}
}
FutureOr<void> _deleteAutomation(
DeleteAutomation event, Emitter<RoutineState> emit) {
try {
//emit(state.copyWith(isLoading: true));
SceneApi.deleteAutomation(
unitUuid: spaceId, automationId: event.automationId);
add(const LoadAutomation(spaceId));
// emit(_resetState());
} catch (e) {
emit(state.copyWith(
isLoading: false,
errorMessage: 'Failed to delete automation',
));
}
}
}

View File

@ -28,11 +28,12 @@ class AddToThenContainer extends RoutineEvent {
class LoadScenes extends RoutineEvent {
final String unitId;
final String communityId;
const LoadScenes(this.unitId);
const LoadScenes(this.unitId, this.communityId);
@override
List<Object> get props => [unitId];
List<Object> get props => [unitId, communityId];
}
class LoadAutomation extends RoutineEvent {
@ -124,6 +125,55 @@ class SetRoutineName extends RoutineEvent {
List<Object> get props => [name];
}
class GetSceneDetails extends RoutineEvent {
final String sceneId;
final bool isUpdate;
final bool isTabToRun;
const GetSceneDetails({
required this.sceneId,
required this.isUpdate,
required this.isTabToRun,
});
@override
List<Object> get props => [sceneId];
}
class GetAutomationDetails extends RoutineEvent {
final String automationId;
final bool isUpdate;
final bool isAutomation;
const GetAutomationDetails({
required this.automationId,
this.isUpdate = false,
this.isAutomation = false,
});
@override
List<Object> get props => [automationId];
}
class InitializeRoutineState extends RoutineEvent {
final RoutineDetailsModel routineDetails;
const InitializeRoutineState(this.routineDetails);
@override
List<Object> get props => [routineDetails];
}
class DeleteScene extends RoutineEvent {
final String sceneId;
final String unitUuid;
const DeleteScene({required this.sceneId, required this.unitUuid});
@override
List<Object> get props => [sceneId];
}
class DeleteAutomation extends RoutineEvent {
final String automationId;
final String unitUuid;
const DeleteAutomation({required this.automationId, required this.unitUuid});
@override
List<Object> get props => [automationId];
}
class ResetRoutineState extends RoutineEvent {}
class ClearFunctions extends RoutineEvent {}

View File

@ -18,6 +18,9 @@ class RoutineState extends Equatable {
final bool isAutomation;
final String selectedAutomationOperator;
final EffectiveTime? effectiveTime;
final String? sceneId;
final String? automationId;
final bool? isUpdate;
const RoutineState({
this.ifItems = const [],
@ -37,6 +40,9 @@ class RoutineState extends Equatable {
this.isAutomation = false,
this.selectedAutomationOperator = 'or',
this.effectiveTime,
this.sceneId,
this.automationId,
this.isUpdate,
});
RoutineState copyWith({
@ -56,6 +62,9 @@ class RoutineState extends Equatable {
bool? isAutomation,
String? selectedAutomationOperator,
EffectiveTime? effectiveTime,
String? sceneId,
String? automationId,
bool? isUpdate,
}) {
return RoutineState(
ifItems: ifItems ?? this.ifItems,
@ -77,6 +86,9 @@ class RoutineState extends Equatable {
selectedAutomationOperator:
selectedAutomationOperator ?? this.selectedAutomationOperator,
effectiveTime: effectiveTime ?? this.effectiveTime,
sceneId: sceneId ?? this.sceneId,
automationId: automationId ?? this.automationId,
isUpdate: isUpdate ?? this.isUpdate,
);
}
@ -97,6 +109,9 @@ class RoutineState extends Equatable {
isTabToRun,
isAutomation,
selectedAutomationOperator,
effectiveTime
effectiveTime,
sceneId,
automationId,
isUpdate
];
}

View File

@ -10,8 +10,9 @@ import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
class DeviceDialogHelper {
static Future<Map<String, dynamic>?> showDeviceDialog(
BuildContext context,
Map<String, dynamic> data,
) async {
Map<String, dynamic> data, {
required bool removeComparetors,
}) async {
final functions = data['functions'] as List<DeviceFunction>;
try {
@ -20,6 +21,7 @@ class DeviceDialogHelper {
data['productType'],
data,
functions,
removeComparetors: removeComparetors,
);
if (result != null) {
@ -33,34 +35,49 @@ class DeviceDialogHelper {
}
static Future<Map<String, dynamic>?> _getDialogForDeviceType(
BuildContext context,
String productType,
Map<String, dynamic> data,
List<DeviceFunction> functions,
) async {
BuildContext context,
String productType,
Map<String, dynamic> data,
List<DeviceFunction> functions,
{required bool removeComparetors}) async {
final routineBloc = context.read<RoutineBloc>();
final deviceSelectedFunctions =
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
switch (productType) {
case 'AC':
return ACHelper.showACFunctionsDialog(context, functions,
data['device'], deviceSelectedFunctions, data['uniqueCustomId']);
return ACHelper.showACFunctionsDialog(
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
removeComparetors);
case '1G':
return OneGangSwitchHelper.showSwitchFunctionsDialog(context, functions,
data['device'], deviceSelectedFunctions, data['uniqueCustomId']);
return OneGangSwitchHelper.showSwitchFunctionsDialog(
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
removeComparetors);
case '2G':
return TwoGangSwitchHelper.showSwitchFunctionsDialog(context, functions,
data['device'], deviceSelectedFunctions, data['uniqueCustomId']);
return TwoGangSwitchHelper.showSwitchFunctionsDialog(
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
removeComparetors);
case '3G':
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
);
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
removeComparetors);
default:
return null;
}

View File

@ -8,8 +8,8 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class SaveRoutineHelper {
static Future<void> showSaveRoutineDialog(BuildContext context) async {
return showDialog<void>(
static Future<bool?> showSaveRoutineDialog(BuildContext context) async {
return showDialog<bool?>(
context: context,
builder: (BuildContext context) {
return BlocBuilder<RoutineBloc, RoutineState>(
@ -54,27 +54,23 @@ class SaveRoutineHelper {
),
if (state.isAutomation)
...state.ifItems.map((item) {
final functions = state.selectedFunctions[
item['uniqueCustomId']] ??
[];
final functions =
state.selectedFunctions[item['uniqueCustomId']] ?? [];
return ListTile(
leading: SvgPicture.asset(
item['imagePath'],
width: 22,
height: 22,
),
title: Text(item['title'],
style: const TextStyle(fontSize: 14)),
title:
Text(item['title'], style: const TextStyle(fontSize: 14)),
subtitle: Wrap(
children: functions
.map((f) => Text(
'${f.operationName}: ${f.value}, ',
style: const TextStyle(
color: ColorsManager
.grayColor,
fontSize: 8),
overflow:
TextOverflow.ellipsis,
color: ColorsManager.grayColor, fontSize: 8),
overflow: TextOverflow.ellipsis,
maxLines: 3,
))
.toList(),
@ -99,25 +95,22 @@ class SaveRoutineHelper {
),
const SizedBox(height: 8),
...state.thenItems.map((item) {
final functions = state.selectedFunctions[
item['uniqueCustomId']] ??
[];
final functions =
state.selectedFunctions[item['uniqueCustomId']] ?? [];
return ListTile(
leading: SvgPicture.asset(
item['imagePath'],
width: 22,
height: 22,
),
title: Text(item['title'],
style: const TextStyle(fontSize: 14)),
title:
Text(item['title'], style: const TextStyle(fontSize: 14)),
subtitle: Wrap(
children: functions
.map((f) => Text(
'${f.operationName}: ${f.value}, ',
style: const TextStyle(
color:
ColorsManager.grayColor,
fontSize: 8),
color: ColorsManager.grayColor, fontSize: 8),
overflow: TextOverflow.ellipsis,
maxLines: 3,
))
@ -140,19 +133,15 @@ class SaveRoutineHelper {
),
),
DialogFooter(
onCancel: () => Navigator.pop(context),
onCancel: () => Navigator.pop(context, false),
onConfirm: () {
if (state.isAutomation) {
context
.read<RoutineBloc>()
.add(const CreateAutomationEvent());
context.read<RoutineBloc>().add(const CreateAutomationEvent());
} else {
context
.read<RoutineBloc>()
.add(const CreateSceneEvent());
context.read<RoutineBloc>().add(const CreateSceneEvent());
}
Navigator.pop(context);
Navigator.pop(context, true);
},
isConfirmEnabled: true,
),

View File

@ -1,177 +1,5 @@
import 'dart:convert';
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart';
// class CreateAutomationModel {
// String unitUuid;
// String automationName;
// String decisionExpr;
// EffectiveTime effectiveTime;
// List<CreateCondition> conditions;
// List<CreateSceneAction> actions;
// CreateAutomationModel({
// required this.unitUuid,
// required this.automationName,
// required this.decisionExpr,
// required this.effectiveTime,
// required this.conditions,
// required this.actions,
// });
// CreateAutomationModel copyWith({
// String? unitUuid,
// String? automationName,
// String? decisionExpr,
// EffectiveTime? effectiveTime,
// List<CreateCondition>? conditions,
// List<CreateSceneAction>? actions,
// }) {
// return CreateAutomationModel(
// unitUuid: unitUuid ?? this.unitUuid,
// automationName: automationName ?? this.automationName,
// decisionExpr: decisionExpr ?? this.decisionExpr,
// effectiveTime: effectiveTime ?? this.effectiveTime,
// conditions: conditions ?? this.conditions,
// actions: actions ?? this.actions,
// );
// }
// Map<String, dynamic> toMap([String? automationId]) {
// return {
// if (automationId == null) 'spaceUuid': unitUuid,
// 'automationName': automationName,
// 'decisionExpr': decisionExpr,
// 'effectiveTime': effectiveTime.toMap(),
// 'conditions': conditions.map((x) => x.toMap()).toList(),
// 'actions': actions.map((x) => x.toMap()).toList(),
// };
// }
// factory CreateAutomationModel.fromMap(Map<String, dynamic> map) {
// return CreateAutomationModel(
// unitUuid: map['spaceUuid'] ?? '',
// automationName: map['automationName'] ?? '',
// decisionExpr: map['decisionExpr'] ?? '',
// effectiveTime: EffectiveTime.fromMap(map['effectiveTime']),
// conditions: List<CreateCondition>.from(
// map['conditions']?.map((x) => CreateCondition.fromMap(x))),
// actions: List<CreateSceneAction>.from(
// map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
// );
// }
// String toJson([String? automationId]) => json.encode(toMap(automationId));
// factory CreateAutomationModel.fromJson(String source) =>
// CreateAutomationModel.fromMap(json.decode(source));
// @override
// String toString() {
// return 'CreateAutomationModel(unitUuid: $unitUuid, automationName: $automationName, decisionExpr: $decisionExpr, effectiveTime: $effectiveTime, conditions: $conditions, actions: $actions)';
// }
// }
// class EffectiveTime {
// String start;
// String end;
// String loops;
// EffectiveTime({
// required this.start,
// required this.end,
// required this.loops,
// });
// Map<String, dynamic> toMap() {
// return {
// 'start': start,
// 'end': end,
// 'loops': loops,
// };
// }
// factory EffectiveTime.fromMap(Map<String, dynamic> map) {
// return EffectiveTime(
// start: map['start'] ?? '',
// end: map['end'] ?? '',
// loops: map['loops'] ?? '',
// );
// }
// @override
// String toString() => 'EffectiveTime(start: $start, end: $end, loops: $loops)';
// }
// class CreateCondition {
// int code;
// String entityId;
// String entityType;
// ConditionExpr expr;
// CreateCondition({
// required this.code,
// required this.entityId,
// required this.entityType,
// required this.expr,
// });
// Map<String, dynamic> toMap() {
// return {
// 'code': code,
// 'entityId': entityId,
// 'entityType': entityType,
// 'expr': expr.toMap(),
// };
// }
// factory CreateCondition.fromMap(Map<String, dynamic> map) {
// return CreateCondition(
// code: map['code'] ?? 0,
// entityId: map['entityId'] ?? '',
// entityType: map['entityType'] ?? '',
// expr: ConditionExpr.fromMap(map['expr']),
// );
// }
// @override
// String toString() =>
// 'CreateCondition(code: $code, entityId: $entityId, entityType: $entityType, expr: $expr)';
// }
// class ConditionExpr {
// String statusCode;
// String comparator;
// dynamic statusValue;
// ConditionExpr({
// required this.statusCode,
// required this.comparator,
// required this.statusValue,
// });
// Map<String, dynamic> toMap() {
// return {
// 'statusCode': statusCode,
// 'comparator': comparator,
// 'statusValue': statusValue,
// };
// }
// factory ConditionExpr.fromMap(Map<String, dynamic> map) {
// return ConditionExpr(
// statusCode: map['statusCode'] ?? '',
// comparator: map['comparator'] ?? '',
// statusValue: map['statusValue'],
// );
// }
// @override
// String toString() =>
// 'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)';
// }
import 'dart:convert';
class CreateAutomationModel {
String spaceUuid;
String automationName;

View File

@ -0,0 +1,262 @@
import 'dart:convert';
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';
class RoutineDetailsModel {
final String spaceUuid;
final String name;
final String decisionExpr;
final List<RoutineAction> actions;
final String? iconId;
final bool? showInDevice;
final EffectiveTime? effectiveTime;
final List<RoutineCondition>? conditions;
final String? type;
RoutineDetailsModel({
required this.spaceUuid,
required this.name,
required this.decisionExpr,
required this.actions,
this.iconId,
this.showInDevice,
this.effectiveTime,
this.conditions,
this.type,
});
// Convert to CreateSceneModel
CreateSceneModel toCreateSceneModel() {
return CreateSceneModel(
spaceUuid: spaceUuid,
iconId: iconId ?? '',
showInDevice: showInDevice ?? false,
sceneName: name,
decisionExpr: decisionExpr,
actions: actions.map((a) => a.toCreateSceneAction()).toList(),
);
}
// Convert to CreateAutomationModel
CreateAutomationModel toCreateAutomationModel() {
return CreateAutomationModel(
spaceUuid: spaceUuid,
automationName: name,
decisionExpr: decisionExpr,
effectiveTime:
effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
conditions: conditions?.map((c) => c.toCondition()).toList() ?? [],
actions: actions.map((a) => a.toAutomationAction()).toList(),
);
}
Map<String, dynamic> toMap() {
return {
'spaceUuid': spaceUuid,
'name': name,
'decisionExpr': decisionExpr,
'actions': actions.map((x) => x.toMap()).toList(),
if (iconId != null) 'iconId': iconId,
if (showInDevice != null) 'showInDevice': showInDevice,
if (effectiveTime != null) 'effectiveTime': effectiveTime!.toMap(),
if (conditions != null)
'conditions': conditions!.map((x) => x.toMap()).toList(),
if (type != null) 'type': type,
};
}
factory RoutineDetailsModel.fromMap(Map<String, dynamic> map) {
return RoutineDetailsModel(
spaceUuid: map['spaceUuid'] ?? '',
name: map['name'] ?? '',
decisionExpr: map['decisionExpr'] ?? '',
actions: List<RoutineAction>.from(
map['actions']?.map((x) => RoutineAction.fromMap(x)) ?? [],
),
iconId: map['iconId'],
showInDevice: map['showInDevice'],
effectiveTime: map['effectiveTime'] != null
? EffectiveTime.fromMap(map['effectiveTime'])
: null,
conditions: map['conditions'] != null
? List<RoutineCondition>.from(
map['conditions'].map((x) => RoutineCondition.fromMap(x)))
: null,
type: map['type'],
);
}
String toJson() => json.encode(toMap());
factory RoutineDetailsModel.fromJson(String source) =>
RoutineDetailsModel.fromMap(json.decode(source));
}
class RoutineAction {
final String entityId;
final String actionExecutor;
final RoutineExecutorProperty? executorProperty;
RoutineAction({
required this.entityId,
required this.actionExecutor,
this.executorProperty,
});
CreateSceneAction toCreateSceneAction() {
return CreateSceneAction(
entityId: entityId,
actionExecutor: actionExecutor,
executorProperty: executorProperty?.toCreateSceneExecutorProperty(),
);
}
AutomationAction toAutomationAction() {
return AutomationAction(
entityId: entityId,
actionExecutor: actionExecutor,
executorProperty: executorProperty?.toExecutorProperty(),
);
}
Map<String, dynamic> toMap() {
return {
'entityId': entityId,
'actionExecutor': actionExecutor,
if (executorProperty != null)
'executorProperty': executorProperty!.toMap(),
};
}
factory RoutineAction.fromMap(Map<String, dynamic> map) {
return RoutineAction(
entityId: map['entityId'] ?? '',
actionExecutor: map['actionExecutor'] ?? '',
executorProperty: map['executorProperty'] != null
? RoutineExecutorProperty.fromMap(map['executorProperty'])
: null,
);
}
}
class RoutineExecutorProperty {
final String? functionCode;
final dynamic functionValue;
final int? delaySeconds;
RoutineExecutorProperty({
this.functionCode,
this.functionValue,
this.delaySeconds,
});
CreateSceneExecutorProperty toCreateSceneExecutorProperty() {
return CreateSceneExecutorProperty(
functionCode: functionCode ?? '',
functionValue: functionValue,
delaySeconds: delaySeconds ?? 0,
);
}
ExecutorProperty toExecutorProperty() {
return ExecutorProperty(
functionCode: functionCode,
functionValue: functionValue,
delaySeconds: delaySeconds,
);
}
Map<String, dynamic> toMap() {
return {
if (functionCode != null) 'functionCode': functionCode,
if (functionValue != null) 'functionValue': functionValue,
if (delaySeconds != null) 'delaySeconds': delaySeconds,
};
}
factory RoutineExecutorProperty.fromMap(Map<String, dynamic> map) {
return RoutineExecutorProperty(
functionCode: map['functionCode'],
functionValue: map['functionValue'],
delaySeconds: map['delaySeconds']?.toInt(),
);
}
}
class RoutineCondition {
final int code;
final String entityId;
final String entityType;
final RoutineConditionExpr expr;
RoutineCondition({
required this.code,
required this.entityId,
required this.entityType,
required this.expr,
});
Condition toCondition() {
return Condition(
code: code,
entityId: entityId,
entityType: entityType,
expr: expr.toConditionExpr(),
);
}
Map<String, dynamic> toMap() {
return {
'code': code,
'entityId': entityId,
'entityType': entityType,
'expr': expr.toMap(),
};
}
factory RoutineCondition.fromMap(Map<String, dynamic> map) {
return RoutineCondition(
code: map['code']?.toInt() ?? 0,
entityId: map['entityId'] ?? '',
entityType: map['entityType'] ?? '',
expr: RoutineConditionExpr.fromMap(map['expr']),
);
}
}
class RoutineConditionExpr {
final String statusCode;
final String comparator;
final dynamic statusValue;
RoutineConditionExpr({
required this.statusCode,
required this.comparator,
required this.statusValue,
});
ConditionExpr toConditionExpr() {
return ConditionExpr(
statusCode: statusCode,
comparator: comparator,
statusValue: statusValue,
);
}
Map<String, dynamic> toMap() {
return {
'statusCode': statusCode,
'comparator': comparator,
'statusValue': statusValue,
};
}
factory RoutineConditionExpr.fromMap(Map<String, dynamic> map) {
return RoutineConditionExpr(
statusCode: map['statusCode'] ?? '',
comparator: map['comparator'] ?? '',
statusValue: map['statusValue'],
);
}
}

View File

@ -1,7 +1,10 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:syncrow_web/utils/constants/assets.dart';
class ScenesModel {
final String id;
final String? sceneTuyaId;
final String name;
final String status;
final String type;
@ -9,26 +12,43 @@ class ScenesModel {
ScenesModel({
required this.id,
this.sceneTuyaId,
required this.name,
required this.status,
required this.type,
this.icon,
});
factory ScenesModel.fromRawJson(String str) =>
ScenesModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
Uint8List? get iconInBytes {
if (icon == null || icon?.isEmpty == true) return null;
try {
return base64Decode(icon!);
} catch (e) {
return null;
}
}
factory ScenesModel.fromJson(Map<String, dynamic> json,
{bool? isAutomation}) =>
ScenesModel(
id: json["id"],
name: json["name"] ?? '',
status: json["status"] ?? '',
type: json["type"] ?? '',
icon: (isAutomation ?? false)
? Assets.automation
: json["icon"] as String?,
);
{bool? isAutomation}) {
return ScenesModel(
id: json["id"] ?? json["uuid"] ?? '',
sceneTuyaId: json["sceneTuyaId"] as String?,
name: json["name"] ?? '',
status: json["status"] ?? '',
type: json["type"] ?? '',
icon:
isAutomation == true ? Assets.automation : (json["icon"] as String?),
);
}
Map<String, dynamic> toJson() => {
"id": id,
"sceneTuyaId": sceneTuyaId ?? '',
"name": name,
"status": status,
"type": type,

View File

@ -6,8 +6,16 @@ import 'package:syncrow_web/pages/routiens/widgets/then_container.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class CreateNewRoutineView extends StatelessWidget {
const CreateNewRoutineView({super.key});
final bool isUpdate;
final String? routineId;
final bool isScene;
const CreateNewRoutineView({
super.key,
this.isUpdate = false,
this.routineId,
this.isScene = true,
});
@override
Widget build(BuildContext context) {
return Container(

View File

@ -1,7 +1,10 @@
import 'package:flutter/material.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/view/create_new_routine_view.dart';
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart';
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class RoutinesView extends StatelessWidget {
@ -23,49 +26,30 @@ class RoutinesView extends StatelessWidget {
children: [
Text(
"Create New Routines",
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 200,
width: 150,
child: GestureDetector(
onTap: () {
BlocProvider.of<SwitchTabsBloc>(context).add(
const CreateNewRoutineViewEvent(true),
);
},
child: Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
color: ColorsManager.whiteColors,
child: Center(
child: Container(
decoration: BoxDecoration(
color: ColorsManager.graysColor,
borderRadius: BorderRadius.circular(120),
border: Border.all(
color: ColorsManager.greyColor,
width: 2.0,
),
),
height: 70,
width: 70,
child: Icon(
Icons.add,
color: ColorsManager.dialogBlueTitle,
size: 40,
),
),
),
),
),
const SizedBox(
height: 10,
),
const Spacer(),
RoutineViewCard(
onTap: () {
BlocProvider.of<SwitchTabsBloc>(context).add(
const CreateNewRoutineViewEvent(true),
);
context.read<RoutineBloc>().add(
(ResetRoutineState()),
);
},
icon: Icons.add,
textString: '',
),
const SizedBox(
height: 15,
),
const Expanded(child: FetchRoutineScenesAutomation()),
],
),
);

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -81,7 +83,9 @@ class DraggableCard extends StatelessWidget {
? SvgPicture.asset(
imagePath,
)
: Image.network(imagePath),
: Image.memory(
base64Decode(imagePath),
),
),
const SizedBox(height: 8),
Padding(

View File

@ -26,8 +26,10 @@ class IfContainer extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('IF', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
if (state.isAutomation)
const Text('IF',
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold)),
if (state.isAutomation && state.ifItems.isNotEmpty)
AutomationOperatorSelector(
selectedOperator: state.selectedAutomationOperator),
],
@ -53,33 +55,44 @@ class IfContainer extends StatelessWidget {
(index) => GestureDetector(
onTap: () async {
if (!state.isTabToRun) {
final result = await DeviceDialogHelper.showDeviceDialog(
context, state.ifItems[index]);
final result = await DeviceDialogHelper
.showDeviceDialog(
context, state.ifItems[index],
removeComparetors: false);
if (result != null) {
context
.read<RoutineBloc>()
.add(AddToIfContainer(state.ifItems[index], false));
} else if (!['AC', '1G', '2G', '3G']
.contains(state.ifItems[index]['productType'])) {
context
.read<RoutineBloc>()
.add(AddToIfContainer(state.ifItems[index], false));
context.read<RoutineBloc>().add(
AddToIfContainer(
state.ifItems[index], false));
} else if (![
'AC',
'1G',
'2G',
'3G'
].contains(
state.ifItems[index]['productType'])) {
context.read<RoutineBloc>().add(
AddToIfContainer(
state.ifItems[index], false));
}
}
},
child: DraggableCard(
imagePath: state.ifItems[index]['imagePath'] ?? '',
imagePath:
state.ifItems[index]['imagePath'] ?? '',
title: state.ifItems[index]['title'] ?? '',
deviceData: state.ifItems[index],
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
padding: const EdgeInsets.symmetric(
horizontal: 4, vertical: 8),
isFromThen: false,
isFromIf: true,
onRemove: () {
context.read<RoutineBloc>().add(RemoveDragCard(
index: index,
isFromThen: false,
key: state.ifItems[index]['uniqueCustomId']));
context.read<RoutineBloc>().add(
RemoveDragCard(
index: index,
isFromThen: false,
key: state.ifItems[index]
['uniqueCustomId']));
},
),
)),
@ -88,23 +101,35 @@ class IfContainer extends StatelessWidget {
),
);
},
onWillAccept: (data) => data != null,
onAccept: (data) async {
onAcceptWithDetails: (data) async {
final uniqueCustomId = const Uuid().v4();
final mutableData = Map<String, dynamic>.from(data);
final mutableData = Map<String, dynamic>.from(data.data);
mutableData['uniqueCustomId'] = uniqueCustomId;
if (state.isAutomation && mutableData['deviceId'] == 'tab_to_run') {
return;
}
if (!state.isTabToRun) {
if (mutableData['deviceId'] == 'tab_to_run') {
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, true));
context
.read<RoutineBloc>()
.add(AddToIfContainer(mutableData, true));
} else {
final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData);
final result = await DeviceDialogHelper.showDeviceDialog(
context, mutableData,
removeComparetors: false);
if (result != null) {
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
} else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) {
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
context
.read<RoutineBloc>()
.add(AddToIfContainer(mutableData, false));
} else if (!['AC', '1G', '2G', '3G']
.contains(mutableData['productType'])) {
context
.read<RoutineBloc>()
.add(AddToIfContainer(mutableData, false));
}
}
}
@ -134,7 +159,7 @@ class AutomationOperatorSelector extends StatelessWidget {
children: [
TextButton(
style: TextButton.styleFrom(
backgroundColor: selectedOperator == 'or'
backgroundColor: selectedOperator.toLowerCase() == 'or'
? ColorsManager.dialogBlueTitle
: ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
@ -144,12 +169,15 @@ class AutomationOperatorSelector extends StatelessWidget {
child: Text(
'Any condition is met',
style: context.textTheme.bodyMedium?.copyWith(
color:
selectedOperator == 'or' ? ColorsManager.whiteColors : ColorsManager.blackColor,
color: selectedOperator.toLowerCase() == 'or'
? ColorsManager.whiteColors
: ColorsManager.blackColor,
),
),
onPressed: () {
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'or'));
context
.read<RoutineBloc>()
.add(const ChangeAutomationOperator(operator: 'or'));
},
),
Container(
@ -159,7 +187,7 @@ class AutomationOperatorSelector extends StatelessWidget {
),
TextButton(
style: TextButton.styleFrom(
backgroundColor: selectedOperator == 'and'
backgroundColor: selectedOperator.toLowerCase() == 'and'
? ColorsManager.dialogBlueTitle
: ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
@ -169,13 +197,15 @@ class AutomationOperatorSelector extends StatelessWidget {
child: Text(
'All condition is met',
style: context.textTheme.bodyMedium?.copyWith(
color: selectedOperator == 'and'
color: selectedOperator.toLowerCase() == 'and'
? ColorsManager.whiteColors
: ColorsManager.blackColor,
),
),
onPressed: () {
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'and'));
context
.read<RoutineBloc>()
.add(const ChangeAutomationOperator(operator: 'and'));
},
),
],

View File

@ -0,0 +1,196 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_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/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class FetchRoutineScenesAutomation extends StatefulWidget {
const FetchRoutineScenesAutomation({super.key});
@override
State<FetchRoutineScenesAutomation> createState() =>
_FetchRoutineScenesState();
}
class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
with HelperResponsiveLayout {
@override
void initState() {
super.initState();
context.read<RoutineBloc>()
..add(const LoadScenes(spaceId, communityId))
..add(const LoadAutomation(spaceId));
}
@override
Widget build(BuildContext context) {
return BlocBuilder<RoutineBloc, RoutineState>(
builder: (context, state) {
return state.isLoading
? const Center(
child: CircularProgressIndicator(),
)
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Scenes (Tab to Run)",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
if (state.scenes.isEmpty)
Text(
"No scenes found",
style: context.textTheme.bodyMedium?.copyWith(
color: ColorsManager.grayColor,
),
),
if (state.scenes.isNotEmpty)
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isSmallScreenSize(context) ? 160 : 170,
),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.scenes.length,
itemBuilder: (context, index) => Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: Stack(
children: [
RoutineViewCard(
onTap: () {},
textString: state.scenes[index].name,
icon: state.scenes[index].icon ??
Assets.logoHorizontal,
isFromScenes: true,
iconInBytes:
state.scenes[index].iconInBytes,
),
Positioned(
top: 0,
right: 0,
child: InkWell(
onTap: () => context
.read<RoutineBloc>()
.add(
DeleteScene(
sceneId: state.scenes[index].id,
unitUuid: spaceId,
),
),
child: Container(
height: 20,
width: 20,
decoration: BoxDecoration(
color: ColorsManager.whiteColors,
shape: BoxShape.circle,
border: Border.all(
color: ColorsManager.grayColor,
width: 2.0,
),
),
child: const Center(
child: Icon(Icons.delete,
size: 15,
color: ColorsManager.grayColor),
),
),
),
),
],
),
),
),
),
const SizedBox(height: 15),
Text(
"Automations",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
if (state.automations.isEmpty)
Text(
"No automations found",
style: context.textTheme.bodyMedium?.copyWith(
color: ColorsManager.grayColor,
),
),
if (state.automations.isNotEmpty)
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isSmallScreenSize(context) ? 160 : 170,
),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.automations.length,
itemBuilder: (context, index) => Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: Stack(
children: [
RoutineViewCard(
onTap: () {},
textString: state.automations[index].name,
icon: state.automations[index].icon ??
Assets.automation,
),
Positioned(
top: 0,
right: 0,
child: InkWell(
onTap: () =>
context.read<RoutineBloc>().add(
DeleteAutomation(
automationId: state
.automations[index].id,
unitUuid: spaceId,
),
),
child: Container(
height: 20,
width: 20,
decoration: BoxDecoration(
color: ColorsManager.whiteColors,
shape: BoxShape.circle,
border: Border.all(
color: ColorsManager.grayColor,
width: 2.0,
),
),
child: const Center(
child: Icon(Icons.delete,
size: 15,
color: ColorsManager.grayColor),
),
),
),
),
],
),
),
),
),
],
),
),
);
},
);
}
}

View File

@ -0,0 +1,127 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class RoutineViewCard extends StatelessWidget with HelperResponsiveLayout {
const RoutineViewCard({
super.key,
required this.onTap,
required this.icon,
required this.textString,
this.isFromScenes,
this.iconInBytes,
});
final Function() onTap;
final dynamic icon;
final String textString;
final bool? isFromScenes;
final Uint8List? iconInBytes;
@override
Widget build(BuildContext context) {
final double cardWidth = isSmallScreenSize(context)
? 120
: isMediumScreenSize(context)
? 135
: 150;
final double cardHeight = isSmallScreenSize(context) ? 160 : 170;
final double iconSize = isSmallScreenSize(context)
? 50
: isMediumScreenSize(context)
? 60
: 70;
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: cardWidth,
maxHeight: cardHeight,
),
child: Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
color: ColorsManager.whiteColors,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(10),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Container(
decoration: BoxDecoration(
color: ColorsManager.graysColor,
borderRadius: BorderRadius.circular(120),
border: Border.all(
color: ColorsManager.greyColor,
width: 2.0,
),
),
height: iconSize,
width: iconSize,
child: (isFromScenes ?? false)
? (iconInBytes != null &&
iconInBytes?.isNotEmpty == true)
? Image.memory(
iconInBytes!,
height: iconSize,
width: iconSize,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) =>
Image.asset(
Assets.logo,
height: iconSize,
width: iconSize,
fit: BoxFit.contain,
),
)
: Image.asset(
Assets.logo,
height: iconSize,
width: iconSize,
fit: BoxFit.contain,
)
: (icon is String && icon.endsWith('.svg'))
? SvgPicture.asset(
icon,
fit: BoxFit.contain,
)
: Icon(
icon,
color: ColorsManager.dialogBlueTitle,
size: isSmallScreenSize(context) ? 30 : 40,
),
),
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 3),
child: Text(
textString,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: context.textTheme.bodySmall?.copyWith(
color: ColorsManager.blackColor,
fontSize: isSmallScreenSize(context) ? 10 : 12,
),
),
),
],
),
),
),
),
);
}
}

View File

@ -75,7 +75,11 @@ class PeriodOptions extends StatelessWidget {
onTap: () {
context.read<EffectPeriodBloc>().add(SetPeriod(value));
},
title: Text(EffectPeriodHelper.formatEnumValue(value)),
title: Text(
EffectPeriodHelper.formatEnumValue(value),
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: ColorsManager.blackColor, fontWeight: FontWeight.w400, fontSize: 12),
),
subtitle: Text(
subtitle,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(

View File

@ -19,6 +19,7 @@ class ACHelper {
AllDevicesModel? device,
List<DeviceFunctionData>? deviceSelectedFunctions,
String uniqueCustomId,
bool? removeComparetors,
) async {
List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
@ -84,6 +85,7 @@ class ACHelper {
acFunctions: acFunctions,
device: device,
operationName: selectedOperationName ?? '',
removeComparators: removeComparetors,
),
),
],
@ -179,6 +181,7 @@ class ACHelper {
required List<ACFunction> acFunctions,
AllDevicesModel? device,
required String operationName,
bool? removeComparators,
}) {
if (selectedFunction == 'temp_set' || selectedFunction == 'temp_current') {
final initialValue = selectedFunctionData?.value ?? 200;
@ -190,6 +193,7 @@ class ACHelper {
device: device,
operationName: operationName,
selectedFunctionData: selectedFunctionData,
removeComparators: removeComparators,
);
}
@ -217,18 +221,20 @@ class ACHelper {
AllDevicesModel? device,
required String operationName,
DeviceFunctionData? selectedFunctionData,
bool? removeComparators,
}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildConditionToggle(
context,
currentCondition,
selectCode,
device,
operationName,
selectedFunctionData,
),
if (removeComparators != true)
_buildConditionToggle(
context,
currentCondition,
selectCode,
device,
operationName,
selectedFunctionData,
),
const SizedBox(height: 20),
_buildTemperatureDisplay(
context,

View File

@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/custom_table.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';

View File

@ -20,6 +20,7 @@ class OneGangSwitchHelper {
AllDevicesModel? device,
List<DeviceFunctionData>? deviceSelectedFunctions,
String uniqueCustomId,
bool removeComparetors,
) async {
List<BaseSwitchFunction> acFunctions =
functions.whereType<BaseSwitchFunction>().toList();
@ -106,6 +107,7 @@ class OneGangSwitchHelper {
acFunctions: acFunctions,
device: device,
operationName: selectedOperationName ?? '',
removeComparetors: removeComparetors,
),
),
],
@ -162,6 +164,7 @@ class OneGangSwitchHelper {
required List<BaseSwitchFunction> acFunctions,
AllDevicesModel? device,
required String operationName,
required bool removeComparetors,
}) {
if (selectedFunction == 'countdown_1') {
final initialValue = selectedFunctionData?.value ?? 200;
@ -173,6 +176,7 @@ class OneGangSwitchHelper {
device: device,
operationName: operationName,
selectedFunctionData: selectedFunctionData,
removeComparetors: removeComparetors,
);
}
@ -199,18 +203,20 @@ class OneGangSwitchHelper {
AllDevicesModel? device,
required String operationName,
DeviceFunctionData? selectedFunctionData,
required bool removeComparetors,
}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildConditionToggle(
context,
currentCondition,
selectCode,
device,
operationName,
selectedFunctionData,
),
if (removeComparetors != true)
_buildConditionToggle(
context,
currentCondition,
selectCode,
device,
operationName,
selectedFunctionData,
),
const SizedBox(height: 20),
_buildCountDownDisplay(context, initialValue, device, operationName,
selectedFunctionData, selectCode),

View File

@ -20,6 +20,7 @@ class ThreeGangSwitchHelper {
AllDevicesModel? device,
List<DeviceFunctionData>? deviceSelectedFunctions,
String uniqueCustomId,
bool removeComparetors,
) async {
List<BaseSwitchFunction> switchFunctions =
functions.whereType<BaseSwitchFunction>().toList();
@ -106,6 +107,7 @@ class ThreeGangSwitchHelper {
switchFunctions: switchFunctions,
device: device,
operationName: selectedOperationName ?? '',
removeComparetors: removeComparetors,
),
),
],
@ -162,6 +164,7 @@ class ThreeGangSwitchHelper {
required List<BaseSwitchFunction> switchFunctions,
AllDevicesModel? device,
required String operationName,
required bool removeComparetors,
}) {
if (selectedFunction == 'countdown_1' ||
selectedFunction == 'countdown_2' ||
@ -175,6 +178,7 @@ class ThreeGangSwitchHelper {
device: device,
operationName: operationName,
selectedFunctionData: selectedFunctionData,
removeComparetors: removeComparetors,
);
}
@ -201,18 +205,20 @@ class ThreeGangSwitchHelper {
AllDevicesModel? device,
required String operationName,
DeviceFunctionData? selectedFunctionData,
bool? removeComparetors,
}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildConditionToggle(
context,
currentCondition,
selectCode,
device,
operationName,
selectedFunctionData,
),
if (removeComparetors != true)
_buildConditionToggle(
context,
currentCondition,
selectCode,
device,
operationName,
selectedFunctionData,
),
const SizedBox(height: 20),
_buildCountDownDisplay(context, initialValue, device, operationName,
selectedFunctionData, selectCode),

View File

@ -20,6 +20,7 @@ class TwoGangSwitchHelper {
AllDevicesModel? device,
List<DeviceFunctionData>? deviceSelectedFunctions,
String uniqueCustomId,
bool removeComparetors,
) async {
List<BaseSwitchFunction> switchFunctions =
functions.whereType<BaseSwitchFunction>().toList();
@ -106,6 +107,7 @@ class TwoGangSwitchHelper {
switchFunctions: switchFunctions,
device: device,
operationName: selectedOperationName ?? '',
removeComparetors: removeComparetors,
),
),
],
@ -162,6 +164,7 @@ class TwoGangSwitchHelper {
required List<BaseSwitchFunction> switchFunctions,
AllDevicesModel? device,
required String operationName,
required bool removeComparetors,
}) {
if (selectedFunction == 'countdown_1' ||
selectedFunction == 'countdown_2') {
@ -174,6 +177,7 @@ class TwoGangSwitchHelper {
device: device,
operationName: operationName,
selectedFunctionData: selectedFunctionData,
removeComparetors: removeComparetors,
);
}
@ -200,18 +204,20 @@ class TwoGangSwitchHelper {
AllDevicesModel? device,
required String operationName,
DeviceFunctionData? selectedFunctionData,
bool? removeComparetors,
}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildConditionToggle(
context,
currentCondition,
selectCode,
device,
operationName,
selectedFunctionData,
),
if (removeComparetors != true)
_buildConditionToggle(
context,
currentCondition,
selectCode,
device,
operationName,
selectedFunctionData,
),
const SizedBox(height: 20),
_buildCountDownDisplay(context, initialValue, device, operationName,
selectedFunctionData, selectCode),

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.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/helper/save_routine_helper.dart';
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/discard_dialog.dart';
@ -173,7 +174,7 @@ class RoutineSearchAndButtons extends StatelessWidget {
width: 200,
child: Center(
child: DefaultButton(
onPressed: () {
onPressed: () async {
if (state.routineName == null || state.routineName!.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
@ -207,7 +208,16 @@ class RoutineSearchAndButtons extends StatelessWidget {
);
return;
}
SaveRoutineHelper.showSaveRoutineDialog(context);
final result =
await SaveRoutineHelper.showSaveRoutineDialog(context);
if (result != null && result) {
BlocProvider.of<SwitchTabsBloc>(context).add(
const CreateNewRoutineViewEvent(false),
);
BlocProvider.of<SwitchTabsBloc>(context).add(
const TriggerSwitchTabsEvent(true),
);
}
},
borderRadius: 15,
elevation: 0,

View File

@ -18,7 +18,7 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
void initState() {
super.initState();
context.read<RoutineBloc>()
..add(const LoadScenes(spaceId))
..add(const LoadScenes(spaceId, communityId))
..add(const LoadAutomation(spaceId));
}
@ -34,7 +34,9 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
children: scenes.asMap().entries.map((entry) {
final scene = entry.value;
if (state.searchText != null && state.searchText!.isNotEmpty) {
return scene.name.toLowerCase().contains(state.searchText!.toLowerCase())
return scene.name
.toLowerCase()
.contains(state.searchText!.toLowerCase())
? DraggableCard(
imagePath: scene.icon ?? Assets.loginLogo,
title: scene.name,

View File

@ -26,7 +26,9 @@ class ThenContainer extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('THEN', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const Text('THEN',
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 16),
Wrap(
spacing: 8,
@ -35,12 +37,16 @@ class ThenContainer extends StatelessWidget {
state.thenItems.length,
(index) => GestureDetector(
onTap: () async {
if (state.thenItems[index]['deviceId'] == 'delay') {
final result = await DelayHelper.showDelayPickerDialog(
context, state.thenItems[index]);
if (state.thenItems[index]['deviceId'] ==
'delay') {
final result = await DelayHelper
.showDelayPickerDialog(
context, state.thenItems[index]);
if (result != null) {
context.read<RoutineBloc>().add(AddToThenContainer({
context
.read<RoutineBloc>()
.add(AddToThenContainer({
...state.thenItems[index],
'imagePath': Assets.delay,
'title': 'Delay',
@ -49,32 +55,41 @@ class ThenContainer extends StatelessWidget {
return;
}
final result = await DeviceDialogHelper.showDeviceDialog(
context, state.thenItems[index]);
final result = await DeviceDialogHelper
.showDeviceDialog(
context, state.thenItems[index],
removeComparetors: true);
if (result != null) {
context
.read<RoutineBloc>()
.add(AddToThenContainer(state.thenItems[index]));
context.read<RoutineBloc>().add(
AddToThenContainer(
state.thenItems[index]));
} else if (!['AC', '1G', '2G', '3G']
.contains(state.thenItems[index]['productType'])) {
context
.read<RoutineBloc>()
.add(AddToThenContainer(state.thenItems[index]));
.contains(state.thenItems[index]
['productType'])) {
context.read<RoutineBloc>().add(
AddToThenContainer(
state.thenItems[index]));
}
},
child: DraggableCard(
imagePath: state.thenItems[index]['imagePath'] ?? '',
title: state.thenItems[index]['title'] ?? '',
imagePath: state.thenItems[index]
['imagePath'] ??
'',
title:
state.thenItems[index]['title'] ?? '',
deviceData: state.thenItems[index],
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
padding: const EdgeInsets.symmetric(
horizontal: 4, vertical: 8),
isFromThen: true,
isFromIf: false,
onRemove: () {
context.read<RoutineBloc>().add(RemoveDragCard(
index: index,
isFromThen: true,
key: state.thenItems[index]['uniqueCustomId']));
context.read<RoutineBloc>().add(
RemoveDragCard(
index: index,
isFromThen: true,
key: state.thenItems[index]
['uniqueCustomId']));
},
),
))),
@ -83,21 +98,6 @@ class ThenContainer extends StatelessWidget {
),
);
},
// onWillAcceptWithDetails: (data) {
// if (data == null) return false;
// return data.data;
// // if (state.isTabToRun) {
// // return data.data['type'] == 'automation';
// // }
// // if (state.isAutomation) {
// // return data.data['type'] == 'scene' ||
// // data.data['type'] == 'automation';
// // }
// // return data.data['deviceId'] != null;
// },
onAcceptWithDetails: (data) async {
final uniqueCustomId = const Uuid().v4();
final mutableData = Map<String, dynamic>.from(data.data);
@ -128,8 +128,23 @@ class ThenContainer extends StatelessWidget {
return;
}
if (mutableData['type'] == 'tap_to_run' && state.isAutomation) {
context.read<RoutineBloc>().add(AddToThenContainer({
...mutableData,
'imagePath': Assets.logo,
'title': mutableData['name'],
}));
return;
}
if (mutableData['type'] == 'tap_to_run' && !state.isAutomation) {
return;
}
if (mutableData['deviceId'] == 'delay') {
final result = await DelayHelper.showDelayPickerDialog(context, mutableData);
final result =
await DelayHelper.showDelayPickerDialog(context, mutableData);
if (result != null) {
context.read<RoutineBloc>().add(AddToThenContainer({
@ -141,11 +156,13 @@ class ThenContainer extends StatelessWidget {
return;
}
final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData);
final result = await DeviceDialogHelper.showDeviceDialog(
context, mutableData,
removeComparetors: true);
if (result != null) {
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
} else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) {
} else if (!['AC', '1G', '2G', '3G']
.contains(mutableData['productType'])) {
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
}
},

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.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/icon_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/services/api/http_service.dart';
import 'package:syncrow_web/utils/constants/api_const.dart';
@ -67,17 +68,24 @@ class SceneApi {
return response;
}
//get scene by unit id
//get scenes by community id and space id
static Future<List<ScenesModel>> getScenesByUnitId(String unitId) async {
static Future<List<ScenesModel>> getScenesByUnitId(
String unitId, String communityId,
{showInDevice = false}) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getSpaceScenes.replaceAll('{unitUuid}', unitId),
path: ApiEndpoints.getUnitScenes
.replaceAll('{spaceUuid}', unitId)
.replaceAll('{communityUuid}', communityId),
queryParameters: {'showInHomePage': showInDevice},
showServerMessage: false,
expectedResponseModel: (json) {
final scenesJson = json['data'] as List;
List<ScenesModel> scenes = [];
for (var scene in json) {
scenes.add(ScenesModel.fromJson(scene));
for (var scene in scenesJson) {
scenes.add(ScenesModel.fromJson(scene, isAutomation: false));
}
return scenes;
},
@ -122,21 +130,21 @@ class SceneApi {
// }
// }
// //automation details
// static Future<SceneDetailsModel> getAutomationDetails(
// String automationId) async {
// try {
// final response = await _httpService.get(
// path: ApiEndpoints.getAutomationDetails
// .replaceAll('{automationId}', automationId),
// showServerMessage: false,
// expectedResponseModel: (json) => SceneDetailsModel.fromJson(json),
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//automation details
static Future<RoutineDetailsModel> getAutomationDetails(
String automationId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getAutomationDetails
.replaceAll('{automationId}', automationId),
showServerMessage: false,
expectedResponseModel: (json) => RoutineDetailsModel.fromJson(json),
);
return response;
} catch (e) {
rethrow;
}
}
//
// //updateAutomationStatus
// static Future<bool> updateAutomationStatus(String automationId,
@ -154,20 +162,19 @@ class SceneApi {
// }
// }
// //getScene
//
// static Future<SceneDetailsModel> getSceneDetails(String sceneId) async {
// try {
// final response = await _httpService.get(
// path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId),
// showServerMessage: false,
// expectedResponseModel: (json) => SceneDetailsModel.fromJson(json),
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//getScene
static Future<RoutineDetailsModel> getSceneDetails(String sceneId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId),
showServerMessage: false,
expectedResponseModel: (json) => RoutineDetailsModel.fromJson(json),
);
return response;
} catch (e) {
rethrow;
}
}
//
// //update Scene
// static updateScene(CreateSceneModel createSceneModel, String sceneId) async {
@ -205,38 +212,39 @@ class SceneApi {
// }
// }
//
// //delete Scene
//
// static Future<bool> deleteScene(
// {required String unitUuid, required String sceneId}) async {
// try {
// final response = await _httpService.delete(
// path: ApiEndpoints.deleteScene
// .replaceAll('{sceneId}', sceneId)
// .replaceAll('{unitUuid}', unitUuid),
// showServerMessage: false,
// expectedResponseModel: (json) => json['statusCode'] == 200,
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//
// // delete automation
// static Future<bool> deleteAutomation(
// {required String unitUuid, required String automationId}) async {
// try {
// final response = await _httpService.delete(
// path: ApiEndpoints.deleteAutomation
// .replaceAll('{automationId}', automationId)
// .replaceAll('{unitUuid}', unitUuid),
// showServerMessage: false,
// expectedResponseModel: (json) => json['statusCode'] == 200,
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//delete Scene
static Future<bool> deleteScene(
{required String unitUuid, required String sceneId}) async {
try {
final response = await _httpService.delete(
path: ApiEndpoints.deleteScene
.replaceAll('{sceneId}', sceneId)
.replaceAll('{unitUuid}', unitUuid),
showServerMessage: false,
expectedResponseModel: (json) => json['statusCode'] == 200,
);
return response;
} catch (e) {
rethrow;
}
}
// delete automation
static Future<bool> deleteAutomation(
{required String unitUuid, required String automationId}) async {
try {
final response = await _httpService.delete(
path: ApiEndpoints.deleteAutomation
.replaceAll('{automationId}', automationId)
.replaceAll('{unitUuid}', unitUuid),
showServerMessage: false,
expectedResponseModel: (json) => json['statusCode'] == 200,
);
return response;
} catch (e) {
rethrow;
}
}
}

View File

@ -46,7 +46,6 @@ abstract class ApiEndpoints {
'/schedule/{deviceUuid}/{scheduleUuid}';
static const String updateScheduleByDeviceId =
'/schedule/enable/{deviceUuid}';
static const String factoryReset = '/device/factory/reset/{deviceUuid}';
static const String powerClamp =
'/device/{powerClampUuid}/power-clamp/status';
@ -55,4 +54,12 @@ abstract class ApiEndpoints {
static const String getIconScene = '/scene/icon';
static const String createScene = '/scene/tap-to-run';
static const String createAutomation = '/automation';
static const String getUnitScenes =
'/communities/{communityUuid}/spaces/{spaceUuid}/scenes';
static const String getAutomationDetails =
'/automation/details/{automationId}';
static const String getScene = '/scene/tap-to-run/{sceneId}';
static const String deleteScene = '/scene/tap-to-run/{sceneId}';
static const String deleteAutomation = '/automation/{automationId}';
}