mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
Merge pull request #168 from SyncrowIOT/flush-presence-sensor-routines
fix real time garage door and add flush sensor to routines
This commit is contained in:
@ -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/flush_presence_sensor/flush_presence_sensor.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';
|
||||
@ -116,6 +117,15 @@ class DeviceDialogHelper {
|
||||
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||
device: data['device'],
|
||||
);
|
||||
case 'NCPS':
|
||||
return FlushPresenceSensor.showFlushFunctionsDialog(
|
||||
context: context,
|
||||
functions: functions,
|
||||
uniqueCustomId: data['uniqueCustomId'],
|
||||
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||
dialogType: dialogType,
|
||||
device: data['device'],
|
||||
);
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
407
lib/pages/routines/models/flush/flush_functions.dart
Normal file
407
lib/pages/routines/models/flush/flush_functions.dart
Normal file
@ -0,0 +1,407 @@
|
||||
import 'package:syncrow_web/pages/device_managment/flush_mounted_presence_sensor/models/flush_mounted_presence_sensor_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/flush/flush_operational_value.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
abstract class FlushFunctions
|
||||
extends DeviceFunction<FlushMountedPresenceSensorModel> {
|
||||
final String type;
|
||||
|
||||
FlushFunctions({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.code,
|
||||
required super.operationName,
|
||||
required super.icon,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
List<FlushOperationalValue> getOperationalValues();
|
||||
}
|
||||
|
||||
class FlushPresenceDelayFunction extends FlushFunctions {
|
||||
final int min;
|
||||
FlushPresenceDelayFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 0,
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codePresenceState,
|
||||
operationName: 'Presence State',
|
||||
icon: Assets.presenceStateIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
return [
|
||||
FlushOperationalValue(
|
||||
icon: Assets.nobodyTime,
|
||||
description: 'None',
|
||||
value: "none",
|
||||
),
|
||||
FlushOperationalValue(
|
||||
icon: Assets.presenceStateIcon,
|
||||
description: 'Presence',
|
||||
value: 'presence',
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class FlushSensiReduceFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
|
||||
FlushSensiReduceFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 1,
|
||||
max = 5,
|
||||
step = 1,
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeSensiReduce,
|
||||
operationName: 'Sensitivity Reduction',
|
||||
icon: Assets.motionlessDetectionSensitivityIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
return List.generate(
|
||||
(max - min) ~/ step + 1,
|
||||
(index) => FlushOperationalValue(
|
||||
icon: Assets.currentDistanceIcon,
|
||||
description: '${min + (index * step)}',
|
||||
value: min + (index * step),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class FlushNoneDelayFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final String unit;
|
||||
|
||||
FlushNoneDelayFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 10,
|
||||
max = 10000,
|
||||
unit = '秒',
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeNoneDelay,
|
||||
operationName: 'None Delay',
|
||||
icon: Assets.nobodyTime,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
return [
|
||||
FlushOperationalValue(
|
||||
icon: icon,
|
||||
description: 'Custom $unit',
|
||||
value: null,
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class FlushIlluminanceFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
|
||||
FlushIlluminanceFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 0,
|
||||
max = 2000,
|
||||
step = 0,
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeIlluminance,
|
||||
operationName: 'Illuminance',
|
||||
icon: Assets.IlluminanceIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
List<FlushOperationalValue> values = [];
|
||||
for (int lux = min; lux <= max; lux += step) {
|
||||
values.add(FlushOperationalValue(
|
||||
icon: Assets.IlluminanceIcon,
|
||||
description: "$lux Lux",
|
||||
value: lux,
|
||||
));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
class FlushOccurDistReduceFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
|
||||
FlushOccurDistReduceFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeOccurDistReduce,
|
||||
operationName: 'Occurrence Distance Reduction',
|
||||
icon: Assets.assetsTempreture,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
return List.generate(
|
||||
(max - min) ~/ step + 1,
|
||||
(index) => FlushOperationalValue(
|
||||
icon: Assets.assetsTempreture,
|
||||
description: '${min + (index * step)}',
|
||||
value: min + (index * step),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// ==== then functions ====
|
||||
class FlushSensitivityFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
|
||||
FlushSensitivityFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 1,
|
||||
max = 9,
|
||||
step = 1,
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeSensitivity,
|
||||
operationName: 'Sensitivity',
|
||||
icon: Assets.sensitivity,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
return List.generate(
|
||||
(max - min) ~/ step + 1,
|
||||
(index) => FlushOperationalValue(
|
||||
icon: Assets.motionDetectionSensitivityValueIcon,
|
||||
description: '${min + (index * step)}',
|
||||
value: min + (index * step),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class FlushNearDetectionFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final double max;
|
||||
final int step;
|
||||
final String unit;
|
||||
|
||||
FlushNearDetectionFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 0,
|
||||
max = 9.5,
|
||||
step = 1,
|
||||
unit = 'm',
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeNearDetection,
|
||||
operationName: 'Nearest Detect Dist',
|
||||
icon: Assets.currentDistanceIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
final values = <FlushOperationalValue>[];
|
||||
for (var value = min; value <= max; value += step) {
|
||||
values.add(FlushOperationalValue(
|
||||
icon: Assets.nobodyTime,
|
||||
description: '$value $unit',
|
||||
value: value * 10,
|
||||
));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
class FlushMaxDetectDistFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
final String unit;
|
||||
|
||||
FlushMaxDetectDistFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 75,
|
||||
max = 600,
|
||||
step = 75,
|
||||
unit = 'cm',
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeFarDetection,
|
||||
operationName: 'Max Detect Dist',
|
||||
icon: Assets.currentDistanceIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
final values = <FlushOperationalValue>[];
|
||||
for (var value = min; value <= max; value += step) {
|
||||
values.add(FlushOperationalValue(
|
||||
icon: Assets.nobodyTime,
|
||||
description: '$value $unit',
|
||||
value: value,
|
||||
));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
class FlushTargetConfirmTimeFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
final String unit;
|
||||
|
||||
FlushTargetConfirmTimeFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 75,
|
||||
max = 600,
|
||||
step = 75,
|
||||
unit = 'cm',
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codePresenceDelay,
|
||||
operationName: 'Target Confirm Time',
|
||||
icon: Assets.targetConfirmTimeIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
final values = <FlushOperationalValue>[];
|
||||
for (var value = min; value <= max; value += step) {
|
||||
values.add(FlushOperationalValue(
|
||||
icon: Assets.nobodyTime,
|
||||
description: '$value $unit',
|
||||
value: value,
|
||||
));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
class FlushDisappeDelayFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
final String unit;
|
||||
|
||||
FlushDisappeDelayFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 75,
|
||||
max = 600,
|
||||
step = 75,
|
||||
unit = 'cm',
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeNoneDelay,
|
||||
operationName: 'Disappe Delay',
|
||||
icon: Assets.DisappeDelayIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
final values = <FlushOperationalValue>[];
|
||||
for (var value = min; value <= max; value += step) {
|
||||
values.add(FlushOperationalValue(
|
||||
icon: Assets.nobodyTime,
|
||||
description: '$value $unit',
|
||||
value: value,
|
||||
));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
class FlushIndentLevelFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
final String unit;
|
||||
|
||||
FlushIndentLevelFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 75,
|
||||
max = 600,
|
||||
step = 75,
|
||||
unit = 'cm',
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeOccurDistReduce,
|
||||
operationName: 'Indent Level',
|
||||
icon: Assets.indentLevelIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
final values = <FlushOperationalValue>[];
|
||||
for (var value = min; value <= max; value += step) {
|
||||
values.add(FlushOperationalValue(
|
||||
icon: Assets.nobodyTime,
|
||||
description: '$value $unit',
|
||||
value: value,
|
||||
));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
class FlushTriggerLevelFunction extends FlushFunctions {
|
||||
final int min;
|
||||
final int max;
|
||||
final int step;
|
||||
final String unit;
|
||||
|
||||
FlushTriggerLevelFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : min = 75,
|
||||
max = 600,
|
||||
step = 75,
|
||||
unit = 'cm',
|
||||
super(
|
||||
code: FlushMountedPresenceSensorModel.codeSensiReduce,
|
||||
operationName: 'Trigger Level',
|
||||
icon: Assets.triggerLevelIcon,
|
||||
);
|
||||
|
||||
@override
|
||||
List<FlushOperationalValue> getOperationalValues() {
|
||||
final values = <FlushOperationalValue>[];
|
||||
for (var value = min; value <= max; value += step) {
|
||||
values.add(FlushOperationalValue(
|
||||
icon: Assets.nobodyTime,
|
||||
description: '$value $unit',
|
||||
value: value,
|
||||
));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
11
lib/pages/routines/models/flush/flush_operational_value.dart
Normal file
11
lib/pages/routines/models/flush/flush_operational_value.dart
Normal file
@ -0,0 +1,11 @@
|
||||
class FlushOperationalValue {
|
||||
final String icon;
|
||||
final String description;
|
||||
final dynamic value;
|
||||
|
||||
FlushOperationalValue({
|
||||
required this.icon,
|
||||
required this.description,
|
||||
required this.value,
|
||||
});
|
||||
}
|
@ -28,10 +28,12 @@ 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),
|
||||
selectedOperator:
|
||||
state.selectedAutomationOperator),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@ -55,16 +57,17 @@ class IfContainer extends StatelessWidget {
|
||||
(index) => GestureDetector(
|
||||
onTap: () async {
|
||||
if (!state.isTabToRun) {
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||
context: context,
|
||||
data: state.ifItems[index],
|
||||
removeComparetors: false,
|
||||
dialogType: "IF");
|
||||
final result = await DeviceDialogHelper
|
||||
.showDeviceDialog(
|
||||
context: context,
|
||||
data: state.ifItems[index],
|
||||
removeComparetors: false,
|
||||
dialogType: "IF");
|
||||
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(state.ifItems[index], false));
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToIfContainer(
|
||||
state.ifItems[index], false));
|
||||
} else if (![
|
||||
'AC',
|
||||
'1G',
|
||||
@ -73,25 +76,32 @@ class IfContainer extends StatelessWidget {
|
||||
'WPS',
|
||||
'GW',
|
||||
'CPS',
|
||||
].contains(state.ifItems[index]['productType'])) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(state.ifItems[index], false));
|
||||
'NCPS'
|
||||
].contains(state.ifItems[index]
|
||||
['productType'])) {
|
||||
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToIfContainer(
|
||||
state.ifItems[index], false));
|
||||
}
|
||||
}
|
||||
},
|
||||
child: DraggableCard(
|
||||
imagePath: state.ifItems[index]['imagePath'] ?? '',
|
||||
imagePath:
|
||||
state.ifItems[index]['imagePath'] ?? '',
|
||||
title: state.ifItems[index]['title'] ?? '',
|
||||
deviceData: state.ifItems[index],
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4, vertical: 8),
|
||||
isFromThen: false,
|
||||
isFromIf: true,
|
||||
onRemove: () {
|
||||
context.read<RoutineBloc>().add(RemoveDragCard(
|
||||
index: index,
|
||||
isFromThen: false,
|
||||
key: state.ifItems[index]['uniqueCustomId']));
|
||||
context.read<RoutineBloc>().add(
|
||||
RemoveDragCard(
|
||||
index: index,
|
||||
isFromThen: false,
|
||||
key: state.ifItems[index]
|
||||
['uniqueCustomId']));
|
||||
},
|
||||
),
|
||||
)),
|
||||
@ -112,7 +122,9 @@ class IfContainer extends StatelessWidget {
|
||||
|
||||
if (!state.isTabToRun) {
|
||||
if (mutableData['deviceId'] == 'tab_to_run') {
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, true));
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, true));
|
||||
} else {
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||
dialogType: 'IF',
|
||||
@ -121,10 +133,14 @@ class IfContainer extends StatelessWidget {
|
||||
removeComparetors: false);
|
||||
|
||||
if (result != null) {
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'GW', 'CPS']
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, false));
|
||||
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'GW', 'CPS', 'NCPS']
|
||||
.contains(mutableData['productType'])) {
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,7 +186,9 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'or'));
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'or'));
|
||||
},
|
||||
),
|
||||
Container(
|
||||
@ -196,7 +214,9 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'and'));
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'and'));
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -17,7 +17,16 @@ class _RoutineDevicesState extends State<RoutineDevices> {
|
||||
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||
}
|
||||
|
||||
static const _allowedProductTypes = {'AC', '1G', '2G', '3G', 'WPS', 'GW', 'CPS'};
|
||||
static const _allowedProductTypes = {
|
||||
'AC',
|
||||
'1G',
|
||||
'2G',
|
||||
'3G',
|
||||
'WPS',
|
||||
'GW',
|
||||
'CPS',
|
||||
'NCPS'
|
||||
};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -34,7 +43,8 @@ class _RoutineDevicesState extends State<RoutineDevices> {
|
||||
});
|
||||
|
||||
final deviceList = state.devices
|
||||
.where((device) => _allowedProductTypes.contains(device.productType))
|
||||
.where(
|
||||
(device) => _allowedProductTypes.contains(device.productType))
|
||||
.toList();
|
||||
|
||||
return Wrap(
|
||||
@ -51,12 +61,16 @@ class _RoutineDevicesState extends State<RoutineDevices> {
|
||||
'productType': device.productType,
|
||||
'functions': device.functions,
|
||||
'uniqueCustomId': '',
|
||||
'tag': device.deviceTags!.isNotEmpty ? device.deviceTags![0].name : '',
|
||||
'tag': device.deviceTags!.isNotEmpty
|
||||
? device.deviceTags![0].name
|
||||
: '',
|
||||
'subSpace': device.deviceSubSpace?.subspaceName ?? '',
|
||||
};
|
||||
|
||||
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
||||
return device.name!.toLowerCase().contains(state.searchText!.toLowerCase())
|
||||
return device.name!
|
||||
.toLowerCase()
|
||||
.contains(state.searchText!.toLowerCase())
|
||||
? DraggableCard(
|
||||
imagePath: deviceData['imagePath'] as String,
|
||||
title: deviceData['title'] as String,
|
||||
|
@ -0,0 +1,70 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.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/flush/flush_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/time_wheel.dart';
|
||||
|
||||
class FlushOperationalValuesList extends StatelessWidget {
|
||||
final List<FlushOperationalValue> values;
|
||||
final dynamic selectedValue;
|
||||
final AllDevicesModel? device;
|
||||
final String operationName;
|
||||
final String selectCode;
|
||||
final ValueChanged<FlushOperationalValue> onSelect;
|
||||
const FlushOperationalValuesList({
|
||||
required this.values,
|
||||
required this.selectedValue,
|
||||
required this.device,
|
||||
required this.operationName,
|
||||
required this.selectCode,
|
||||
required this.onSelect,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(20),
|
||||
itemCount: values.length,
|
||||
itemBuilder: (context, index) =>
|
||||
_buildValueItem(context, values[index]),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Widget _buildValueItem(BuildContext context, FlushOperationalValue value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(child: _buildValueDescription(value)),
|
||||
_buildValueRadio(context, value),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Widget _buildValueDescription(FlushOperationalValue value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(value.description),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildValueRadio(context, FlushOperationalValue value) {
|
||||
return Radio<dynamic>(
|
||||
value: value.value,
|
||||
groupValue: selectedValue,
|
||||
onChanged: (_) => onSelect(value));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.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/flush/flush_functions.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/flush_presence_sensor/flush_value_selector_widget.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class FlushPresenceSensor extends StatefulWidget {
|
||||
final List<DeviceFunction> functions;
|
||||
final AllDevicesModel? device;
|
||||
final List<DeviceFunctionData>? deviceSelectedFunctions;
|
||||
final String? uniqueCustomId;
|
||||
final String dialogType;
|
||||
final bool removeComparetors;
|
||||
|
||||
const FlushPresenceSensor({
|
||||
super.key,
|
||||
required this.functions,
|
||||
this.device,
|
||||
this.deviceSelectedFunctions,
|
||||
this.uniqueCustomId,
|
||||
required this.dialogType,
|
||||
this.removeComparetors = false,
|
||||
});
|
||||
|
||||
static Future<Map<String, dynamic>?> showFlushFunctionsDialog({
|
||||
required BuildContext context,
|
||||
required List<DeviceFunction> functions,
|
||||
AllDevicesModel? device,
|
||||
List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||
String? uniqueCustomId,
|
||||
required String dialogType,
|
||||
bool removeComparetors = false,
|
||||
}) async {
|
||||
return showDialog<Map<String, dynamic>?>(
|
||||
context: context,
|
||||
builder: (context) => FlushPresenceSensor(
|
||||
functions: functions,
|
||||
device: device,
|
||||
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||
uniqueCustomId: uniqueCustomId,
|
||||
removeComparetors: removeComparetors,
|
||||
dialogType: dialogType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
State<FlushPresenceSensor> createState() => _WallPresenceSensorState();
|
||||
}
|
||||
|
||||
class _WallPresenceSensorState extends State<FlushPresenceSensor> {
|
||||
late final List<FlushFunctions> _flushFunctions;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_flushFunctions =
|
||||
widget.functions.whereType<FlushFunctions>().where((function) {
|
||||
if (widget.dialogType == 'THEN') {
|
||||
return function.type == 'THEN' || function.type == 'BOTH';
|
||||
}
|
||||
return function.type == 'IF' || function.type == 'BOTH';
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => FunctionBloc()
|
||||
..add(InitializeFunctions(widget.deviceSelectedFunctions ?? [])),
|
||||
child: _buildDialogContent(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDialogContent() {
|
||||
return AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||
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('Presence Sensor Condition'),
|
||||
Expanded(child: _buildMainContent(context, state)),
|
||||
_buildDialogFooter(context, state),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMainContent(BuildContext context, FunctionBlocState state) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_buildFunctionList(context),
|
||||
if (state.selectedFunction != null) _buildValueSelector(context, state),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFunctionList(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 360,
|
||||
child: ListView.separated(
|
||||
shrinkWrap: false,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
itemCount: _flushFunctions.length,
|
||||
separatorBuilder: (context, index) => const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
child: Divider(color: ColorsManager.dividerColor),
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
final function = _flushFunctions[index];
|
||||
return ListTile(
|
||||
leading: SvgPicture.asset(
|
||||
function.icon,
|
||||
width: 24,
|
||||
height: 24,
|
||||
placeholderBuilder: (context) => const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
function.operationName,
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
trailing: const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 16,
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
onTap: () => context.read<FunctionBloc>().add(
|
||||
SelectFunction(
|
||||
functionCode: function.code,
|
||||
operationName: function.operationName,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildValueSelector(BuildContext context, FunctionBlocState state) {
|
||||
final selectedFunction = state.selectedFunction ?? '';
|
||||
final functionData = state.addedFunctions.firstWhere(
|
||||
(f) => f.functionCode == selectedFunction,
|
||||
orElse: () => DeviceFunctionData(
|
||||
entityId: '',
|
||||
functionCode: selectedFunction,
|
||||
operationName: state.selectedOperationName ?? '',
|
||||
value: null,
|
||||
),
|
||||
);
|
||||
|
||||
return Expanded(
|
||||
child: FlushValueSelectorWidget(
|
||||
selectedFunction: selectedFunction,
|
||||
functionData: functionData,
|
||||
flushFunctions: _flushFunctions,
|
||||
device: widget.device,
|
||||
dialogType: widget.dialogType,
|
||||
removeComparators: widget.removeComparetors,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDialogFooter(BuildContext context, FunctionBlocState state) {
|
||||
return DialogFooter(
|
||||
onCancel: () => Navigator.pop(context),
|
||||
onConfirm: state.addedFunctions.isNotEmpty
|
||||
? () {
|
||||
context.read<RoutineBloc>().add(
|
||||
AddFunctionToRoutine(
|
||||
state.addedFunctions,
|
||||
widget.uniqueCustomId!,
|
||||
),
|
||||
);
|
||||
Navigator.pop(
|
||||
context,
|
||||
{'deviceId': widget.functions.first.deviceId},
|
||||
);
|
||||
}
|
||||
: null,
|
||||
isConfirmEnabled: state.selectedFunction != null,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
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/device_managment/flush_mounted_presence_sensor/models/flush_mounted_presence_sensor_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/flush/flush_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/flush_presence_sensor/flush_operational_values_list.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
||||
|
||||
class FlushValueSelectorWidget extends StatelessWidget {
|
||||
final String selectedFunction;
|
||||
final DeviceFunctionData functionData;
|
||||
final List<FlushFunctions> flushFunctions;
|
||||
final AllDevicesModel? device;
|
||||
final String dialogType;
|
||||
final bool removeComparators;
|
||||
|
||||
const FlushValueSelectorWidget({
|
||||
required this.selectedFunction,
|
||||
required this.functionData,
|
||||
required this.flushFunctions,
|
||||
required this.device,
|
||||
required this.dialogType,
|
||||
required this.removeComparators,
|
||||
super.key,
|
||||
});
|
||||
|
||||
(double, double) get sliderRange => switch (functionData.functionCode) {
|
||||
FlushMountedPresenceSensorModel.codeOccurDistReduce => (0, 3),
|
||||
FlushMountedPresenceSensorModel.codeNoneDelay => (200, 3000),
|
||||
FlushMountedPresenceSensorModel.codeSensiReduce => (0, 3),
|
||||
FlushMountedPresenceSensorModel.codePresenceDelay => (0, 5),
|
||||
FlushMountedPresenceSensorModel.codeIlluminance => (0.0, 2000.0),
|
||||
FlushMountedPresenceSensorModel.codeFarDetection => (0.0, 9.5),
|
||||
FlushMountedPresenceSensorModel.codeNearDetection => (0.0, 9.5),
|
||||
_ => (0.0, 100.0),
|
||||
};
|
||||
|
||||
double get stepSize => switch (functionData.functionCode) {
|
||||
FlushMountedPresenceSensorModel.codeNoneDelay => 10.0,
|
||||
FlushMountedPresenceSensorModel.codeFarDetection => 0.5,
|
||||
FlushMountedPresenceSensorModel.codeNearDetection => 0.5,
|
||||
FlushMountedPresenceSensorModel.codePresenceDelay => 1.0,
|
||||
FlushMountedPresenceSensorModel.codeOccurDistReduce => 1.0,
|
||||
FlushMountedPresenceSensorModel.codeSensiReduce => 1.0,
|
||||
_ => 1.0,
|
||||
};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final selectedFn = flushFunctions.firstWhere(
|
||||
(f) => f.code == selectedFunction,
|
||||
orElse: () => throw Exception('Function $selectedFunction not found'),
|
||||
);
|
||||
|
||||
if (_isSliderFunction(selectedFunction)) {
|
||||
final isNearDetection =
|
||||
selectedFunction == FlushMountedPresenceSensorModel.codeNearDetection;
|
||||
final isFarDetection =
|
||||
selectedFunction == FlushMountedPresenceSensorModel.codeFarDetection;
|
||||
|
||||
final isDistanceDetection = isNearDetection || isFarDetection;
|
||||
double initialValue = (functionData.value as num?)?.toDouble() ?? 0.0;
|
||||
|
||||
if (isDistanceDetection) {
|
||||
initialValue = initialValue / 100;
|
||||
}
|
||||
return SliderValueSelector(
|
||||
currentCondition: functionData.condition,
|
||||
dialogType: dialogType,
|
||||
sliderRange: sliderRange,
|
||||
displayedValue: getDisplayText,
|
||||
initialValue: initialValue,
|
||||
onConditionChanged: (condition) => context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectedFunction,
|
||||
operationName: functionData.operationName,
|
||||
condition: condition,
|
||||
value: functionData.value ?? 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
onSliderChanged: (value) {
|
||||
final roundedValue = _roundToStep(value, stepSize);
|
||||
final finalValue =
|
||||
isDistanceDetection ? (roundedValue * 100).toInt() : roundedValue;
|
||||
|
||||
context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectedFunction,
|
||||
operationName: functionData.operationName,
|
||||
value: finalValue,
|
||||
condition: functionData.condition,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
unit: _unit,
|
||||
dividendOfRange: stepSize,
|
||||
);
|
||||
}
|
||||
|
||||
return FlushOperationalValuesList(
|
||||
values: selectedFn.getOperationalValues(),
|
||||
selectedValue: functionData.value,
|
||||
device: device,
|
||||
operationName: selectedFn.operationName,
|
||||
selectCode: selectedFunction,
|
||||
onSelect: (selectedValue) async {
|
||||
context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectedFunction,
|
||||
operationName: functionData.operationName,
|
||||
value: selectedValue.value,
|
||||
condition: functionData.condition,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
double _roundToStep(double value, double step) {
|
||||
return (value / step).roundToDouble() * step;
|
||||
}
|
||||
|
||||
bool _isSliderFunction(String function) => [
|
||||
FlushMountedPresenceSensorModel.codeOccurDistReduce,
|
||||
FlushMountedPresenceSensorModel.codeSensiReduce,
|
||||
FlushMountedPresenceSensorModel.codeNoneDelay,
|
||||
FlushMountedPresenceSensorModel.codeIlluminance,
|
||||
FlushMountedPresenceSensorModel.codePresenceDelay,
|
||||
FlushMountedPresenceSensorModel.codeFarDetection,
|
||||
FlushMountedPresenceSensorModel.codeNearDetection,
|
||||
].contains(function);
|
||||
|
||||
String get _unit => switch (functionData.functionCode) {
|
||||
FlushMountedPresenceSensorModel.codeOccurDistReduce => 'Min',
|
||||
FlushMountedPresenceSensorModel.codeSensiReduce => 'Sec',
|
||||
FlushMountedPresenceSensorModel.codeNoneDelay => 'Sec',
|
||||
FlushMountedPresenceSensorModel.codePresenceDelay => 'Sec',
|
||||
FlushMountedPresenceSensorModel.codeIlluminance => 'Lux',
|
||||
FlushMountedPresenceSensorModel.codeFarDetection => 'm',
|
||||
FlushMountedPresenceSensorModel.codeNearDetection => 'm',
|
||||
_ => '',
|
||||
};
|
||||
|
||||
String get getDisplayText {
|
||||
final num? value = functionData.value;
|
||||
double displayValue = value?.toDouble() ?? 0.0;
|
||||
|
||||
if (functionData.functionCode ==
|
||||
FlushMountedPresenceSensorModel.codeNearDetection ||
|
||||
functionData.functionCode ==
|
||||
FlushMountedPresenceSensorModel.codeFarDetection) {
|
||||
displayValue = displayValue / 100;
|
||||
}
|
||||
|
||||
switch (functionData.functionCode) {
|
||||
case FlushMountedPresenceSensorModel.codeFarDetection:
|
||||
case FlushMountedPresenceSensorModel.codeNearDetection:
|
||||
return displayValue.toStringAsFixed(1);
|
||||
case FlushMountedPresenceSensorModel.codeOccurDistReduce:
|
||||
case FlushMountedPresenceSensorModel.codeSensiReduce:
|
||||
case FlushMountedPresenceSensorModel.codePresenceDelay:
|
||||
return displayValue.toStringAsFixed(0);
|
||||
default:
|
||||
return displayValue.toStringAsFixed(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class TimeWheelPicker extends StatefulWidget {
|
||||
final int initialHours;
|
||||
final int initialMinutes;
|
||||
final int initialSeconds;
|
||||
final Function(int, int, int) onTimeChanged;
|
||||
|
||||
const TimeWheelPicker({
|
||||
super.key,
|
||||
required this.initialHours,
|
||||
required this.initialMinutes,
|
||||
required this.initialSeconds,
|
||||
required this.onTimeChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
State<TimeWheelPicker> createState() => _TimeWheelPickerState();
|
||||
}
|
||||
|
||||
class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
||||
late FixedExtentScrollController _hoursController;
|
||||
late FixedExtentScrollController _minutesController;
|
||||
late FixedExtentScrollController _secondsController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_hoursController =
|
||||
FixedExtentScrollController(initialItem: widget.initialHours);
|
||||
_minutesController =
|
||||
FixedExtentScrollController(initialItem: widget.initialMinutes);
|
||||
_secondsController =
|
||||
FixedExtentScrollController(initialItem: widget.initialSeconds);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(TimeWheelPicker oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.initialHours != widget.initialHours) {
|
||||
_hoursController.jumpToItem(widget.initialHours);
|
||||
}
|
||||
if (oldWidget.initialMinutes != widget.initialMinutes) {
|
||||
_minutesController.jumpToItem(widget.initialMinutes);
|
||||
}
|
||||
if (oldWidget.initialSeconds != widget.initialSeconds) {
|
||||
_secondsController.jumpToItem(widget.initialSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_hoursController.dispose();
|
||||
_minutesController.dispose();
|
||||
_secondsController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_buildPickerColumn(
|
||||
label: 'h',
|
||||
controller: _hoursController,
|
||||
itemCount: 3,
|
||||
onChanged: (value) {
|
||||
_handleTimeChange(
|
||||
value,
|
||||
_minutesController.selectedItem,
|
||||
_secondsController.selectedItem,
|
||||
);
|
||||
}),
|
||||
const SizedBox(width: 5),
|
||||
_buildPickerColumn(
|
||||
label: 'm',
|
||||
controller: _minutesController,
|
||||
itemCount: 60,
|
||||
onChanged: (value) {
|
||||
_handleTimeChange(
|
||||
_hoursController.selectedItem,
|
||||
value,
|
||||
_secondsController.selectedItem,
|
||||
);
|
||||
}),
|
||||
const SizedBox(width: 5),
|
||||
_buildPickerColumn(
|
||||
label: 's',
|
||||
controller: _secondsController,
|
||||
itemCount: 60,
|
||||
onChanged: (value) => _handleTimeChange(
|
||||
_hoursController.selectedItem,
|
||||
_minutesController.selectedItem,
|
||||
value,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _handleTimeChange(int hours, int minutes, int seconds) {
|
||||
int total = hours * 3600 + minutes * 60 + seconds;
|
||||
if (total > 10000) {
|
||||
hours = 2;
|
||||
minutes = 46;
|
||||
seconds = 40;
|
||||
total = 10000;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_hoursController.jumpToItem(hours);
|
||||
_minutesController.jumpToItem(minutes);
|
||||
_secondsController.jumpToItem(seconds);
|
||||
});
|
||||
}
|
||||
|
||||
widget.onTimeChanged(hours, minutes, seconds);
|
||||
}
|
||||
|
||||
Widget _buildPickerColumn({
|
||||
required String label,
|
||||
required FixedExtentScrollController controller,
|
||||
required int itemCount,
|
||||
required Function(int) onChanged,
|
||||
}) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
height: 40,
|
||||
width: 40,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.boxColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: ListWheelScrollView.useDelegate(
|
||||
controller: controller,
|
||||
itemExtent: 40.0,
|
||||
physics: const FixedExtentScrollPhysics(),
|
||||
onSelectedItemChanged: onChanged,
|
||||
childDelegate: ListWheelChildBuilderDelegate(
|
||||
builder: (context, index) => Center(
|
||||
child: Text(
|
||||
index.toString().padLeft(2),
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
color: ColorsManager.blue1,
|
||||
),
|
||||
),
|
||||
),
|
||||
childCount: itemCount,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
color: ColorsManager.blackColor,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -27,7 +27,8 @@ class ThenContainer extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('THEN',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 16),
|
||||
state.isLoading && state.isUpdate == true
|
||||
? const Center(
|
||||
@ -40,11 +41,12 @@ class ThenContainer extends StatelessWidget {
|
||||
state.thenItems.length,
|
||||
(index) => GestureDetector(
|
||||
onTap: () async {
|
||||
if (state.thenItems[index]['deviceId'] ==
|
||||
if (state.thenItems[index]
|
||||
['deviceId'] ==
|
||||
'delay') {
|
||||
final result = await DelayHelper
|
||||
.showDelayPickerDialog(
|
||||
context, state.thenItems[index]);
|
||||
.showDelayPickerDialog(context,
|
||||
state.thenItems[index]);
|
||||
|
||||
if (result != null) {
|
||||
context
|
||||
@ -64,14 +66,17 @@ class ThenContainer extends StatelessWidget {
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
AutomationDialog(
|
||||
automationName: state.thenItems[index]
|
||||
['name'] ??
|
||||
'Automation',
|
||||
automationId: state.thenItems[index]
|
||||
['deviceId'] ??
|
||||
'',
|
||||
uniqueCustomId: state.thenItems[index]
|
||||
['uniqueCustomId'],
|
||||
automationName:
|
||||
state.thenItems[index]
|
||||
['name'] ??
|
||||
'Automation',
|
||||
automationId:
|
||||
state.thenItems[index]
|
||||
['deviceId'] ??
|
||||
'',
|
||||
uniqueCustomId:
|
||||
state.thenItems[index]
|
||||
['uniqueCustomId'],
|
||||
),
|
||||
);
|
||||
|
||||
@ -80,11 +85,13 @@ class ThenContainer extends StatelessWidget {
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToThenContainer({
|
||||
...state.thenItems[index],
|
||||
'imagePath': Assets.automation,
|
||||
'title': state.thenItems[index]
|
||||
['name'] ??
|
||||
'imagePath':
|
||||
Assets.automation,
|
||||
'title':
|
||||
state.thenItems[index]
|
||||
['title'],
|
||||
['name'] ??
|
||||
state.thenItems[index]
|
||||
['title'],
|
||||
}));
|
||||
}
|
||||
return;
|
||||
@ -109,8 +116,9 @@ class ThenContainer extends StatelessWidget {
|
||||
'WPS',
|
||||
'CPS',
|
||||
"GW",
|
||||
].contains(
|
||||
state.thenItems[index]['productType'])) {
|
||||
"NCPS"
|
||||
].contains(state.thenItems[index]
|
||||
['productType'])) {
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToThenContainer(
|
||||
state.thenItems[index]));
|
||||
@ -120,7 +128,9 @@ class ThenContainer extends StatelessWidget {
|
||||
imagePath: state.thenItems[index]
|
||||
['imagePath'] ??
|
||||
'',
|
||||
title: state.thenItems[index]['title'] ?? '',
|
||||
title: state.thenItems[index]
|
||||
['title'] ??
|
||||
'',
|
||||
deviceData: state.thenItems[index],
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4, vertical: 8),
|
||||
@ -157,8 +167,8 @@ class ThenContainer extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (mutableData['type'] == 'automation') {
|
||||
int index = state.thenItems
|
||||
.indexWhere((item) => item['deviceId'] == mutableData['deviceId']);
|
||||
int index = state.thenItems.indexWhere(
|
||||
(item) => item['deviceId'] == mutableData['deviceId']);
|
||||
if (index != -1) {
|
||||
return;
|
||||
}
|
||||
@ -183,8 +193,8 @@ class ThenContainer extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (mutableData['type'] == 'tap_to_run' && state.isAutomation) {
|
||||
int index = state.thenItems
|
||||
.indexWhere((item) => item['deviceId'] == mutableData['deviceId']);
|
||||
int index = state.thenItems.indexWhere(
|
||||
(item) => item['deviceId'] == mutableData['deviceId']);
|
||||
if (index != -1) {
|
||||
return;
|
||||
}
|
||||
@ -222,7 +232,7 @@ class ThenContainer extends StatelessWidget {
|
||||
dialogType: "THEN");
|
||||
if (result != null) {
|
||||
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
|
||||
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'GW', 'CPS']
|
||||
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'GW', 'CPS', "NCPS"]
|
||||
.contains(mutableData['productType'])) {
|
||||
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
|
||||
}
|
||||
|
Reference in New Issue
Block a user