push calling create scene

This commit is contained in:
ashrafzarkanisala
2024-11-24 11:17:54 +03:00
parent 5a9729fe10
commit 87c47a74ce
13 changed files with 759 additions and 131 deletions

View File

@ -18,6 +18,7 @@ class StatefulTextField extends StatefulWidget {
this.padding, this.padding,
this.icon, this.icon,
this.hintColor, this.hintColor,
required this.onChanged,
}); });
final String title; final String title;
@ -32,6 +33,7 @@ class StatefulTextField extends StatefulWidget {
final double? padding; final double? padding;
final IconData? icon; final IconData? icon;
final Color? hintColor; final Color? hintColor;
final Function(String)? onChanged;
@override @override
State<StatefulTextField> createState() => _StatefulTextFieldState(); State<StatefulTextField> createState() => _StatefulTextFieldState();
@ -59,6 +61,7 @@ class _StatefulTextFieldState extends State<StatefulTextField> {
padding: widget.padding, padding: widget.padding,
icon: widget.icon, icon: widget.icon,
hintColor: widget.hintColor, hintColor: widget.hintColor,
onChanged: widget.onChanged,
); );
} }
} }
@ -78,6 +81,7 @@ class CustomTextField extends StatelessWidget {
this.padding, this.padding,
this.icon, this.icon,
this.hintColor, this.hintColor,
required this.onChanged,
}); });
final String title; final String title;
@ -92,6 +96,7 @@ class CustomTextField extends StatelessWidget {
final double? padding; final double? padding;
final IconData? icon; final IconData? icon;
final Color? hintColor; final Color? hintColor;
final Function(String)? onChanged;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -120,14 +125,21 @@ class CustomTextField extends StatelessWidget {
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
decoration: InputDecoration( decoration: InputDecoration(
hintText: hintText, hintText: hintText,
hintStyle: TextStyle(fontSize: 12, color: hintColor ?? ColorsManager.blackColor), hintStyle: TextStyle(
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: padding ?? 10), fontSize: 12, color: hintColor ?? ColorsManager.blackColor),
contentPadding: EdgeInsets.symmetric(
horizontal: 12, vertical: padding ?? 10),
border: InputBorder.none, border: InputBorder.none,
suffixIcon: icon != null ? Icon(icon, color: ColorsManager.greyColor) : null, suffixIcon: icon != null
? Icon(icon, color: ColorsManager.greyColor)
: null,
), ),
onFieldSubmitted: (_) { onFieldSubmitted: (_) {
onSubmittedFun!(); onSubmittedFun!();
}, },
onChanged: (value) {
onChanged!(value);
},
), ),
), ),
), ),

View File

@ -2,8 +2,10 @@ 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/bloc/device_mgmt_bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart'; import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart'; import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
import 'package:syncrow_web/pages/routiens/view/routines_view.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
@ -20,7 +22,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
create: (context) => DeviceManagementBloc()..add(FetchDevices()), create: (context) => DeviceManagementBloc()..add(FetchDevices()),
), ),
BlocProvider( BlocProvider(
create: (context) => SwitchTabsBloc()..add(const TriggerSwitchTabsEvent(false)), create: (context) =>
SwitchTabsBloc()..add(const TriggerSwitchTabsEvent(false)),
), ),
], ],
child: WebScaffold( child: WebScaffold(
@ -30,7 +33,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
style: Theme.of(context).textTheme.headlineLarge, style: Theme.of(context).textTheme.headlineLarge,
), ),
), ),
centerBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(builder: (context, state) { centerBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(
builder: (context, state) {
return Row( return Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -39,16 +43,21 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
backgroundColor: null, backgroundColor: null,
), ),
onPressed: () { onPressed: () {
context.read<SwitchTabsBloc>().add(const TriggerSwitchTabsEvent(false)); context
.read<SwitchTabsBloc>()
.add(const TriggerSwitchTabsEvent(false));
}, },
child: Text( child: Text(
'Devices', 'Devices',
style: context.textTheme.titleMedium?.copyWith( style: context.textTheme.titleMedium?.copyWith(
color: state is SelectedTabState && state.selectedTab == false color:
? ColorsManager.whiteColors state is SelectedTabState && state.selectedTab == false
: ColorsManager.grayColor, ? ColorsManager.whiteColors
fontWeight: : ColorsManager.grayColor,
(state is SelectedTabState) && state.selectedTab == false ? FontWeight.w700 : FontWeight.w400, fontWeight: (state is SelectedTabState) &&
state.selectedTab == false
? FontWeight.w700
: FontWeight.w400,
), ),
), ),
), ),
@ -57,16 +66,21 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
backgroundColor: null, backgroundColor: null,
), ),
onPressed: () { onPressed: () {
context.read<SwitchTabsBloc>().add(const TriggerSwitchTabsEvent(true)); context
.read<SwitchTabsBloc>()
.add(const TriggerSwitchTabsEvent(true));
}, },
child: Text( child: Text(
'Routines', 'Routines',
style: context.textTheme.titleMedium?.copyWith( style: context.textTheme.titleMedium?.copyWith(
color: (state is SelectedTabState) && state.selectedTab == true color:
? ColorsManager.whiteColors (state is SelectedTabState) && state.selectedTab == true
: ColorsManager.grayColor, ? ColorsManager.whiteColors
: ColorsManager.grayColor,
fontWeight: fontWeight:
(state is SelectedTabState) && state.selectedTab == true ? FontWeight.w700 : FontWeight.w400, (state is SelectedTabState) && state.selectedTab == true
? FontWeight.w700
: FontWeight.w400,
), ),
), ),
), ),
@ -74,30 +88,31 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
); );
}), }),
rightBody: const NavigateHomeGridView(), rightBody: const NavigateHomeGridView(),
scaffoldBody: CreateNewRoutineView(), scaffoldBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(
// BlocBuilder<SwitchTabsBloc, SwitchTabsState>(builder: (context, state) { builder: (context, state) {
// if (state is SelectedTabState && state.selectedTab) { if (state is SelectedTabState && state.selectedTab) {
// return const RoutinesView(); return const RoutinesView();
// } }
// if (state is ShowCreateRoutineState && state.showCreateRoutine) { if (state is ShowCreateRoutineState && state.showCreateRoutine) {
// return const CreateNewRoutineView(); return const CreateNewRoutineView();
// } }
//
// return BlocBuilder<DeviceManagementBloc, DeviceManagementState>( return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
// builder: (context, deviceState) { builder: (context, deviceState) {
// if (deviceState is DeviceManagementLoading) { if (deviceState is DeviceManagementLoading) {
// return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
// } else if (deviceState is DeviceManagementLoaded || deviceState is DeviceManagementFiltered) { } else if (deviceState is DeviceManagementLoaded ||
// final devices = deviceState is DeviceManagementFiltered) {
// (deviceState as dynamic).devices ?? (deviceState as DeviceManagementFiltered).filteredDevices; final devices = (deviceState as dynamic).devices ??
// (deviceState as DeviceManagementFiltered).filteredDevices;
// return DeviceManagementBody(devices: devices);
// } else { return DeviceManagementBody(devices: devices);
// return const Center(child: Text('Error fetching Devices')); } else {
// } return const Center(child: Text('Error fetching Devices'));
// }, }
// ); },
// }), );
}),
), ),
); );
} }

