mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
push calling create scene
This commit is contained in:
@ -18,6 +18,7 @@ class StatefulTextField extends StatefulWidget {
|
||||
this.padding,
|
||||
this.icon,
|
||||
this.hintColor,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
final String title;
|
||||
@ -32,6 +33,7 @@ class StatefulTextField extends StatefulWidget {
|
||||
final double? padding;
|
||||
final IconData? icon;
|
||||
final Color? hintColor;
|
||||
final Function(String)? onChanged;
|
||||
|
||||
@override
|
||||
State<StatefulTextField> createState() => _StatefulTextFieldState();
|
||||
@ -59,6 +61,7 @@ class _StatefulTextFieldState extends State<StatefulTextField> {
|
||||
padding: widget.padding,
|
||||
icon: widget.icon,
|
||||
hintColor: widget.hintColor,
|
||||
onChanged: widget.onChanged,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -78,6 +81,7 @@ class CustomTextField extends StatelessWidget {
|
||||
this.padding,
|
||||
this.icon,
|
||||
this.hintColor,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
final String title;
|
||||
@ -92,6 +96,7 @@ class CustomTextField extends StatelessWidget {
|
||||
final double? padding;
|
||||
final IconData? icon;
|
||||
final Color? hintColor;
|
||||
final Function(String)? onChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -120,14 +125,21 @@ class CustomTextField extends StatelessWidget {
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText,
|
||||
hintStyle: TextStyle(fontSize: 12, color: hintColor ?? ColorsManager.blackColor),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: padding ?? 10),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: hintColor ?? ColorsManager.blackColor),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: padding ?? 10),
|
||||
border: InputBorder.none,
|
||||
suffixIcon: icon != null ? Icon(icon, color: ColorsManager.greyColor) : null,
|
||||
suffixIcon: icon != null
|
||||
? Icon(icon, color: ColorsManager.greyColor)
|
||||
: null,
|
||||
),
|
||||
onFieldSubmitted: (_) {
|
||||
onSubmittedFun!();
|
||||
},
|
||||
onChanged: (value) {
|
||||
onChanged!(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -2,8 +2,10 @@ import 'package:flutter/material.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/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/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/extension/build_context_x.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()),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => SwitchTabsBloc()..add(const TriggerSwitchTabsEvent(false)),
|
||||
create: (context) =>
|
||||
SwitchTabsBloc()..add(const TriggerSwitchTabsEvent(false)),
|
||||
),
|
||||
],
|
||||
child: WebScaffold(
|
||||
@ -30,7 +33,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
style: Theme.of(context).textTheme.headlineLarge,
|
||||
),
|
||||
),
|
||||
centerBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(builder: (context, state) {
|
||||
centerBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(
|
||||
builder: (context, state) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@ -39,16 +43,21 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
backgroundColor: null,
|
||||
),
|
||||
onPressed: () {
|
||||
context.read<SwitchTabsBloc>().add(const TriggerSwitchTabsEvent(false));
|
||||
context
|
||||
.read<SwitchTabsBloc>()
|
||||
.add(const TriggerSwitchTabsEvent(false));
|
||||
},
|
||||
child: Text(
|
||||
'Devices',
|
||||
style: context.textTheme.titleMedium?.copyWith(
|
||||
color: state is SelectedTabState && state.selectedTab == false
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.grayColor,
|
||||
fontWeight:
|
||||
(state is SelectedTabState) && state.selectedTab == false ? FontWeight.w700 : FontWeight.w400,
|
||||
color:
|
||||
state is SelectedTabState && state.selectedTab == false
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.grayColor,
|
||||
fontWeight: (state is SelectedTabState) &&
|
||||
state.selectedTab == false
|
||||
? FontWeight.w700
|
||||
: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -57,16 +66,21 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
backgroundColor: null,
|
||||
),
|
||||
onPressed: () {
|
||||
context.read<SwitchTabsBloc>().add(const TriggerSwitchTabsEvent(true));
|
||||
context
|
||||
.read<SwitchTabsBloc>()
|
||||
.add(const TriggerSwitchTabsEvent(true));
|
||||
},
|
||||
child: Text(
|
||||
'Routines',
|
||||
style: context.textTheme.titleMedium?.copyWith(
|
||||
color: (state is SelectedTabState) && state.selectedTab == true
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.grayColor,
|
||||
color:
|
||||
(state is SelectedTabState) && state.selectedTab == true
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.grayColor,
|
||||
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(),
|
||||
scaffoldBody: CreateNewRoutineView(),
|
||||
// BlocBuilder<SwitchTabsBloc, SwitchTabsState>(builder: (context, state) {
|
||||
// if (state is SelectedTabState && state.selectedTab) {
|
||||
// return const RoutinesView();
|
||||
// }
|
||||
// if (state is ShowCreateRoutineState && state.showCreateRoutine) {
|
||||
// return const CreateNewRoutineView();
|
||||
// }
|
||||
//
|
||||
// return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
// 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 {
|
||||
// return const Center(child: Text('Error fetching Devices'));
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
// }),
|
||||
scaffoldBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(
|
||||
builder: (context, state) {
|
||||
if (state is SelectedTabState && state.selectedTab) {
|
||||
return const RoutinesView();
|
||||
}
|
||||
if (state is ShowCreateRoutineState && state.showCreateRoutine) {
|
||||
return const CreateNewRoutineView();
|
||||
}
|
||||
|
||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
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 {
|
||||
return const Center(child: Text('Error fetching Devices'));
|
||||
}
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -12,7 +12,8 @@ class DeviceSearchFilters extends StatefulWidget {
|
||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||
}
|
||||
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
with HelperResponsiveLayout {
|
||||
final TextEditingController communityController = TextEditingController();
|
||||
final TextEditingController unitNameController = TextEditingController();
|
||||
final TextEditingController productNameController = TextEditingController();
|
||||
@ -34,7 +35,8 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Space Name", unitNameController, 200),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
||||
_buildSearchField(
|
||||
"Device Name / Product Name", productNameController, 300),
|
||||
const SizedBox(width: 20),
|
||||
_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(
|
||||
child: StatefulTextField(
|
||||
title: title,
|
||||
@ -73,6 +76,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
|
||||
community: communityController.text,
|
||||
searchField: true));
|
||||
},
|
||||
onChanged: (p0) {},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.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/routine_model.dart';
|
||||
import 'package:syncrow_web/services/routines_api.dart';
|
||||
@ -20,6 +23,9 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
on<LoadScenes>(_onLoadScenes);
|
||||
on<LoadAutomation>(_onLoadAutomation);
|
||||
on<AddFunctionToRoutine>(_onAddFunctionsToRoutine);
|
||||
on<SearchRoutines>(_onSearchRoutines);
|
||||
on<AddSelectedIcon>(_onAddSelectedIcon);
|
||||
on<CreateSceneEvent>(_onCreateScene);
|
||||
// on<RemoveFunction>(_onRemoveFunction);
|
||||
// on<ClearFunctions>(_onClearFunctions);
|
||||
}
|
||||
@ -40,8 +46,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
void _onAddFunctionsToRoutine(
|
||||
AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
||||
debugPrint('Adding functions to routine: ${event.functions}');
|
||||
debugPrint('Unique Custom ID: ${event.uniqueCustomId}');
|
||||
final currentSelectedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
|
||||
@ -52,7 +56,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
|
||||
emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
|
||||
debugPrint('Updated selected functions: $currentSelectedFunctions');
|
||||
}
|
||||
|
||||
// void _onRemoveFunction(RemoveFunction event, Emitter<RoutineState> emit) {
|
||||
@ -80,7 +83,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: 'Something went wrong',
|
||||
errorMessage: 'Failed to load scenes',
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -98,7 +101,97 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -59,4 +59,24 @@ class RemoveFunction extends RoutineEvent {
|
||||
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 {}
|
||||
|
@ -9,6 +9,8 @@ class RoutineState extends Equatable {
|
||||
final Map<String, List<DeviceFunctionData>> selectedFunctions;
|
||||
final bool isLoading;
|
||||
final String? errorMessage;
|
||||
final String? routineName;
|
||||
final String? selectedIcon;
|
||||
|
||||
const RoutineState({
|
||||
this.ifItems = const [],
|
||||
@ -19,6 +21,8 @@ class RoutineState extends Equatable {
|
||||
this.selectedFunctions = const {},
|
||||
this.isLoading = false,
|
||||
this.errorMessage,
|
||||
this.routineName,
|
||||
this.selectedIcon,
|
||||
});
|
||||
|
||||
RoutineState copyWith({
|
||||
@ -29,6 +33,8 @@ class RoutineState extends Equatable {
|
||||
Map<String, List<DeviceFunctionData>>? selectedFunctions,
|
||||
bool? isLoading,
|
||||
String? errorMessage,
|
||||
String? routineName,
|
||||
String? selectedIcon,
|
||||
}) {
|
||||
return RoutineState(
|
||||
ifItems: ifItems ?? this.ifItems,
|
||||
@ -38,6 +44,8 @@ class RoutineState extends Equatable {
|
||||
selectedFunctions: selectedFunctions ?? this.selectedFunctions,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
routineName: routineName ?? this.routineName,
|
||||
selectedIcon: selectedIcon ?? this.selectedIcon,
|
||||
);
|
||||
}
|
||||
|
||||
@ -50,5 +58,7 @@ class RoutineState extends Equatable {
|
||||
selectedFunctions,
|
||||
isLoading,
|
||||
errorMessage,
|
||||
routineName,
|
||||
selectedIcon,
|
||||
];
|
||||
}
|
||||
|
132
lib/pages/routiens/helper/save_routine_helper.dart
Normal file
132
lib/pages/routiens/helper/save_routine_helper.dart
Normal 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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -10,13 +10,16 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class SettingHelper {
|
||||
static Future<Map<String, dynamic>?> showSettingDialog(
|
||||
{required BuildContext context, String? iconId, required bool isAutomation}) async {
|
||||
return showDialog<Map<String, dynamic>?>(
|
||||
static Future<String?> showSettingDialog(
|
||||
{required BuildContext context,
|
||||
String? iconId,
|
||||
required bool isAutomation}) async {
|
||||
return showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => SettingBloc()..add(InitialEvent(selectedIcon: iconId ?? '')),
|
||||
create: (_) =>
|
||||
SettingBloc()..add(InitialEvent(selectedIcon: iconId ?? '')),
|
||||
child: AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: BlocBuilder<SettingBloc, SettingState>(
|
||||
@ -29,7 +32,9 @@ class SettingHelper {
|
||||
}
|
||||
return Container(
|
||||
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(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
@ -52,13 +57,18 @@ class SettingHelper {
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10, left: 10, right: 10, bottom: 10),
|
||||
top: 10,
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Validity',
|
||||
@ -66,13 +76,18 @@ class SettingHelper {
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios_outlined,
|
||||
color: ColorsManager.textGray,
|
||||
Icons
|
||||
.arrow_forward_ios_outlined,
|
||||
color: ColorsManager
|
||||
.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
@ -89,14 +104,18 @@ class SettingHelper {
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(context).add(
|
||||
FetchIcons(
|
||||
BlocProvider.of<SettingBloc>(
|
||||
context)
|
||||
.add(FetchIcons(
|
||||
expanded: !context
|
||||
.read<SettingBloc>()
|
||||
.read<
|
||||
SettingBloc>()
|
||||
.isExpanded));
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Effective Period',
|
||||
@ -104,13 +123,18 @@ class SettingHelper {
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios_outlined,
|
||||
color: ColorsManager.textGray,
|
||||
Icons
|
||||
.arrow_forward_ios_outlined,
|
||||
color: ColorsManager
|
||||
.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
@ -126,7 +150,9 @@ class SettingHelper {
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Executed by',
|
||||
@ -134,8 +160,10 @@ class SettingHelper {
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Text('Cloud',
|
||||
@ -143,8 +171,12 @@ class SettingHelper {
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textGray,
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
ColorsManager
|
||||
.textGray,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14)),
|
||||
],
|
||||
),
|
||||
@ -157,19 +189,26 @@ class SettingHelper {
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10, left: 10, right: 10, bottom: 10),
|
||||
top: 10,
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(context).add(
|
||||
FetchIcons(
|
||||
BlocProvider.of<SettingBloc>(
|
||||
context)
|
||||
.add(FetchIcons(
|
||||
expanded: !context
|
||||
.read<SettingBloc>()
|
||||
.read<
|
||||
SettingBloc>()
|
||||
.isExpanded));
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Icons',
|
||||
@ -177,13 +216,18 @@ class SettingHelper {
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios_outlined,
|
||||
color: ColorsManager.textGray,
|
||||
Icons
|
||||
.arrow_forward_ios_outlined,
|
||||
color: ColorsManager
|
||||
.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
@ -199,7 +243,9 @@ class SettingHelper {
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Show on devices page',
|
||||
@ -207,17 +253,21 @@ class SettingHelper {
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
height: 30,
|
||||
width: 1,
|
||||
color: ColorsManager.graysColor,
|
||||
color: ColorsManager
|
||||
.graysColor,
|
||||
),
|
||||
Transform.scale(
|
||||
scale: .8,
|
||||
@ -241,7 +291,9 @@ class SettingHelper {
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Executed by',
|
||||
@ -249,8 +301,10 @@ class SettingHelper {
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Text('Cloud',
|
||||
@ -258,8 +312,12 @@ class SettingHelper {
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textGray,
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
ColorsManager
|
||||
.textGray,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14)),
|
||||
],
|
||||
),
|
||||
@ -268,12 +326,14 @@ class SettingHelper {
|
||||
],
|
||||
),
|
||||
),
|
||||
if (context.read<SettingBloc>().isExpanded && !isAutomation)
|
||||
if (context.read<SettingBloc>().isExpanded &&
|
||||
!isAutomation)
|
||||
SizedBox(
|
||||
width: 400,
|
||||
height: 150,
|
||||
child: state is LoadingState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
? const Center(
|
||||
child: CircularProgressIndicator())
|
||||
: GridView.builder(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
@ -290,7 +350,8 @@ class SettingHelper {
|
||||
height: 35,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(context)
|
||||
BlocProvider.of<SettingBloc>(
|
||||
context)
|
||||
.add(SelectIcon(
|
||||
iconId: iconModel.uuid,
|
||||
));
|
||||
@ -299,12 +360,16 @@ class SettingHelper {
|
||||
child: SizedBox(
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(1),
|
||||
padding:
|
||||
const EdgeInsets.all(1),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: selectedIcon == iconModel.uuid
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: Colors.transparent,
|
||||
color: selectedIcon ==
|
||||
iconModel.uuid
|
||||
? ColorsManager
|
||||
.primaryColorWithOpacity
|
||||
: Colors
|
||||
.transparent,
|
||||
width: 2,
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
@ -319,8 +384,12 @@ class SettingHelper {
|
||||
);
|
||||
},
|
||||
)),
|
||||
if (context.read<SettingBloc>().isExpanded && isAutomation)
|
||||
const SizedBox(height: 350, width: 400, child: EffectivePeriodView())
|
||||
if (context.read<SettingBloc>().isExpanded &&
|
||||
isAutomation)
|
||||
const SizedBox(
|
||||
height: 350,
|
||||
width: 400,
|
||||
child: EffectivePeriodView())
|
||||
],
|
||||
),
|
||||
Container(
|
||||
@ -344,14 +413,20 @@ class SettingHelper {
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(width: 1, height: 50, color: ColorsManager.greyColor),
|
||||
Container(
|
||||
width: 1,
|
||||
height: 50,
|
||||
color: ColorsManager.greyColor),
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
@ -361,8 +436,12 @@ class SettingHelper {
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Text(
|
||||
'Confirm',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.primaryColorWithOpacity,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
230
lib/pages/routiens/models/create_scene/create_scene_model.dart
Normal file
230
lib/pages/routiens/models/create_scene/create_scene_model.dart
Normal 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;
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
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/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/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
@ -28,7 +32,9 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: constraints.maxWidth > 700 ? 450 : constraints.maxWidth - 32),
|
||||
maxWidth: constraints.maxWidth > 700
|
||||
? 450
|
||||
: constraints.maxWidth - 32),
|
||||
child: StatefulTextField(
|
||||
title: 'Routine Name',
|
||||
height: 40,
|
||||
@ -38,6 +44,11 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
||||
elevation: 0,
|
||||
borderRadius: 15,
|
||||
width: 450,
|
||||
onChanged: (value) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(SearchRoutines(value));
|
||||
},
|
||||
),
|
||||
),
|
||||
(constraints.maxWidth <= 1000)
|
||||
@ -48,8 +59,17 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () async {
|
||||
final result = await SettingHelper.showSettingDialog(
|
||||
context: context, isAutomation: true);
|
||||
final result =
|
||||
await SettingHelper.showSettingDialog(
|
||||
context: context,
|
||||
isAutomation: context
|
||||
.read<RoutineBloc>()
|
||||
.isAutomation);
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddSelectedIcon(result));
|
||||
}
|
||||
},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
@ -100,7 +120,9 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
SaveRoutineHelper.showSaveRoutineDialog(context);
|
||||
},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
backgroundColor: ColorsManager.primaryColor,
|
||||
|
@ -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/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class ConditionTitleAndSearchBar extends StatelessWidget with HelperResponsiveLayout {
|
||||
class ConditionTitleAndSearchBar extends StatelessWidget
|
||||
with HelperResponsiveLayout {
|
||||
const ConditionTitleAndSearchBar({
|
||||
super.key,
|
||||
});
|
||||
@ -33,6 +34,7 @@ class ConditionTitleAndSearchBar extends StatelessWidget with HelperResponsiveLa
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
controller: TextEditingController(),
|
||||
onChanged: (value) {},
|
||||
),
|
||||
],
|
||||
)
|
||||
@ -55,6 +57,7 @@ class ConditionTitleAndSearchBar extends StatelessWidget with HelperResponsiveLa
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
controller: TextEditingController(),
|
||||
onChanged: (value) {},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -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/routine_model.dart';
|
||||
import 'package:syncrow_web/services/api/http_service.dart';
|
||||
@ -7,22 +8,22 @@ class SceneApi {
|
||||
static final HTTPService _httpService = HTTPService();
|
||||
|
||||
// //create scene
|
||||
// static Future<Map<String, dynamic>> createScene(
|
||||
// CreateSceneModel createSceneModel) async {
|
||||
// try {
|
||||
// final response = await _httpService.post(
|
||||
// path: ApiEndpoints.createScene,
|
||||
// body: createSceneModel.toMap(),
|
||||
// showServerMessage: false,
|
||||
// expectedResponseModel: (json) {
|
||||
// return json;
|
||||
// },
|
||||
// );
|
||||
// return response;
|
||||
// } catch (e) {
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
static Future<Map<String, dynamic>> createScene(
|
||||
CreateSceneModel createSceneModel) async {
|
||||
try {
|
||||
final response = await _httpService.post(
|
||||
path: ApiEndpoints.createScene,
|
||||
body: createSceneModel.toMap(),
|
||||
showServerMessage: false,
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
//
|
||||
// // create automation
|
||||
// static Future<Map<String, dynamic>> createAutomation(
|
||||
|
@ -11,12 +11,14 @@ abstract class ApiEndpoints {
|
||||
static const String visitorPassword = '/visitor-password';
|
||||
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 =
|
||||
'/visitor-password/temporary-password/online/multiple-time';
|
||||
|
||||
//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 =
|
||||
'/visitor-password/temporary-password/offline/multiple-time';
|
||||
|
||||
@ -38,13 +40,18 @@ abstract class ApiEndpoints {
|
||||
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
|
||||
|
||||
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
|
||||
static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}';
|
||||
static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}';
|
||||
static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}';
|
||||
static const String getScheduleByDeviceId =
|
||||
'/schedule/{deviceUuid}?category={category}';
|
||||
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 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 getSpaceAutomation = '/automation/{unitUuid}';
|
||||
static const String getIconScene = '/scene/icon';
|
||||
static const String createScene = '/scene/tap-to-run';
|
||||
}
|
||||
|
Reference in New Issue
Block a user