mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
Refactor wall presence sensor components and add new widgets for improved functionality and clarity to ensure reusability in the future for other devices.
This commit is contained in:
33
lib/pages/routines/widgets/condition_toggle.dart
Normal file
33
lib/pages/routines/widgets/condition_toggle.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class ConditionToggle extends StatelessWidget {
|
||||
final String? currentCondition;
|
||||
final void Function(String condition) onChanged;
|
||||
|
||||
const ConditionToggle({
|
||||
required this.onChanged,
|
||||
this.currentCondition,
|
||||
super.key,
|
||||
});
|
||||
|
||||
static const _conditions = ["<", "==", ">"];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ToggleButtons(
|
||||
onPressed: (index) => onChanged(_conditions[index]),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
||||
selectedColor: Colors.white,
|
||||
fillColor: ColorsManager.primaryColorWithOpacity,
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
constraints: const BoxConstraints(
|
||||
minHeight: 40.0,
|
||||
minWidth: 40.0,
|
||||
),
|
||||
isSelected: _conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
children: _conditions.map((c) => Text(c)).toList(),
|
||||
);
|
||||
}
|
||||
}
|
26
lib/pages/routines/widgets/function_slider.dart
Normal file
26
lib/pages/routines/widgets/function_slider.dart
Normal file
@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FunctionSlider extends StatelessWidget {
|
||||
final dynamic initialValue;
|
||||
|
||||
final (double min, double max) range;
|
||||
final void Function(double value) onChanged;
|
||||
|
||||
const FunctionSlider({
|
||||
required this.onChanged,
|
||||
required this.initialValue,
|
||||
required this.range,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Slider(
|
||||
value: initialValue is int ? initialValue.toDouble() : range.$1,
|
||||
min: range.$1,
|
||||
max: range.$2,
|
||||
divisions: (range.$2 - range.$1).toInt(),
|
||||
onChanged: onChanged,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
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/wps/wps_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/wps/wps_operational_value.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/wall_sensor/time_wheel.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wps_value_selector_widget.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
|
||||
class WallPresenceSensor extends StatefulWidget {
|
||||
final List<DeviceFunction> functions;
|
||||
@ -63,8 +62,7 @@ class _WallPresenceSensorState extends State<WallPresenceSensor> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_wpsFunctions =
|
||||
widget.functions.whereType<WpsFunctions>().where((function) {
|
||||
_wpsFunctions = widget.functions.whereType<WpsFunctions>().where((function) {
|
||||
if (widget.dialogType == 'THEN') {
|
||||
return function.type == 'THEN' || function.type == 'BOTH';
|
||||
}
|
||||
@ -176,10 +174,10 @@ class _WallPresenceSensorState extends State<WallPresenceSensor> {
|
||||
);
|
||||
|
||||
return Expanded(
|
||||
child: _ValueSelector(
|
||||
child: WpsValueSelectorWidget(
|
||||
selectedFunction: selectedFunction,
|
||||
functionData: functionData,
|
||||
acFunctions: _wpsFunctions,
|
||||
wpsFunctions: _wpsFunctions,
|
||||
device: widget.device,
|
||||
dialogType: widget.dialogType!,
|
||||
removeComparators: widget.removeComparetors,
|
||||
@ -208,342 +206,3 @@ class _WallPresenceSensorState extends State<WallPresenceSensor> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ValueSelector extends StatelessWidget {
|
||||
final String selectedFunction;
|
||||
final DeviceFunctionData functionData;
|
||||
final List<WpsFunctions> acFunctions;
|
||||
final AllDevicesModel? device;
|
||||
final String dialogType;
|
||||
final bool removeComparators;
|
||||
|
||||
const _ValueSelector({
|
||||
required this.selectedFunction,
|
||||
required this.functionData,
|
||||
required this.acFunctions,
|
||||
required this.device,
|
||||
required this.dialogType,
|
||||
required this.removeComparators,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final selectedFn =
|
||||
acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final values = selectedFn.getOperationalValues();
|
||||
|
||||
if (_isSliderFunction(selectedFunction)) {
|
||||
return _SliderValueSelector(
|
||||
selectedFunction: selectedFunction,
|
||||
functionData: functionData,
|
||||
device: device,
|
||||
dialogType: dialogType,
|
||||
);
|
||||
}
|
||||
|
||||
return _OperationalValuesList(
|
||||
values: values,
|
||||
selectedValue: functionData.value,
|
||||
device: device,
|
||||
operationName: selectedFn.operationName,
|
||||
selectCode: selectedFunction,
|
||||
);
|
||||
}
|
||||
|
||||
bool _isSliderFunction(String function) =>
|
||||
['dis_current', 'presence_time', 'illuminance_value'].contains(function);
|
||||
}
|
||||
|
||||
class _SliderValueSelector extends StatelessWidget {
|
||||
final String selectedFunction;
|
||||
final DeviceFunctionData functionData;
|
||||
final AllDevicesModel? device;
|
||||
final String dialogType;
|
||||
|
||||
const _SliderValueSelector({
|
||||
required this.selectedFunction,
|
||||
required this.functionData,
|
||||
required this.device,
|
||||
required this.dialogType,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final initialValue = functionData.value ?? 250;
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
_ConditionToggle(
|
||||
currentCondition: functionData.condition,
|
||||
selectCode: selectedFunction,
|
||||
device: device,
|
||||
operationName: functionData.operationName,
|
||||
selectedValue: functionData.value,
|
||||
),
|
||||
_ValueDisplay(
|
||||
value: initialValue,
|
||||
functionCode: selectedFunction,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_FunctionSlider(
|
||||
initialValue: initialValue,
|
||||
functionCode: selectedFunction,
|
||||
functionData: functionData,
|
||||
device: device,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConditionToggle extends StatelessWidget {
|
||||
final String? currentCondition;
|
||||
final String selectCode;
|
||||
final AllDevicesModel? device;
|
||||
final String operationName;
|
||||
final dynamic selectedValue;
|
||||
|
||||
const _ConditionToggle({
|
||||
this.currentCondition,
|
||||
required this.selectCode,
|
||||
this.device,
|
||||
required this.operationName,
|
||||
this.selectedValue,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const conditions = ["<", "==", ">"];
|
||||
return ToggleButtons(
|
||||
onPressed: (index) => _updateCondition(context, conditions[index]),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
||||
selectedColor: Colors.white,
|
||||
fillColor: ColorsManager.primaryColorWithOpacity,
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
constraints: const BoxConstraints(
|
||||
minHeight: 40.0,
|
||||
minWidth: 40.0,
|
||||
),
|
||||
isSelected:
|
||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
children: conditions.map((c) => Text(c)).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
void _updateCondition(BuildContext context, String condition) {
|
||||
context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectCode,
|
||||
operationName: operationName,
|
||||
condition: condition,
|
||||
value: selectedValue,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ValueDisplay extends StatelessWidget {
|
||||
final dynamic value;
|
||||
final String functionCode;
|
||||
|
||||
const _ValueDisplay({
|
||||
required this.value,
|
||||
required this.functionCode,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
_getDisplayText(),
|
||||
style: context.textTheme.headlineMedium!.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _getDisplayText() {
|
||||
final intValue = (value as num?)?.toInt() ?? 0;
|
||||
switch (functionCode) {
|
||||
case 'presence_time':
|
||||
return '$intValue Min';
|
||||
case 'dis_current':
|
||||
return '$intValue CM';
|
||||
case 'illuminance_value':
|
||||
return '$intValue Lux';
|
||||
default:
|
||||
return '$intValue';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _FunctionSlider extends StatelessWidget {
|
||||
final dynamic initialValue;
|
||||
final String functionCode;
|
||||
final DeviceFunctionData functionData;
|
||||
final AllDevicesModel? device;
|
||||
|
||||
const _FunctionSlider({
|
||||
required this.initialValue,
|
||||
required this.functionCode,
|
||||
required this.functionData,
|
||||
required this.device,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final (min, max) = _getSliderRange();
|
||||
return Slider(
|
||||
value: initialValue is int ? initialValue.toDouble() : min,
|
||||
min: min,
|
||||
max: max,
|
||||
divisions: (max - min).toInt(),
|
||||
onChanged: (value) => _updateValue(context, value.toInt()),
|
||||
);
|
||||
}
|
||||
|
||||
(double, double) _getSliderRange() {
|
||||
switch (functionCode) {
|
||||
case 'presence_time':
|
||||
return (0, 65535);
|
||||
case 'dis_current':
|
||||
return (1, 600);
|
||||
case 'illuminance_value':
|
||||
return (0, 10000);
|
||||
default:
|
||||
return (200, 300);
|
||||
}
|
||||
}
|
||||
|
||||
void _updateValue(BuildContext context, int value) {
|
||||
context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: functionCode,
|
||||
operationName: functionData.operationName,
|
||||
value: value,
|
||||
condition: functionData.condition,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _OperationalValuesList extends StatelessWidget {
|
||||
final List<WpsOperationalValue> values;
|
||||
final dynamic selectedValue;
|
||||
final AllDevicesModel? device;
|
||||
final String operationName;
|
||||
final String selectCode;
|
||||
|
||||
const _OperationalValuesList({
|
||||
required this.values,
|
||||
required this.selectedValue,
|
||||
required this.device,
|
||||
required this.operationName,
|
||||
required this.selectCode,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return operationName == 'Nobody Time'
|
||||
? _buildTimeWheel(context)
|
||||
: ListView.builder(
|
||||
padding: const EdgeInsets.all(20),
|
||||
itemCount: values.length,
|
||||
itemBuilder: (context, index) =>
|
||||
_buildValueItem(context, values[index]),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTimeWheel(BuildContext context) {
|
||||
final currentTotalSeconds = selectedValue as int? ?? 0;
|
||||
return TimeWheelPicker(
|
||||
initialHours: currentTotalSeconds ~/ 3600,
|
||||
initialMinutes: (currentTotalSeconds % 3600) ~/ 60,
|
||||
initialSeconds: currentTotalSeconds % 60,
|
||||
onTimeChanged: (h, m, s) => _updateTotalSeconds(context, h, m, s),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildValueItem(BuildContext context, WpsOperationalValue value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_buildValueIcon(context, value),
|
||||
Expanded(child: _buildValueDescription(value)),
|
||||
_buildValueRadio(context, value),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildValueIcon(context, WpsOperationalValue value) {
|
||||
return Column(
|
||||
children: [
|
||||
if (_shouldShowTextDescription)
|
||||
Text(value.description.replaceAll("cm", '')),
|
||||
SvgPicture.asset(value.icon, width: 25, height: 25),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
bool get _shouldShowTextDescription =>
|
||||
operationName == 'Far Detection' ||
|
||||
operationName == 'Motionless Detection Sensitivity';
|
||||
|
||||
Widget _buildValueDescription(WpsOperationalValue value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(value.description),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildValueRadio(context, WpsOperationalValue value) {
|
||||
return Radio<dynamic>(
|
||||
value: value.value,
|
||||
groupValue: selectedValue,
|
||||
onChanged: (_) => _selectValue(context, value.value),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectValue(BuildContext context, dynamic value) {
|
||||
context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectCode,
|
||||
operationName: operationName,
|
||||
value: value,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _updateTotalSeconds(BuildContext context, int h, int m, int s) {
|
||||
context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectCode,
|
||||
operationName: operationName,
|
||||
value: h * 3600 + m * 60 + s,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,114 @@
|
||||
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/wps/wps_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/time_wheel.dart';
|
||||
|
||||
class WpsOperationalValuesList extends StatelessWidget {
|
||||
final List<WpsOperationalValue> values;
|
||||
final dynamic selectedValue;
|
||||
final AllDevicesModel? device;
|
||||
final String operationName;
|
||||
final String selectCode;
|
||||
|
||||
const WpsOperationalValuesList({
|
||||
required this.values,
|
||||
required this.selectedValue,
|
||||
required this.device,
|
||||
required this.operationName,
|
||||
required this.selectCode,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return operationName == 'Nobody Time'
|
||||
? _buildTimeWheel(context)
|
||||
: ListView.builder(
|
||||
padding: const EdgeInsets.all(20),
|
||||
itemCount: values.length,
|
||||
itemBuilder: (context, index) => _buildValueItem(context, values[index]),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTimeWheel(BuildContext context) {
|
||||
final currentTotalSeconds = selectedValue as int? ?? 0;
|
||||
return TimeWheelPicker(
|
||||
initialHours: currentTotalSeconds ~/ 3600,
|
||||
initialMinutes: (currentTotalSeconds % 3600) ~/ 60,
|
||||
initialSeconds: currentTotalSeconds % 60,
|
||||
onTimeChanged: (h, m, s) => _updateTotalSeconds(context, h, m, s),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildValueItem(BuildContext context, WpsOperationalValue value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_buildValueIcon(context, value),
|
||||
Expanded(child: _buildValueDescription(value)),
|
||||
_buildValueRadio(context, value),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildValueIcon(context, WpsOperationalValue value) {
|
||||
return Column(
|
||||
children: [
|
||||
if (_shouldShowTextDescription) Text(value.description.replaceAll("cm", '')),
|
||||
SvgPicture.asset(value.icon, width: 25, height: 25),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
bool get _shouldShowTextDescription =>
|
||||
operationName == 'Far Detection' ||
|
||||
operationName == 'Motionless Detection Sensitivity';
|
||||
|
||||
Widget _buildValueDescription(WpsOperationalValue value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(value.description),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildValueRadio(context, WpsOperationalValue value) {
|
||||
return Radio<dynamic>(
|
||||
value: value.value,
|
||||
groupValue: selectedValue,
|
||||
onChanged: (_) => _selectValue(context, value.value),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectValue(BuildContext context, dynamic value) {
|
||||
context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectCode,
|
||||
operationName: operationName,
|
||||
value: value,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _updateTotalSeconds(BuildContext context, int h, int m, int s) {
|
||||
context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectCode,
|
||||
operationName: operationName,
|
||||
value: h * 3600 + m * 60 + s,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
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/wps/wps_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wps_operational_values_list.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
||||
|
||||
class WpsValueSelectorWidget extends StatelessWidget {
|
||||
final String selectedFunction;
|
||||
final DeviceFunctionData functionData;
|
||||
final List<WpsFunctions> wpsFunctions;
|
||||
final AllDevicesModel? device;
|
||||
final String dialogType;
|
||||
final bool removeComparators;
|
||||
|
||||
const WpsValueSelectorWidget({
|
||||
required this.selectedFunction,
|
||||
required this.functionData,
|
||||
required this.wpsFunctions,
|
||||
required this.device,
|
||||
required this.dialogType,
|
||||
required this.removeComparators,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final selectedFn = wpsFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||
final values = selectedFn.getOperationalValues();
|
||||
|
||||
if (_isSliderFunction(selectedFunction)) {
|
||||
return SliderValueSelector(
|
||||
selectedFunction: selectedFunction,
|
||||
functionData: functionData,
|
||||
device: device,
|
||||
dialogType: dialogType,
|
||||
sliderRange: sliderRange,
|
||||
displayedValue: getDisplayText,
|
||||
initialValue: functionData.value ?? 250,
|
||||
onConditionChanged: (condition) => context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectedFunction,
|
||||
operationName: functionData.operationName,
|
||||
condition: condition,
|
||||
value: functionData.value,
|
||||
),
|
||||
),
|
||||
),
|
||||
onSliderChanged: (value) => context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectedFunction,
|
||||
operationName: functionData.operationName,
|
||||
value: value.toInt(),
|
||||
condition: functionData.condition,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return WpsOperationalValuesList(
|
||||
values: values,
|
||||
selectedValue: functionData.value,
|
||||
device: device,
|
||||
operationName: selectedFn.operationName,
|
||||
selectCode: selectedFunction,
|
||||
);
|
||||
}
|
||||
|
||||
bool _isSliderFunction(String function) =>
|
||||
['dis_current', 'presence_time', 'illuminance_value'].contains(function);
|
||||
|
||||
(double, double) get sliderRange => switch (functionData.functionCode) {
|
||||
'presence_time' => (0, 65535),
|
||||
'dis_current' => (0, 600),
|
||||
'illuminance_value' => (0, 10000),
|
||||
_ => (200, 300),
|
||||
};
|
||||
|
||||
String get getDisplayText {
|
||||
final intValue = int.tryParse('${functionData.value ?? ''}');
|
||||
return switch (functionData.functionCode) {
|
||||
'presence_time' => '${intValue ?? '0'} Min',
|
||||
'dis_current' => '${intValue ?? '250'} CM',
|
||||
'illuminance_value' => '${intValue ?? '0'} Lux',
|
||||
_ => '$intValue',
|
||||
};
|
||||
}
|
||||
}
|
67
lib/pages/routines/widgets/slider_value_selector.dart
Normal file
67
lib/pages/routines/widgets/slider_value_selector.dart
Normal file
@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/condition_toggle.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/function_slider.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/value_display.dart';
|
||||
|
||||
class SliderValueSelector extends StatelessWidget {
|
||||
final String selectedFunction;
|
||||
final DeviceFunctionData functionData;
|
||||
final AllDevicesModel? device;
|
||||
final String dialogType;
|
||||
final (double, double) sliderRange;
|
||||
final String displayedValue;
|
||||
final Object? initialValue;
|
||||
final void Function(String condition) onConditionChanged;
|
||||
final void Function(double value) onSliderChanged;
|
||||
|
||||
const SliderValueSelector({
|
||||
required this.selectedFunction,
|
||||
required this.functionData,
|
||||
required this.device,
|
||||
required this.dialogType,
|
||||
required this.sliderRange,
|
||||
required this.displayedValue,
|
||||
required this.initialValue,
|
||||
required this.onConditionChanged,
|
||||
required this.onSliderChanged,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
ConditionToggle(
|
||||
currentCondition: functionData.condition,
|
||||
onChanged: onConditionChanged,
|
||||
),
|
||||
ValueDisplay(
|
||||
value: initialValue,
|
||||
label: displayedValue,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FunctionSlider(
|
||||
initialValue: initialValue,
|
||||
range: sliderRange, onChanged: onSliderChanged,
|
||||
// void _updateValue(BuildContext context, int value) {
|
||||
// context.read<FunctionBloc>().add(
|
||||
// AddFunction(
|
||||
// functionData: DeviceFunctionData(
|
||||
// entityId: device?.uuid ?? '',
|
||||
// functionCode: functionCode,
|
||||
// operationName: functionData.operationName,
|
||||
// value: value,
|
||||
// condition: functionData.condition,
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
31
lib/pages/routines/widgets/value_display.dart
Normal file
31
lib/pages/routines/widgets/value_display.dart
Normal file
@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class ValueDisplay extends StatelessWidget {
|
||||
final dynamic value;
|
||||
final String label;
|
||||
|
||||
const ValueDisplay({
|
||||
required this.value,
|
||||
required this.label,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: context.textTheme.headlineMedium!.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user