View File

@ -12,7 +12,8 @@ class DeviceSearchFilters extends StatefulWidget {
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState(); State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
} }
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout { class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
with HelperResponsiveLayout {
final TextEditingController communityController = TextEditingController(); final TextEditingController communityController = TextEditingController();
final TextEditingController unitNameController = TextEditingController(); final TextEditingController unitNameController = TextEditingController();
final TextEditingController productNameController = TextEditingController(); final TextEditingController productNameController = TextEditingController();
@ -34,7 +35,8 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchField("Space Name", unitNameController, 200), _buildSearchField("Space Name", unitNameController, 200),
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchField("Device Name / Product Name", productNameController, 300), _buildSearchField(
"Device Name / Product Name", productNameController, 300),
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchResetButtons(), _buildSearchResetButtons(),
], ],
@ -59,7 +61,8 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
); );
} }
Widget _buildSearchField(String title, TextEditingController controller, double width) { Widget _buildSearchField(
String title, TextEditingController controller, double width) {
return Container( return Container(
child: StatefulTextField( child: StatefulTextField(
title: title, title: title,
@ -73,6 +76,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
community: communityController.text, community: communityController.text,
searchField: true)); searchField: true));
}, },
onChanged: (p0) {},
), ),
); );
} }

View File

@ -1,6 +1,9 @@
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/routiens/models/create_scene/create_scene_model.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_model.dart'; import 'package:syncrow_web/pages/routiens/models/routine_model.dart';
import 'package:syncrow_web/services/routines_api.dart'; import 'package:syncrow_web/services/routines_api.dart';
@ -20,6 +23,9 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
on<LoadScenes>(_onLoadScenes); on<LoadScenes>(_onLoadScenes);
on<LoadAutomation>(_onLoadAutomation); on<LoadAutomation>(_onLoadAutomation);
on<AddFunctionToRoutine>(_onAddFunctionsToRoutine); on<AddFunctionToRoutine>(_onAddFunctionsToRoutine);
on<SearchRoutines>(_onSearchRoutines);
on<AddSelectedIcon>(_onAddSelectedIcon);
on<CreateSceneEvent>(_onCreateScene);
// on<RemoveFunction>(_onRemoveFunction); // on<RemoveFunction>(_onRemoveFunction);
// on<ClearFunctions>(_onClearFunctions); // on<ClearFunctions>(_onClearFunctions);
} }
@ -40,8 +46,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
void _onAddFunctionsToRoutine( void _onAddFunctionsToRoutine(
AddFunctionToRoutine event, Emitter<RoutineState> emit) { AddFunctionToRoutine event, Emitter<RoutineState> emit) {
debugPrint('Adding functions to routine: ${event.functions}');
debugPrint('Unique Custom ID: ${event.uniqueCustomId}');
final currentSelectedFunctions = final currentSelectedFunctions =
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions); Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
@ -52,7 +56,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
emit(state.copyWith(selectedFunctions: currentSelectedFunctions)); emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
debugPrint('Updated selected functions: $currentSelectedFunctions');
} }
// void _onRemoveFunction(RemoveFunction event, Emitter<RoutineState> emit) { // void _onRemoveFunction(RemoveFunction event, Emitter<RoutineState> emit) {
@ -80,7 +83,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} catch (e) { } catch (e) {
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
errorMessage: 'Something went wrong', errorMessage: 'Failed to load scenes',
)); ));
} }
} }
@ -98,7 +101,97 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} catch (e) { } catch (e) {
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
errorMessage: 'Something went wrong', errorMessage: 'Failed to load automations',
));
}
}
FutureOr<void> _onSearchRoutines(
SearchRoutines event, Emitter<RoutineState> emit) {
emit(state.copyWith(routineName: event.query));
}
FutureOr<void> _onAddSelectedIcon(
AddSelectedIcon event, Emitter<RoutineState> emit) {
emit(state.copyWith(selectedIcon: event.icon));
}
bool _isFirstActionDelay(List<Map<String, dynamic>> actions) {
if (actions.isEmpty) return false;
return actions.first['deviceId'] == 'delay';
}
Future<void> _onCreateScene(
CreateSceneEvent 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));
final actions = state.thenItems
.map((item) {
final functions =
state.selectedFunctions[item['uniqueCustomId']] ?? [];
if (functions.isEmpty) return null;
final function = functions.first;
if (item['deviceId'] == 'delay') {
return CreateSceneAction(
entityId: function.entityId,
actionExecutor: 'delay',
executorProperty: CreateSceneExecutorProperty(
functionCode: '',
functionValue: '',
delaySeconds: function.value,
),
);
}
return CreateSceneAction(
entityId: function.entityId,
actionExecutor: 'device_issue',
executorProperty: CreateSceneExecutorProperty(
functionCode: function.functionCode.toString(),
functionValue: function.value,
delaySeconds: 0,
),
);
})
.whereType<CreateSceneAction>()
.toList();
final createSceneModel = CreateSceneModel(
spaceUuid: spaceId,
iconId: state.selectedIcon ?? '',
showInDevice: true,
sceneName: state.routineName ?? '',
decisionExpr: 'and',
actions: actions,
);
final result = await SceneApi.createScene(createSceneModel);
if (result['success']) {
emit(state.copyWith(
isLoading: false,
errorMessage: null,
));
} else {
emit(state.copyWith(
isLoading: false,
errorMessage: result['message'],
));
}
} catch (e) {
emit(state.copyWith(
isLoading: false,
errorMessage: e.toString(),
)); ));
} }
} }

