diff --git a/assets/icons/active_bell.svg b/assets/icons/active_bell.svg
new file mode 100644
index 00000000..3887ead5
--- /dev/null
+++ b/assets/icons/active_bell.svg
@@ -0,0 +1,21 @@
+
diff --git a/assets/icons/gear.svg b/assets/icons/gear.svg
new file mode 100644
index 00000000..02dbab04
--- /dev/null
+++ b/assets/icons/gear.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/pages/device_managment/all_devices/models/devices_model.dart b/lib/pages/device_managment/all_devices/models/devices_model.dart
index deac5b2a..2ea085c5 100644
--- a/lib/pages/device_managment/all_devices/models/devices_model.dart
+++ b/lib/pages/device_managment/all_devices/models/devices_model.dart
@@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/routines/models/device_functions.dart';
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
import 'package:syncrow_web/pages/routines/models/gang_switches/three_gang_switch/three_gang_switch.dart';
import 'package:syncrow_web/pages/routines/models/gang_switches/two_gang_switch/two_gang_switch.dart';
+import 'package:syncrow_web/pages/routines/models/gateway.dart';
import 'package:syncrow_web/pages/routines/models/wps/wps_functions.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/enum/device_types.dart';
@@ -318,6 +319,24 @@ SOS
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
];
+ case 'GW':
+ return [
+ GatewaySwitchAlarmSound(
+ deviceId: uuid ?? '',
+ deviceName: name ?? '',
+ type: 'BOTH',
+ ),
+ GatewayMasterState(
+ deviceId: uuid ?? '',
+ deviceName: name ?? '',
+ type: 'BOTH',
+ ),
+ GatewayFactoryReset(
+ deviceId: uuid ?? '',
+ deviceName: name ?? '',
+ type: 'BOTH',
+ ),
+ ];
default:
return [];
}
diff --git a/lib/pages/device_managment/gateway/model/gateway_model.dart b/lib/pages/device_managment/gateway/model/gateway_model.dart
new file mode 100644
index 00000000..a522aa00
--- /dev/null
+++ b/lib/pages/device_managment/gateway/model/gateway_model.dart
@@ -0,0 +1,49 @@
+class GatewayModel {
+ final String uuid;
+ final bool switchAlarmSound;
+ final String masterState;
+ final bool factoryReset;
+ final String alarmActive;
+
+ GatewayModel({
+ required this.uuid,
+ required this.switchAlarmSound,
+ required this.masterState,
+ required this.factoryReset,
+ required this.alarmActive,
+ });
+
+ factory GatewayModel.fromJson(Map json) {
+ final status = json['status'] as List? ?? [];
+
+ bool? switchAlarmSound;
+ String? masterState;
+ bool? factoryReset;
+ String? alarmActive;
+
+ for (final item in status) {
+ switch (item['code']) {
+ case 'switch_alarm_sound':
+ switchAlarmSound = item['value'] as bool;
+ break;
+ case 'master_state':
+ masterState = item['value'] as String;
+ break;
+ case 'factory_reset':
+ factoryReset = item['value'] as bool;
+ break;
+ case 'alarm_active':
+ alarmActive = item['value'] as String;
+ break;
+ }
+ }
+
+ return GatewayModel(
+ uuid: json['uuid'] as String? ?? '',
+ switchAlarmSound: switchAlarmSound ?? false,
+ masterState: masterState ?? '',
+ factoryReset: factoryReset ?? false,
+ alarmActive: alarmActive ?? '',
+ );
+ }
+}
diff --git a/lib/pages/routines/helper/dialog_helper/device_dialog_helper.dart b/lib/pages/routines/helper/dialog_helper/device_dialog_helper.dart
index df440004..b1afbc12 100644
--- a/lib/pages/routines/helper/dialog_helper/device_dialog_helper.dart
+++ b/lib/pages/routines/helper/dialog_helper/device_dialog_helper.dart
@@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ac_dialog.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/ceiling_sensor_helper.dart';
+import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/gateway/gateway_helper.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/three_gang_switch_dialog.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/two_gang_switch_dialog.dart';
@@ -107,6 +108,14 @@ class DeviceDialogHelper {
uniqueCustomId: data['uniqueCustomId'],
dialogType: dialogType,
);
+ case 'GW':
+ return GatewayHelper.showGatewayFunctionsDialog(
+ context: context,
+ functions: functions,
+ uniqueCustomId: data['uniqueCustomId'],
+ deviceSelectedFunctions: deviceSelectedFunctions,
+ device: data['device'],
+ );
default:
return null;
diff --git a/lib/pages/routines/models/gateway.dart b/lib/pages/routines/models/gateway.dart
new file mode 100644
index 00000000..b1a70d2e
--- /dev/null
+++ b/lib/pages/routines/models/gateway.dart
@@ -0,0 +1,111 @@
+import 'package:syncrow_web/pages/routines/models/device_functions.dart';
+import 'package:syncrow_web/utils/constants/assets.dart';
+
+class GatewayOperationalValue {
+ final String icon;
+ final String description;
+ final dynamic value;
+
+ GatewayOperationalValue({
+ required this.icon,
+ required this.description,
+ required this.value,
+ });
+}
+
+abstract class GatewayFunctions extends DeviceFunction {
+ final String type;
+
+ GatewayFunctions({
+ required super.deviceId,
+ required super.deviceName,
+ required super.code,
+ required super.operationName,
+ required super.icon,
+ required this.type,
+ });
+
+ List getOperationalValues();
+}
+
+final class GatewaySwitchAlarmSound extends GatewayFunctions {
+ GatewaySwitchAlarmSound({
+ required super.deviceId,
+ required super.deviceName,
+ required super.type,
+ }) : super(
+ code: 'switch_alarm_sound',
+ operationName: 'Switch Alarm Sound',
+ icon: Assets.activeBell,
+ );
+
+ @override
+ List getOperationalValues() => [
+ GatewayOperationalValue(
+ icon: Assets.assetsAcPower,
+ description: "ON",
+ value: true,
+ ),
+ GatewayOperationalValue(
+ icon: Assets.assetsAcPowerOFF,
+ description: "OFF",
+ value: false,
+ ),
+ ];
+}
+
+final class GatewayMasterState extends GatewayFunctions {
+ GatewayMasterState({
+ required super.deviceId,
+ required super.deviceName,
+ required super.type,
+ }) : super(
+ code: 'master_state',
+ operationName: 'Master State',
+ icon: Assets.gear,
+ );
+
+ @override
+ List getOperationalValues() {
+ return [
+ GatewayOperationalValue(
+ icon: Assets.assetsAcPower,
+ description: "Normal",
+ value: 'normal',
+ ),
+ GatewayOperationalValue(
+ icon: Assets.assetsAcPowerOFF,
+ description: "Alarm",
+ value: 'alarm',
+ ),
+ ];
+ }
+}
+
+final class GatewayFactoryReset extends GatewayFunctions {
+ GatewayFactoryReset({
+ required super.deviceId,
+ required super.deviceName,
+ required super.type,
+ }) : super(
+ code: 'factory_reset',
+ operationName: 'Factory Reset',
+ icon: Assets.factoryReset,
+ );
+
+ @override
+ List getOperationalValues() {
+ return [
+ GatewayOperationalValue(
+ icon: Assets.assetsAcPower,
+ description: "ON",
+ value: true,
+ ),
+ GatewayOperationalValue(
+ icon: Assets.assetsAcPowerOFF,
+ description: "OFF",
+ value: false,
+ ),
+ ];
+ }
+}
diff --git a/lib/pages/routines/widgets/if_container.dart b/lib/pages/routines/widgets/if_container.dart
index 5ca549fb..598ca406 100644
--- a/lib/pages/routines/widgets/if_container.dart
+++ b/lib/pages/routines/widgets/if_container.dart
@@ -27,8 +27,8 @@ class IfContainer extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('IF',
- style: TextStyle(
- fontSize: 18, fontWeight: FontWeight.bold)),
+ style:
+ TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
if (state.isAutomation && state.ifItems.isNotEmpty)
AutomationOperatorSelector(
selectedOperator: state.selectedAutomationOperator),
@@ -55,8 +55,8 @@ class IfContainer extends StatelessWidget {
(index) => GestureDetector(
onTap: () async {
if (!state.isTabToRun) {
- final result = await DeviceDialogHelper
- .showDeviceDialog(
+ final result =
+ await DeviceDialogHelper.showDeviceDialog(
context: context,
data: state.ifItems[index],
removeComparetors: false,
@@ -72,6 +72,7 @@ class IfContainer extends StatelessWidget {
'2G',
'3G',
'WPS',
+ 'GW',
'CPS',
].contains(
state.ifItems[index]['productType'])) {
@@ -82,8 +83,7 @@ class IfContainer extends StatelessWidget {
}
},
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(
@@ -91,12 +91,11 @@ class IfContainer extends StatelessWidget {
isFromThen: false,
isFromIf: true,
onRemove: () {
- context.read().add(
- RemoveDragCard(
- index: index,
- isFromThen: false,
- key: state.ifItems[index]
- ['uniqueCustomId']));
+ context.read().add(RemoveDragCard(
+ index: index,
+ isFromThen: false,
+ key: state.ifItems[index]
+ ['uniqueCustomId']));
},
),
)),
@@ -116,9 +115,7 @@ class IfContainer extends StatelessWidget {
if (!state.isTabToRun) {
if (mutableData['deviceId'] == 'tab_to_run') {
- context
- .read()
- .add(AddToIfContainer(mutableData, true));
+ context.read().add(AddToIfContainer(mutableData, true));
} else {
final result = await DeviceDialogHelper.showDeviceDialog(
dialogType: 'IF',
@@ -130,7 +127,7 @@ class IfContainer extends StatelessWidget {
context
.read()
.add(AddToIfContainer(mutableData, false));
- } else if (!['AC', '1G', '2G', '3G', 'WPS', 'CPS']
+ } else if (!['AC', '1G', '2G', '3G', 'WPS', 'GW', 'CPS']
.contains(mutableData['productType'])) {
context
.read()
diff --git a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart
index 0a22208c..92a837b6 100644
--- a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart
+++ b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart
@@ -183,7 +183,7 @@ class _FetchRoutineScenesState extends State
state.automations[index].id,
cardType: 'automations',
spaceName:
- state.scenes[index].spaceName,
+ state.automations[index].spaceName,
onTap: () {
BlocProvider.of(context)
.add(
diff --git a/lib/pages/routines/widgets/routine_devices.dart b/lib/pages/routines/widgets/routine_devices.dart
index 5f642bac..e568d3e0 100644
--- a/lib/pages/routines/widgets/routine_devices.dart
+++ b/lib/pages/routines/widgets/routine_devices.dart
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
@@ -18,6 +17,8 @@ class _RoutineDevicesState extends State {
context.read().add(FetchDevicesInRoutine());
}
+ static const _allowedProductTypes = {'AC', '1G', '2G', '3G', 'WPS', 'GW', 'CPS'};
+
@override
Widget build(BuildContext context) {
return BlocBuilder(
@@ -32,14 +33,8 @@ class _RoutineDevicesState extends State {
}
});
- List deviceList = state.devices
- .where((device) =>
- device.productType == 'AC' ||
- device.productType == '1G' ||
- device.productType == '2G' ||
- device.productType == '3G' ||
- device.productType == 'WPS' ||
- device.productType == 'CPS')
+ final deviceList = state.devices
+ .where((device) => _allowedProductTypes.contains(device.productType))
.toList();
return Wrap(
@@ -47,37 +42,32 @@ class _RoutineDevicesState extends State {
runSpacing: 10,
children: deviceList.asMap().entries.map((entry) {
final device = entry.value;
+
+ final deviceData = {
+ 'device': device,
+ 'imagePath': device.getDefaultIcon(device.productType),
+ 'title': device.name ?? '',
+ 'deviceId': device.uuid,
+ 'productType': device.productType,
+ 'functions': device.functions,
+ 'uniqueCustomId': '',
+ };
+
if (state.searchText != null && state.searchText!.isNotEmpty) {
return device.name!
.toLowerCase()
.contains(state.searchText!.toLowerCase())
? DraggableCard(
- imagePath: device.getDefaultIcon(device.productType),
- title: device.name ?? '',
- deviceData: {
- 'device': device,
- 'imagePath': device.getDefaultIcon(device.productType),
- 'title': device.name ?? '',
- 'deviceId': device.uuid,
- 'productType': device.productType,
- 'functions': device.functions,
- 'uniqueCustomId': '',
- },
+ imagePath: deviceData['imagePath'] as String,
+ title: deviceData['title'] as String,
+ deviceData: deviceData,
)
- : Container();
+ : const SizedBox.shrink();
} else {
return DraggableCard(
- imagePath: device.getDefaultIcon(device.productType),
- title: device.name ?? '',
- deviceData: {
- 'device': device,
- 'imagePath': device.getDefaultIcon(device.productType),
- 'title': device.name ?? '',
- 'deviceId': device.uuid,
- 'productType': device.productType,
- 'functions': device.functions,
- 'uniqueCustomId': '',
- },
+ imagePath: deviceData['imagePath'] as String,
+ title: deviceData['title'] as String,
+ deviceData: deviceData,
);
}
}).toList(),
diff --git a/lib/pages/routines/widgets/routine_dialog_function_list_tile.dart b/lib/pages/routines/widgets/routine_dialog_function_list_tile.dart
new file mode 100644
index 00000000..3e98a06e
--- /dev/null
+++ b/lib/pages/routines/widgets/routine_dialog_function_list_tile.dart
@@ -0,0 +1,42 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:syncrow_web/utils/color_manager.dart';
+import 'package:syncrow_web/utils/extension/build_context_x.dart';
+
+class RoutineDialogFunctionListTile extends StatelessWidget {
+ const RoutineDialogFunctionListTile({
+ super.key,
+ required this.iconPath,
+ required this.operationName,
+ required this.onTap,
+ });
+
+ final String iconPath;
+ final String operationName;
+ final void Function() onTap;
+
+ @override
+ Widget build(BuildContext context) {
+ return ListTile(
+ leading: SvgPicture.asset(
+ iconPath,
+ width: 24,
+ height: 24,
+ placeholderBuilder: (context) => const SizedBox(
+ width: 24,
+ height: 24,
+ ),
+ ),
+ title: Text(
+ operationName,
+ style: context.textTheme.bodyMedium,
+ ),
+ trailing: const Icon(
+ Icons.arrow_forward_ios,
+ size: 16,
+ color: ColorsManager.textGray,
+ ),
+ onTap: onTap,
+ );
+ }
+}
diff --git a/lib/pages/routines/widgets/routine_dialog_selection_list_tile.dart b/lib/pages/routines/widgets/routine_dialog_selection_list_tile.dart
new file mode 100644
index 00000000..b661e591
--- /dev/null
+++ b/lib/pages/routines/widgets/routine_dialog_selection_list_tile.dart
@@ -0,0 +1,47 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:syncrow_web/utils/color_manager.dart';
+import 'package:syncrow_web/utils/extension/build_context_x.dart';
+
+class RoutineDialogSelectionListTile extends StatelessWidget {
+ const RoutineDialogSelectionListTile({
+ required this.iconPath,
+ required this.description,
+ required this.isSelected,
+ required this.onTap,
+ super.key,
+ });
+
+ final bool isSelected;
+ final String iconPath;
+ final String description;
+ final void Function() onTap;
+
+ @override
+ Widget build(BuildContext context) {
+ return ListTile(
+ leading: SvgPicture.asset(
+ iconPath,
+ width: 24,
+ height: 24,
+ placeholderBuilder: (context) => Container(
+ width: 24,
+ height: 24,
+ color: Colors.transparent,
+ ),
+ ),
+ title: Text(
+ description,
+ style: context.textTheme.bodyMedium,
+ ),
+ trailing: Icon(
+ isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
+ size: 24,
+ color: isSelected
+ ? ColorsManager.primaryColorWithOpacity
+ : ColorsManager.textGray,
+ ),
+ onTap: onTap,
+ );
+ }
+}
diff --git a/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog.dart b/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog.dart
new file mode 100644
index 00000000..364854ce
--- /dev/null
+++ b/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog.dart
@@ -0,0 +1,130 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
+import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
+import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
+import 'package:syncrow_web/pages/routines/models/device_functions.dart';
+import 'package:syncrow_web/pages/routines/models/gateway.dart';
+import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
+import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
+import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog_value_selector.dart';
+import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/gateway/gateway_functions_list.dart';
+
+class GatewayDialog extends StatefulWidget {
+ const GatewayDialog({
+ required this.uniqueCustomId,
+ required this.functions,
+ required this.deviceSelectedFunctions,
+ required this.device,
+ super.key,
+ });
+
+ final String? uniqueCustomId;
+ final List functions;
+ final List deviceSelectedFunctions;
+ final AllDevicesModel? device;
+
+ @override
+ State createState() => _GatewayDialogState();
+}
+
+class _GatewayDialogState extends State {
+ late final List _gatewayFunctions;
+
+ @override
+ void initState() {
+ super.initState();
+ _gatewayFunctions = widget.functions.whereType().toList();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return AlertDialog(
+ contentPadding: EdgeInsets.zero,
+ content: BlocBuilder(
+ builder: (context, state) {
+ final selectedFunction = state.selectedFunction;
+ return Container(
+ width: selectedFunction != null ? 600 : 360,
+ height: 450,
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ padding: const EdgeInsets.only(top: 20),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const DialogHeader('Gateway Conditions'),
+ Expanded(child: _buildMainContent(context, state)),
+ _buildDialogFooter(context, state),
+ ],
+ ),
+ );
+ },
+ ),
+ );
+ }
+
+ Widget _buildMainContent(BuildContext context, FunctionBlocState state) {
+ final selectedFunction = state.selectedFunction;
+ final selectedOperationName = state.selectedOperationName;
+ final selectedFunctionData = state.addedFunctions.firstWhere(
+ (f) => f.functionCode == selectedFunction,
+ orElse: () => DeviceFunctionData(
+ entityId: '',
+ functionCode: selectedFunction ?? '',
+ operationName: '',
+ value: null,
+ ),
+ );
+ final selectedGatewayFunctions = _gatewayFunctions.firstWhere(
+ (f) => f.code == selectedFunction,
+ orElse: () => GatewaySwitchAlarmSound(
+ deviceId: '',
+ deviceName: '',
+ type: '',
+ ),
+ );
+ final operations = selectedGatewayFunctions.getOperationalValues();
+
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ GatewayFunctionsList(gatewayFunctions: _gatewayFunctions),
+ if (state.selectedFunction != null)
+ Expanded(
+ child: GatewayDialogValueSelector(
+ operations: operations,
+ selectedFunction: selectedFunction ?? '',
+ selectedFunctionData: selectedFunctionData,
+ gatewayFunctions: _gatewayFunctions,
+ operationName: selectedOperationName ?? '',
+ device: widget.device,
+ ),
+ ),
+ ],
+ );
+ }
+
+ Widget _buildDialogFooter(BuildContext context, FunctionBlocState state) {
+ return DialogFooter(
+ onCancel: () => Navigator.pop(context),
+ onConfirm: state.addedFunctions.isNotEmpty
+ ? () {
+ context.read().add(
+ AddFunctionToRoutine(
+ state.addedFunctions,
+ widget.uniqueCustomId ?? '-1',
+ ),
+ );
+ Navigator.pop(
+ context,
+ {'deviceId': widget.functions.firstOrNull?.deviceId},
+ );
+ }
+ : null,
+ isConfirmEnabled: state.selectedFunction != null,
+ );
+ }
+}
diff --git a/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog_value_selector.dart b/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog_value_selector.dart
new file mode 100644
index 00000000..392c3012
--- /dev/null
+++ b/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog_value_selector.dart
@@ -0,0 +1,58 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
+import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
+import 'package:syncrow_web/pages/routines/models/device_functions.dart';
+import 'package:syncrow_web/pages/routines/models/gateway.dart';
+import 'package:syncrow_web/pages/routines/widgets/routine_dialog_selection_list_tile.dart';
+
+class GatewayDialogValueSelector extends StatelessWidget {
+ const GatewayDialogValueSelector({
+ required this.operations,
+ required this.selectedFunction,
+ required this.selectedFunctionData,
+ required this.gatewayFunctions,
+ required this.device,
+ required this.operationName,
+ super.key,
+ });
+
+ final List operations;
+ final String selectedFunction;
+ final DeviceFunctionData? selectedFunctionData;
+ final List gatewayFunctions;
+ final AllDevicesModel? device;
+ final String operationName;
+
+ @override
+ Widget build(BuildContext context) {
+ return ListView.builder(
+ itemCount: operations.length,
+ itemBuilder: (context, index) {
+ final operation = operations[index];
+ final isSelected = selectedFunctionData?.value == operation.value;
+ return RoutineDialogSelectionListTile(
+ iconPath: operation.icon,
+ description: operation.description,
+ isSelected: isSelected,
+ onTap: () {
+ if (!isSelected) {
+ context.read().add(
+ AddFunction(
+ functionData: DeviceFunctionData(
+ entityId: device?.uuid ?? '',
+ functionCode: selectedFunction,
+ operationName: operationName,
+ value: operation.value,
+ condition: selectedFunctionData?.condition,
+ valueDescription: selectedFunctionData?.valueDescription,
+ ),
+ ),
+ );
+ }
+ },
+ );
+ },
+ );
+ }
+}
diff --git a/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_functions_list.dart b/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_functions_list.dart
new file mode 100644
index 00000000..6d253dcb
--- /dev/null
+++ b/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_functions_list.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
+import 'package:syncrow_web/pages/routines/models/gateway.dart';
+import 'package:syncrow_web/pages/routines/widgets/routine_dialog_function_list_tile.dart';
+import 'package:syncrow_web/utils/color_manager.dart';
+
+class GatewayFunctionsList extends StatelessWidget {
+ const GatewayFunctionsList({
+ required this.gatewayFunctions,
+ super.key,
+ });
+
+ final List gatewayFunctions;
+
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox(
+ width: 360,
+ child: ListView.separated(
+ shrinkWrap: false,
+ itemCount: gatewayFunctions.length,
+ separatorBuilder: (context, index) => const Padding(
+ padding: EdgeInsets.symmetric(horizontal: 40.0),
+ child: Divider(color: ColorsManager.dividerColor),
+ ),
+ itemBuilder: (context, index) {
+ final function = gatewayFunctions[index];
+ return RoutineDialogFunctionListTile(
+ iconPath: function.icon,
+ operationName: function.operationName,
+ onTap: () => context.read().add(
+ SelectFunction(
+ functionCode: function.code,
+ operationName: function.operationName,
+ ),
+ ),
+ );
+ },
+ ),
+ );
+ }
+}
diff --git a/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_helper.dart b/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_helper.dart
new file mode 100644
index 00000000..9a9351ca
--- /dev/null
+++ b/lib/pages/routines/widgets/routine_dialogs/gateway/gateway_helper.dart
@@ -0,0 +1,34 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
+import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
+import 'package:syncrow_web/pages/routines/models/device_functions.dart';
+import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog.dart';
+
+abstract final class GatewayHelper {
+ const GatewayHelper._();
+
+ static Future