mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00

Add dialogType parameter in WaterHeaterPresenceSensor and CeilingSensorDialog. Update step parameter in FlushValueSelectorWidget. Update step parameter in FunctionBloc and WaterHeaterFunctions. Update step, unit, min, and max parameters in ACFunction subclasses.
479 lines
18 KiB
Dart
479 lines
18 KiB
Dart
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/ac/ac_function.dart';
|
|
import 'package:syncrow_web/pages/routines/models/ac/ac_operational_value.dart';
|
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.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/helpers/routine_tap_function_helper.dart';
|
|
import 'package:syncrow_web/utils/color_manager.dart';
|
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
|
|
class ACHelper {
|
|
static Future<Map<String, dynamic>?> showACFunctionsDialog({
|
|
required BuildContext context,
|
|
required List<DeviceFunction> functions,
|
|
required AllDevicesModel? device,
|
|
required List<DeviceFunctionData>? deviceSelectedFunctions,
|
|
required String uniqueCustomId,
|
|
required bool? removeComparetors,
|
|
required String dialogType,
|
|
}) async {
|
|
List<ACFunction> acFunctions =
|
|
functions.whereType<ACFunction>().where((function) {
|
|
if (dialogType == 'THEN') {
|
|
return function.type == 'THEN' || function.type == 'BOTH';
|
|
}
|
|
return function.type == 'IF' || function.type == 'BOTH';
|
|
}).toList();
|
|
// List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
|
|
|
|
return showDialog<Map<String, dynamic>?>(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return BlocProvider(
|
|
create: (_) => FunctionBloc()
|
|
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
|
child: AlertDialog(
|
|
contentPadding: EdgeInsets.zero,
|
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
|
builder: (context, 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,
|
|
));
|
|
|
|
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('AC Functions'),
|
|
Expanded(
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
// Function list
|
|
SizedBox(
|
|
width: selectedFunction != null ? 320 : 360,
|
|
child: _buildFunctionsList(
|
|
context: context,
|
|
acFunctions: acFunctions,
|
|
device: device,
|
|
onFunctionSelected:
|
|
(functionCode, operationName) {
|
|
RoutineTapFunctionHelper.onTapFunction(
|
|
context,
|
|
functionCode: functionCode,
|
|
functionOperationName: operationName,
|
|
functionValueDescription:
|
|
selectedFunctionData.valueDescription,
|
|
deviceUuid: device?.uuid,
|
|
codesToAddIntoFunctionsWithDefaultValue: [
|
|
'temp_set',
|
|
'temp_current',
|
|
],
|
|
defaultValue: 0);
|
|
},
|
|
),
|
|
),
|
|
// Value selector
|
|
if (selectedFunction != null)
|
|
Expanded(
|
|
child: _buildValueSelector(
|
|
context: context,
|
|
selectedFunction: selectedFunction,
|
|
selectedFunctionData: selectedFunctionData,
|
|
acFunctions: acFunctions,
|
|
device: device,
|
|
operationName: selectedOperationName ?? '',
|
|
removeComparators: removeComparetors,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
DialogFooter(
|
|
onCancel: () {
|
|
Navigator.pop(context);
|
|
},
|
|
onConfirm: state.addedFunctions.isNotEmpty
|
|
? () {
|
|
/// add the functions to the routine bloc
|
|
context.read<RoutineBloc>().add(
|
|
AddFunctionToRoutine(
|
|
state.addedFunctions,
|
|
uniqueCustomId,
|
|
),
|
|
);
|
|
|
|
// Return the device data to be added to the container
|
|
Navigator.pop(context, {
|
|
'deviceId': functions.first.deviceId,
|
|
});
|
|
}
|
|
: null,
|
|
isConfirmEnabled: selectedFunction != null,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
},
|
|
).then((value) {
|
|
return value;
|
|
});
|
|
}
|
|
|
|
/// Build functions list for AC functions dialog
|
|
static Widget _buildFunctionsList({
|
|
required BuildContext context,
|
|
required List<ACFunction> acFunctions,
|
|
required Function(String, String) onFunctionSelected,
|
|
required AllDevicesModel? device,
|
|
}) {
|
|
return ListView.separated(
|
|
shrinkWrap: false,
|
|
physics: const AlwaysScrollableScrollPhysics(),
|
|
itemCount: acFunctions.length,
|
|
separatorBuilder: (context, index) => const Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
|
child: Divider(
|
|
color: ColorsManager.dividerColor,
|
|
),
|
|
),
|
|
itemBuilder: (context, index) {
|
|
final function = acFunctions[index];
|
|
return ListTile(
|
|
leading: SvgPicture.asset(
|
|
function.icon,
|
|
width: 24,
|
|
height: 24,
|
|
placeholderBuilder: (BuildContext context) => Container(
|
|
width: 24,
|
|
height: 24,
|
|
color: Colors.transparent,
|
|
),
|
|
),
|
|
title: Text(
|
|
function.operationName,
|
|
style: context.textTheme.bodyMedium,
|
|
),
|
|
trailing: const Icon(
|
|
Icons.arrow_forward_ios,
|
|
size: 16,
|
|
color: ColorsManager.textGray,
|
|
),
|
|
onTap: () => onFunctionSelected(
|
|
function.code,
|
|
function.operationName,
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
/// Build value selector for AC functions dialog
|
|
static Widget _buildValueSelector({
|
|
required BuildContext context,
|
|
required String selectedFunction,
|
|
required DeviceFunctionData? selectedFunctionData,
|
|
required List<ACFunction> acFunctions,
|
|
AllDevicesModel? device,
|
|
required String operationName,
|
|
bool? removeComparators,
|
|
}) {
|
|
final selectedFn =
|
|
acFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
|
|
if (selectedFunction == 'temp_set' || selectedFunction == 'temp_current') {
|
|
// Convert stored integer value to display value
|
|
final displayValue =
|
|
(selectedFunctionData?.value ?? selectedFn.min ?? 0) / 10;
|
|
final minValue = selectedFn.min! / 10;
|
|
final maxValue = selectedFn.max! / 10;
|
|
return CustomRoutinesTextbox(
|
|
withSpecialChar: true,
|
|
dividendOfRange: maxValue,
|
|
currentCondition: selectedFunctionData?.condition,
|
|
dialogType: selectedFn.type,
|
|
sliderRange: (minValue, maxValue),
|
|
displayedValue: displayValue.toStringAsFixed(1),
|
|
initialValue: displayValue.toDouble(),
|
|
unit: selectedFn.unit!,
|
|
onConditionChanged: (condition) => context.read<FunctionBloc>().add(
|
|
AddFunction(
|
|
functionData: DeviceFunctionData(
|
|
entityId: device?.uuid ?? '',
|
|
functionCode: selectedFunction,
|
|
operationName: selectedFn.operationName,
|
|
condition: condition,
|
|
value: 0,
|
|
step: selectedFn.step,
|
|
unit: selectedFn.unit,
|
|
max: selectedFn.max,
|
|
min: selectedFn.min,
|
|
),
|
|
),
|
|
),
|
|
onTextChanged: (value) => context.read<FunctionBloc>().add(
|
|
AddFunction(
|
|
functionData: DeviceFunctionData(
|
|
entityId: device?.uuid ?? '',
|
|
functionCode: selectedFunction,
|
|
operationName: selectedFn.operationName,
|
|
value: (value * 10).round(), // Store as integer
|
|
condition: selectedFunctionData?.condition,
|
|
step: selectedFn.step,
|
|
unit: selectedFn.unit,
|
|
max: selectedFn.max,
|
|
min: selectedFn.min,
|
|
),
|
|
),
|
|
),
|
|
stepIncreaseAmount: selectedFn.step! / 10, // Convert step for display
|
|
);
|
|
}
|
|
|
|
return _buildOperationalValuesList(
|
|
context: context,
|
|
values: selectedFn.getOperationalValues(),
|
|
selectedValue: selectedFunctionData?.value,
|
|
device: device,
|
|
operationName: operationName,
|
|
selectCode: selectedFunction,
|
|
selectedFunctionData: selectedFunctionData,
|
|
);
|
|
}
|
|
|
|
// /// Build temperature selector for AC functions dialog
|
|
// static Widget _buildTemperatureSelector({
|
|
// required BuildContext context,
|
|
// required dynamic initialValue,
|
|
// required String? currentCondition,
|
|
// required String selectCode,
|
|
// AllDevicesModel? device,
|
|
// required String operationName,
|
|
// DeviceFunctionData? selectedFunctionData,
|
|
// bool? removeComparators,
|
|
// }) {
|
|
// return Column(
|
|
// mainAxisAlignment: MainAxisAlignment.center,
|
|
// children: [
|
|
// if (removeComparators != true)
|
|
// _buildConditionToggle(
|
|
// context,
|
|
// currentCondition,
|
|
// selectCode,
|
|
// device,
|
|
// operationName,
|
|
// selectedFunctionData,
|
|
// ),
|
|
// const SizedBox(height: 20),
|
|
// _buildTemperatureDisplay(
|
|
// context,
|
|
// initialValue,
|
|
// device,
|
|
// operationName,
|
|
// selectedFunctionData,
|
|
// selectCode,
|
|
// ),
|
|
// const SizedBox(height: 20),
|
|
// _buildTemperatureSlider(
|
|
// context,
|
|
// initialValue,
|
|
// device,
|
|
// operationName,
|
|
// selectedFunctionData,
|
|
// selectCode,
|
|
// ),
|
|
// ],
|
|
// );
|
|
// }
|
|
|
|
// /// Build condition toggle for AC functions dialog
|
|
// static Widget _buildConditionToggle(
|
|
// BuildContext context,
|
|
// String? currentCondition,
|
|
// String selectCode,
|
|
// AllDevicesModel? device,
|
|
// String operationName,
|
|
// DeviceFunctionData? selectedFunctionData,
|
|
|
|
// // Function(String) onConditionChanged,
|
|
// ) {
|
|
// final conditions = ["<", "==", ">"];
|
|
|
|
// return ToggleButtons(
|
|
// onPressed: (int index) {
|
|
// context.read<FunctionBloc>().add(
|
|
// AddFunction(
|
|
// functionData: DeviceFunctionData(
|
|
// entityId: device?.uuid ?? '',
|
|
// functionCode: selectCode,
|
|
// operationName: operationName,
|
|
// condition: conditions[index],
|
|
// value: selectedFunctionData?.value ?? selectCode == 'temp_set'
|
|
// ? 200
|
|
// : -100,
|
|
// valueDescription: selectedFunctionData?.valueDescription,
|
|
// ),
|
|
// ),
|
|
// );
|
|
// },
|
|
// 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(),
|
|
// );
|
|
// }
|
|
|
|
// /// Build temperature display for AC functions dialog
|
|
// static Widget _buildTemperatureDisplay(
|
|
// BuildContext context,
|
|
// dynamic initialValue,
|
|
// AllDevicesModel? device,
|
|
// String operationName,
|
|
// DeviceFunctionData? selectedFunctionData,
|
|
// String selectCode,
|
|
// ) {
|
|
// final initialVal = selectCode == 'temp_set' ? 200 : -100;
|
|
// return Container(
|
|
// padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
// decoration: BoxDecoration(
|
|
// color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
|
// borderRadius: BorderRadius.circular(10),
|
|
// ),
|
|
// child: Text(
|
|
// '${(initialValue ?? initialVal) / 10}°C',
|
|
// style: context.textTheme.headlineMedium!.copyWith(
|
|
// color: ColorsManager.primaryColorWithOpacity,
|
|
// ),
|
|
// ),
|
|
// );
|
|
// }
|
|
|
|
// static Widget _buildTemperatureSlider(
|
|
// BuildContext context,
|
|
// dynamic initialValue,
|
|
// AllDevicesModel? device,
|
|
// String operationName,
|
|
// DeviceFunctionData? selectedFunctionData,
|
|
// String selectCode,
|
|
// ) {
|
|
// return Slider(
|
|
// value: initialValue is int ? initialValue.toDouble() : 200.0,
|
|
// min: selectCode == 'temp_current' ? -100 : 200,
|
|
// max: selectCode == 'temp_current' ? 900 : 300,
|
|
// divisions: 10,
|
|
// label: '${((initialValue ?? 160) / 10).toInt()}°C',
|
|
// onChanged: (value) {
|
|
// context.read<FunctionBloc>().add(
|
|
// AddFunction(
|
|
// functionData: DeviceFunctionData(
|
|
// entityId: device?.uuid ?? '',
|
|
// functionCode: selectCode,
|
|
// operationName: operationName,
|
|
// value: value,
|
|
// condition: selectedFunctionData?.condition,
|
|
// valueDescription: selectedFunctionData?.valueDescription,
|
|
// ),
|
|
// ),
|
|
// );
|
|
// },
|
|
// );
|
|
// }
|
|
|
|
static Widget _buildOperationalValuesList({
|
|
required BuildContext context,
|
|
required List<ACOperationalValue> values,
|
|
required dynamic selectedValue,
|
|
AllDevicesModel? device,
|
|
required String operationName,
|
|
required String selectCode,
|
|
DeviceFunctionData? selectedFunctionData,
|
|
|
|
// required Function(dynamic) onValueChanged,
|
|
}) {
|
|
return ListView.builder(
|
|
shrinkWrap: false,
|
|
physics: const AlwaysScrollableScrollPhysics(),
|
|
itemCount: values.length,
|
|
itemBuilder: (context, index) {
|
|
final value = values[index];
|
|
final isSelected = selectedValue == value.value;
|
|
return ListTile(
|
|
leading: SvgPicture.asset(
|
|
value.icon,
|
|
width: 24,
|
|
height: 24,
|
|
placeholderBuilder: (BuildContext context) => Container(
|
|
width: 24,
|
|
height: 24,
|
|
color: Colors.transparent,
|
|
),
|
|
),
|
|
title: Text(
|
|
value.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: () {
|
|
if (!isSelected) {
|
|
context.read<FunctionBloc>().add(
|
|
AddFunction(
|
|
functionData: DeviceFunctionData(
|
|
entityId: device?.uuid ?? '',
|
|
functionCode: selectCode,
|
|
operationName: operationName,
|
|
value: value.value,
|
|
condition: selectedFunctionData?.condition,
|
|
valueDescription:
|
|
selectedFunctionData?.valueDescription,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
},
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|