View File

@ -59,4 +59,24 @@ class RemoveFunction extends RoutineEvent {
List<Object> get props => [function]; List<Object> get props => [function];
} }
class SearchRoutines extends RoutineEvent {
final String query;
const SearchRoutines(this.query);
@override
List<Object> get props => [query];
}
class AddSelectedIcon extends RoutineEvent {
final String icon;
const AddSelectedIcon(this.icon);
@override
List<Object> get props => [icon];
}
class CreateSceneEvent extends RoutineEvent {
const CreateSceneEvent();
@override
List<Object> get props => [];
}
class ClearFunctions extends RoutineEvent {} class ClearFunctions extends RoutineEvent {}

View File

@ -9,6 +9,8 @@ class RoutineState extends Equatable {
final Map<String, List<DeviceFunctionData>> selectedFunctions; final Map<String, List<DeviceFunctionData>> selectedFunctions;
final bool isLoading; final bool isLoading;
final String? errorMessage; final String? errorMessage;
final String? routineName;
final String? selectedIcon;
const RoutineState({ const RoutineState({
this.ifItems = const [], this.ifItems = const [],
@ -19,6 +21,8 @@ class RoutineState extends Equatable {
this.selectedFunctions = const {}, this.selectedFunctions = const {},
this.isLoading = false, this.isLoading = false,
this.errorMessage, this.errorMessage,
this.routineName,
this.selectedIcon,
}); });
RoutineState copyWith({ RoutineState copyWith({
@ -29,6 +33,8 @@ class RoutineState extends Equatable {
Map<String, List<DeviceFunctionData>>? selectedFunctions, Map<String, List<DeviceFunctionData>>? selectedFunctions,
bool? isLoading, bool? isLoading,
String? errorMessage, String? errorMessage,
String? routineName,
String? selectedIcon,
}) { }) {
return RoutineState( return RoutineState(
ifItems: ifItems ?? this.ifItems, ifItems: ifItems ?? this.ifItems,
@ -38,6 +44,8 @@ class RoutineState extends Equatable {
selectedFunctions: selectedFunctions ?? this.selectedFunctions, selectedFunctions: selectedFunctions ?? this.selectedFunctions,
isLoading: isLoading ?? this.isLoading, isLoading: isLoading ?? this.isLoading,
errorMessage: errorMessage ?? this.errorMessage, errorMessage: errorMessage ?? this.errorMessage,
routineName: routineName ?? this.routineName,
selectedIcon: selectedIcon ?? this.selectedIcon,
); );
} }
@ -50,5 +58,7 @@ class RoutineState extends Equatable {
selectedFunctions, selectedFunctions,
isLoading, isLoading,
errorMessage, errorMessage,
routineName,
selectedIcon,
]; ];
} }

View File

@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
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>(
context: context,
builder: (BuildContext context) {
return BlocBuilder<RoutineBloc, RoutineState>(
builder: (context, state) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Container(
width: 600,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
DialogHeader('Create a scene: ${state.routineName ?? ""}'),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Left side - IF
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'IF:',
style: TextStyle(
fontSize: 16,
),
),
const SizedBox(height: 8),
if (context.read<RoutineBloc>().isTabToRun)
ListTile(
leading: SvgPicture.asset(
Assets.tabToRun,
width: 24,
height: 24,
),
title: const Text('Tab to run'),
),
],
),
),
const SizedBox(width: 16),
// Right side - THEN items
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'THEN:',
style: TextStyle(
fontSize: 16,
),
),
const SizedBox(height: 8),
...state.thenItems.map((item) {
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)),
subtitle: Wrap(
children: functions
.map((f) => Text(
'${f.operationName}: ${f.value}, ',
style: const TextStyle(
color:
ColorsManager.grayColor,
fontSize: 8),
overflow: TextOverflow.ellipsis,
maxLines: 3,
))
.toList(),
),
);
}),
],
),
),
],
),
),
if (state.errorMessage != null)
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
state.errorMessage!,
style: const TextStyle(color: Colors.red),
),
),
DialogFooter(
onCancel: () => Navigator.pop(context),
onConfirm: () {
context
.read<RoutineBloc>()
.add(const CreateSceneEvent());
Navigator.pop(context);
},
isConfirmEnabled: true,
),
],
),
),
);
},
);
},
);
}
}

View File

@ -10,13 +10,16 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
class SettingHelper { class SettingHelper {
static Future<Map<String, dynamic>?> showSettingDialog( static Future<String?> showSettingDialog(
{required BuildContext context, String? iconId, required bool isAutomation}) async { {required BuildContext context,
return showDialog<Map<String, dynamic>?>( String? iconId,
required bool isAutomation}) async {
return showDialog<String>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return BlocProvider( return BlocProvider(
create: (_) => SettingBloc()..add(InitialEvent(selectedIcon: iconId ?? '')), create: (_) =>
SettingBloc()..add(InitialEvent(selectedIcon: iconId ?? '')),
child: AlertDialog( child: AlertDialog(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
content: BlocBuilder<SettingBloc, SettingState>( content: BlocBuilder<SettingBloc, SettingState>(
@ -29,7 +32,9 @@ class SettingHelper {
} }
return Container( return Container(
width: context.read<SettingBloc>().isExpanded ? 800 : 400, width: context.read<SettingBloc>().isExpanded ? 800 : 400,
height: context.read<SettingBloc>().isExpanded && isAutomation ? 500 : 300, height: context.read<SettingBloc>().isExpanded && isAutomation
? 500
: 300,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
@ -52,13 +57,18 @@ class SettingHelper {
children: [ children: [
Container( Container(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 10, left: 10, right: 10, bottom: 10), top: 10,
left: 10,
right: 10,
bottom: 10),
child: Column( child: Column(
children: [ children: [
InkWell( InkWell(
onTap: () {}, onTap: () {},
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [ children: [
Text( Text(
'Validity', 'Validity',
@ -66,13 +76,18 @@ class SettingHelper {
.textTheme .textTheme
.bodyMedium! .bodyMedium!
.copyWith( .copyWith(
color: ColorsManager.textPrimaryColor, color: ColorsManager
fontWeight: FontWeight.w400, .textPrimaryColor,
fontWeight:
FontWeight
.w400,
fontSize: 14), fontSize: 14),
), ),
const Icon( const Icon(
Icons.arrow_forward_ios_outlined, Icons
color: ColorsManager.textGray, .arrow_forward_ios_outlined,
color: ColorsManager
.textGray,
size: 15, size: 15,
) )
], ],
@ -89,14 +104,18 @@ class SettingHelper {
), ),
InkWell( InkWell(
onTap: () { onTap: () {
BlocProvider.of<SettingBloc>(context).add( BlocProvider.of<SettingBloc>(
FetchIcons( context)
.add(FetchIcons(
expanded: !context expanded: !context
.read<SettingBloc>() .read<
SettingBloc>()
.isExpanded)); .isExpanded));
}, },
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [ children: [
Text( Text(
'Effective Period', 'Effective Period',
@ -104,13 +123,18 @@ class SettingHelper {
.textTheme .textTheme
.bodyMedium! .bodyMedium!
.copyWith( .copyWith(
color: ColorsManager.textPrimaryColor, color: ColorsManager
fontWeight: FontWeight.w400, .textPrimaryColor,
fontWeight:
FontWeight
.w400,
fontSize: 14), fontSize: 14),
), ),
const Icon( const Icon(
Icons.arrow_forward_ios_outlined, Icons
color: ColorsManager.textGray, .arrow_forward_ios_outlined,
color: ColorsManager
.textGray,
size: 15, size: 15,
) )
], ],
@ -126,7 +150,9 @@ class SettingHelper {
height: 5, height: 5,
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [ children: [
Text( Text(
'Executed by', 'Executed by',
@ -134,8 +160,10 @@ class SettingHelper {
.textTheme .textTheme
.bodyMedium! .bodyMedium!
.copyWith( .copyWith(
color: ColorsManager.textPrimaryColor, color: ColorsManager
fontWeight: FontWeight.w400, .textPrimaryColor,
fontWeight:
FontWeight.w400,
fontSize: 14), fontSize: 14),
), ),
Text('Cloud', Text('Cloud',
@ -143,8 +171,12 @@ class SettingHelper {
.textTheme .textTheme
.bodyMedium! .bodyMedium!
.copyWith( .copyWith(
color: ColorsManager.textGray, color:
fontWeight: FontWeight.w400, ColorsManager
.textGray,
fontWeight:
FontWeight
.w400,
fontSize: 14)), fontSize: 14)),
], ],
), ),
@ -157,19 +189,26 @@ class SettingHelper {
children: [ children: [
Container( Container(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 10, left: 10, right: 10, bottom: 10), top: 10,
left: 10,
right: 10,
bottom: 10),
child: Column( child: Column(
children: [ children: [
InkWell( InkWell(
onTap: () { onTap: () {
BlocProvider.of<SettingBloc>(context).add( BlocProvider.of<SettingBloc>(
FetchIcons( context)
.add(FetchIcons(
expanded: !context expanded: !context
.read<SettingBloc>() .read<
SettingBloc>()
.isExpanded)); .isExpanded));
}, },
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [ children: [
Text( Text(
'Icons', 'Icons',
@ -177,13 +216,18 @@ class SettingHelper {
.textTheme .textTheme
.bodyMedium! .bodyMedium!
.copyWith( .copyWith(
color: ColorsManager.textPrimaryColor, color: ColorsManager
fontWeight: FontWeight.w400, .textPrimaryColor,
fontWeight:
FontWeight
.w400,
fontSize: 14), fontSize: 14),
), ),
const Icon( const Icon(
Icons.arrow_forward_ios_outlined, Icons
color: ColorsManager.textGray, .arrow_forward_ios_outlined,
color: ColorsManager
.textGray,
size: 15, size: 15,
) )
], ],
@ -199,7 +243,9 @@ class SettingHelper {
height: 5, height: 5,
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [ children: [
Text( Text(
'Show on devices page', 'Show on devices page',
@ -207,17 +253,21 @@ class SettingHelper {
.textTheme .textTheme
.bodyMedium! .bodyMedium!
.copyWith( .copyWith(
color: ColorsManager.textPrimaryColor, color: ColorsManager
fontWeight: FontWeight.w400, .textPrimaryColor,
fontWeight:
FontWeight.w400,
fontSize: 14), fontSize: 14),
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment:
MainAxisAlignment.end,
children: [ children: [
Container( Container(
height: 30, height: 30,
width: 1, width: 1,
color: ColorsManager.graysColor, color: ColorsManager
.graysColor,
), ),
Transform.scale( Transform.scale(
scale: .8, scale: .8,
@ -241,7 +291,9 @@ class SettingHelper {
height: 5, height: 5,
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [ children: [
Text( Text(
'Executed by', 'Executed by',
@ -249,8 +301,10 @@ class SettingHelper {
.textTheme .textTheme
.bodyMedium! .bodyMedium!
.copyWith( .copyWith(
color: ColorsManager.textPrimaryColor, color: ColorsManager
fontWeight: FontWeight.w400, .textPrimaryColor,
fontWeight:
FontWeight.w400,
fontSize: 14), fontSize: 14),
), ),
Text('Cloud', Text('Cloud',
@ -258,8 +312,12 @@ class SettingHelper {
.textTheme .textTheme
.bodyMedium! .bodyMedium!
.copyWith( .copyWith(
color: ColorsManager.textGray, color:
fontWeight: FontWeight.w400, ColorsManager
.textGray,
fontWeight:
FontWeight
.w400,
fontSize: 14)), fontSize: 14)),
], ],
), ),
@ -268,12 +326,14 @@ class SettingHelper {
], ],
), ),
), ),
if (context.read<SettingBloc>().isExpanded && !isAutomation) if (context.read<SettingBloc>().isExpanded &&
!isAutomation)
SizedBox( SizedBox(
width: 400, width: 400,
height: 150, height: 150,
child: state is LoadingState child: state is LoadingState
? const Center(child: CircularProgressIndicator()) ? const Center(
child: CircularProgressIndicator())
: GridView.builder( : GridView.builder(
gridDelegate: gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount( const SliverGridDelegateWithFixedCrossAxisCount(
@ -290,7 +350,8 @@ class SettingHelper {
height: 35, height: 35,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
BlocProvider.of<SettingBloc>(context) BlocProvider.of<SettingBloc>(
context)
.add(SelectIcon( .add(SelectIcon(
iconId: iconModel.uuid, iconId: iconModel.uuid,
)); ));
@ -299,12 +360,16 @@ class SettingHelper {
child: SizedBox( child: SizedBox(
child: ClipOval( child: ClipOval(
child: Container( child: Container(
padding: const EdgeInsets.all(1), padding:
const EdgeInsets.all(1),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(
color: selectedIcon == iconModel.uuid color: selectedIcon ==
? ColorsManager.primaryColorWithOpacity iconModel.uuid
: Colors.transparent, ? ColorsManager
.primaryColorWithOpacity
: Colors
.transparent,
width: 2, width: 2,
), ),
shape: BoxShape.circle, shape: BoxShape.circle,
@ -319,8 +384,12 @@ class SettingHelper {
); );
}, },
)), )),
if (context.read<SettingBloc>().isExpanded && isAutomation) if (context.read<SettingBloc>().isExpanded &&
const SizedBox(height: 350, width: 400, child: EffectivePeriodView()) isAutomation)
const SizedBox(
height: 350,
width: 400,
child: EffectivePeriodView())
], ],
), ),
Container( Container(
@ -344,14 +413,20 @@ class SettingHelper {
alignment: AlignmentDirectional.center, alignment: AlignmentDirectional.center,
child: Text( child: Text(
'Cancel', 'Cancel',
style: Theme.of(context).textTheme.bodyMedium!.copyWith( style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color: ColorsManager.textGray, color: ColorsManager.textGray,
), ),
), ),
), ),
), ),
), ),
Container(width: 1, height: 50, color: ColorsManager.greyColor), Container(
width: 1,
height: 50,
color: ColorsManager.greyColor),
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
@ -361,8 +436,12 @@ class SettingHelper {
alignment: AlignmentDirectional.center, alignment: AlignmentDirectional.center,
child: Text( child: Text(
'Confirm', 'Confirm',
style: Theme.of(context).textTheme.bodyMedium!.copyWith( style: Theme.of(context)
color: ColorsManager.primaryColorWithOpacity, .textTheme
.bodyMedium!
.copyWith(
color: ColorsManager
.primaryColorWithOpacity,
), ),
), ),
), ),

View File

@ -0,0 +1,230 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
class CreateSceneModel {
String spaceUuid;
String iconId;
bool showInDevice;
String sceneName;
String decisionExpr;
List<CreateSceneAction> actions;
CreateSceneModel({
required this.spaceUuid,
required this.iconId,
required this.showInDevice,
required this.sceneName,
required this.decisionExpr,
required this.actions,
});
CreateSceneModel copyWith({
String? spaceUuid,
String? iconId,
bool? showInDevice,
String? sceneName,
String? decisionExpr,
List<CreateSceneAction>? actions,
bool? showInHomePage,
}) {
return CreateSceneModel(
spaceUuid: spaceUuid ?? this.spaceUuid,
iconId: iconId ?? this.iconId,
showInDevice: showInDevice ?? this.showInDevice,
sceneName: sceneName ?? this.sceneName,
decisionExpr: decisionExpr ?? this.decisionExpr,
actions: actions ?? this.actions,
);
}
Map<String, dynamic> toMap([String? sceneId]) {
return {
if (sceneId == null) 'spaceUuid': spaceUuid,
if (iconId.isNotEmpty) 'iconUuid': iconId,
'showInHomePage': showInDevice,
'sceneName': sceneName,
'decisionExpr': decisionExpr,
'actions': actions.map((x) => x.toMap()).toList(),
};
}
factory CreateSceneModel.fromMap(Map<String, dynamic> map) {
return CreateSceneModel(
spaceUuid: map['spaceUuid'] ?? '',
showInDevice: map['showInHomePage'] ?? false,
iconId: map['iconUuid'] ?? '',
sceneName: map['sceneName'] ?? '',
decisionExpr: map['decisionExpr'] ?? '',
actions: List<CreateSceneAction>.from(
map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
);
}
String toJson([String? sceneId]) => json.encode(toMap(sceneId));
factory CreateSceneModel.fromJson(String source) =>
CreateSceneModel.fromMap(json.decode(source));
@override
String toString() {
return 'CreateSceneModel(unitUuid: $spaceUuid, sceneName: $sceneName, decisionExpr: $decisionExpr, actions: $actions)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CreateSceneModel &&
other.spaceUuid == spaceUuid &&
other.iconId == iconId &&
other.showInDevice == showInDevice &&
other.sceneName == sceneName &&
other.decisionExpr == decisionExpr &&
listEquals(other.actions, actions);
}
@override
int get hashCode {
return spaceUuid.hashCode ^
sceneName.hashCode ^
decisionExpr.hashCode ^
actions.hashCode;
}
}
class CreateSceneAction {
String entityId;
String actionExecutor;
CreateSceneExecutorProperty? executorProperty;
CreateSceneAction({
required this.entityId,
required this.actionExecutor,
required this.executorProperty,
});
CreateSceneAction copyWith({
String? entityId,
String? actionExecutor,
CreateSceneExecutorProperty? executorProperty,
}) {
return CreateSceneAction(
entityId: entityId ?? this.entityId,
actionExecutor: actionExecutor ?? this.actionExecutor,
executorProperty: executorProperty ?? this.executorProperty,
);
}
Map<String, dynamic> toMap() {
if (executorProperty != null) {
return {
'entityId': entityId,
'actionExecutor': actionExecutor,
'executorProperty': executorProperty?.toMap(actionExecutor),
};
} else {
return {
'entityId': entityId,
'actionExecutor': actionExecutor,
};
}
}
factory CreateSceneAction.fromMap(Map<String, dynamic> map) {
return CreateSceneAction(
entityId: map['entityId'] ?? '',
actionExecutor: map['actionExecutor'] ?? '',
executorProperty:
CreateSceneExecutorProperty.fromMap(map['executorProperty']),
);
}
String toJson() => json.encode(toMap());
factory CreateSceneAction.fromJson(String source) =>
CreateSceneAction.fromMap(json.decode(source));
@override
String toString() =>
'CreateSceneAction(entityId: $entityId, actionExecutor: $actionExecutor, executorProperty: $executorProperty)';
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CreateSceneAction &&
other.entityId == entityId &&
other.actionExecutor == actionExecutor &&
other.executorProperty == executorProperty;
}
@override
int get hashCode =>
entityId.hashCode ^ actionExecutor.hashCode ^ executorProperty.hashCode;
}
class CreateSceneExecutorProperty {
String functionCode;
dynamic functionValue;
int delaySeconds;
CreateSceneExecutorProperty({
required this.functionCode,
required this.functionValue,
required this.delaySeconds,
});
CreateSceneExecutorProperty copyWith({
String? functionCode,
dynamic functionValue,
int? delaySeconds,
}) {
return CreateSceneExecutorProperty(
functionCode: functionCode ?? this.functionCode,
functionValue: functionValue ?? this.functionValue,
delaySeconds: delaySeconds ?? this.delaySeconds,
);
}
Map<String, dynamic> toMap(String actionExecutor) {
final map = <String, dynamic>{};
if (functionCode.isNotEmpty) map['functionCode'] = functionCode;
if (functionValue != null) map['functionValue'] = functionValue;
if (actionExecutor == 'delay' && delaySeconds > 0) {
map['delaySeconds'] = delaySeconds;
}
return map;
}
factory CreateSceneExecutorProperty.fromMap(Map<String, dynamic> map) {
return CreateSceneExecutorProperty(
functionCode: map['functionCode'] ?? '',
functionValue: map['functionValue'] ?? '',
delaySeconds: map['delaySeconds']?.toInt() ?? 0,
);
}
String toJson(String actionExecutor) => json.encode(toMap(actionExecutor));
factory CreateSceneExecutorProperty.fromJson(String source) =>
CreateSceneExecutorProperty.fromMap(json.decode(source));
@override
String toString() =>
'CreateSceneExecutorProperty(functionCode: $functionCode, functionValue: $functionValue, delaySeconds: $delaySeconds)';
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CreateSceneExecutorProperty &&
other.functionCode == functionCode &&
other.functionValue == functionValue &&
other.delaySeconds == delaySeconds;
}
@override
int get hashCode =>
functionCode.hashCode ^ functionValue.hashCode ^ delaySeconds.hashCode;
}

View File

@ -1,6 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/main.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart'; import 'package:syncrow_web/pages/common/text_field/custom_text_field.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/helper/setting_helper.dart'; import 'package:syncrow_web/pages/routiens/helper/setting_helper.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/utils/style.dart';
@ -28,7 +32,9 @@ class RoutineSearchAndButtons extends StatelessWidget {
children: [ children: [
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: constraints.maxWidth > 700 ? 450 : constraints.maxWidth - 32), maxWidth: constraints.maxWidth > 700
? 450
: constraints.maxWidth - 32),
child: StatefulTextField( child: StatefulTextField(
title: 'Routine Name', title: 'Routine Name',
height: 40, height: 40,
@ -38,6 +44,11 @@ class RoutineSearchAndButtons extends StatelessWidget {
elevation: 0, elevation: 0,
borderRadius: 15, borderRadius: 15,
width: 450, width: 450,
onChanged: (value) {
context
.read<RoutineBloc>()
.add(SearchRoutines(value));
},
), ),
), ),
(constraints.maxWidth <= 1000) (constraints.maxWidth <= 1000)
@ -48,8 +59,17 @@ class RoutineSearchAndButtons extends StatelessWidget {
child: Center( child: Center(
child: DefaultButton( child: DefaultButton(
onPressed: () async { onPressed: () async {
final result = await SettingHelper.showSettingDialog( final result =
context: context, isAutomation: true); await SettingHelper.showSettingDialog(
context: context,
isAutomation: context
.read<RoutineBloc>()
.isAutomation);
if (result != null) {
context
.read<RoutineBloc>()
.add(AddSelectedIcon(result));
}
}, },
borderRadius: 15, borderRadius: 15,
elevation: 0, elevation: 0,
@ -100,7 +120,9 @@ class RoutineSearchAndButtons extends StatelessWidget {
width: 200, width: 200,
child: Center( child: Center(
child: DefaultButton( child: DefaultButton(
onPressed: () {}, onPressed: () {
SaveRoutineHelper.showSaveRoutineDialog(context);
},
borderRadius: 15, borderRadius: 15,
elevation: 0, elevation: 0,
backgroundColor: ColorsManager.primaryColor, backgroundColor: ColorsManager.primaryColor,

View File

@ -4,7 +4,8 @@ import 'package:syncrow_web/pages/routiens/widgets/routines_title_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class ConditionTitleAndSearchBar extends StatelessWidget with HelperResponsiveLayout { class ConditionTitleAndSearchBar extends StatelessWidget
with HelperResponsiveLayout {
const ConditionTitleAndSearchBar({ const ConditionTitleAndSearchBar({
super.key, super.key,
}); });
@ -33,6 +34,7 @@ class ConditionTitleAndSearchBar extends StatelessWidget with HelperResponsiveLa
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
), ),
controller: TextEditingController(), controller: TextEditingController(),
onChanged: (value) {},
), ),
], ],
) )
@ -55,6 +57,7 @@ class ConditionTitleAndSearchBar extends StatelessWidget with HelperResponsiveLa
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
), ),
controller: TextEditingController(), controller: TextEditingController(),
onChanged: (value) {},
), ),
], ],
); );

View File

@ -1,3 +1,4 @@
import 'package:syncrow_web/pages/routiens/models/create_scene/create_scene_model.dart';
import 'package:syncrow_web/pages/routiens/models/icon_model.dart'; import 'package:syncrow_web/pages/routiens/models/icon_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/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';
@ -7,22 +8,22 @@ class SceneApi {
static final HTTPService _httpService = HTTPService(); static final HTTPService _httpService = HTTPService();
// //create scene // //create scene
// static Future<Map<String, dynamic>> createScene( static Future<Map<String, dynamic>> createScene(
// CreateSceneModel createSceneModel) async { CreateSceneModel createSceneModel) async {
// try { try {
// final response = await _httpService.post( final response = await _httpService.post(
// path: ApiEndpoints.createScene, path: ApiEndpoints.createScene,
// body: createSceneModel.toMap(), body: createSceneModel.toMap(),
// showServerMessage: false, showServerMessage: false,
// expectedResponseModel: (json) { expectedResponseModel: (json) {
// return json; return json;
// }, },
// ); );
// return response; return response;
// } catch (e) { } catch (e) {
// rethrow; rethrow;
// } }
// } }
// //
// // create automation // // create automation
// static Future<Map<String, dynamic>> createAutomation( // static Future<Map<String, dynamic>> createAutomation(

View File

@ -11,12 +11,14 @@ abstract class ApiEndpoints {
static const String visitorPassword = '/visitor-password'; static const String visitorPassword = '/visitor-password';
static const String getDevices = '/visitor-password/devices'; static const String getDevices = '/visitor-password/devices';
static const String sendOnlineOneTime = '/visitor-password/temporary-password/online/one-time'; static const String sendOnlineOneTime =
'/visitor-password/temporary-password/online/one-time';
static const String sendOnlineMultipleTime = static const String sendOnlineMultipleTime =
'/visitor-password/temporary-password/online/multiple-time'; '/visitor-password/temporary-password/online/multiple-time';
//offline Password //offline Password
static const String sendOffLineOneTime = '/visitor-password/temporary-password/offline/one-time'; static const String sendOffLineOneTime =
'/visitor-password/temporary-password/offline/one-time';
static const String sendOffLineMultipleTime = static const String sendOffLineMultipleTime =
'/visitor-password/temporary-password/offline/multiple-time'; '/visitor-password/temporary-password/offline/multiple-time';
@ -38,13 +40,18 @@ abstract class ApiEndpoints {
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}'; '/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
static const String scheduleByDeviceId = '/schedule/{deviceUuid}'; static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}'; static const String getScheduleByDeviceId =
static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}'; '/schedule/{deviceUuid}?category={category}';
static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}'; static const String deleteScheduleByDeviceId =
'/schedule/{deviceUuid}/{scheduleUuid}';
static const String updateScheduleByDeviceId =
'/schedule/enable/{deviceUuid}';
static const String factoryReset = '/device/factory/reset/{deviceUuid}'; static const String factoryReset = '/device/factory/reset/{deviceUuid}';
static const String powerClamp = '/device/{powerClampUuid}/power-clamp/status'; static const String powerClamp =
'/device/{powerClampUuid}/power-clamp/status';
static const String getSpaceScenes = '/scene/tap-to-run/{unitUuid}'; static const String getSpaceScenes = '/scene/tap-to-run/{unitUuid}';
static const String getSpaceAutomation = '/automation/{unitUuid}'; static const String getSpaceAutomation = '/automation/{unitUuid}';
static const String getIconScene = '/scene/icon'; static const String getIconScene = '/scene/icon';
static const String createScene = '/scene/tap-to-run';
} }