mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
220 lines
8.9 KiB
Dart
220 lines
8.9 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/routiens/bloc/routine_bloc.dart';
|
|
import 'package:syncrow_web/pages/routiens/models/ac/ac_function.dart';
|
|
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
|
import 'package:syncrow_web/utils/color_manager.dart';
|
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
|
|
class ACHelper {
|
|
static Future<void> showACFunctionsDialog(
|
|
BuildContext context,
|
|
List<DeviceFunction<dynamic>> functions,
|
|
) async {
|
|
List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
|
|
// Track multiple selections using a map
|
|
Map<String, dynamic> selectedValues = {};
|
|
List<DeviceFunctionData> selectedFunctions = [];
|
|
|
|
await showDialog(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return Dialog(
|
|
child: Container(
|
|
width: 600,
|
|
height: 450,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
padding: const EdgeInsets.only(top: 20),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
'AC Functions',
|
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
color: ColorsManager.primaryColorWithOpacity,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
Padding(
|
|
padding:
|
|
const EdgeInsets.symmetric(vertical: 15, horizontal: 50),
|
|
child: Container(
|
|
height: 1,
|
|
width: double.infinity,
|
|
color: ColorsManager.greyColor,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: ListView.separated(
|
|
itemCount: acFunctions.length,
|
|
separatorBuilder: (_, __) => const Divider(
|
|
color: ColorsManager.dividerColor,
|
|
),
|
|
itemBuilder: (context, index) {
|
|
final function = acFunctions[index];
|
|
final isSelected =
|
|
selectedValues.containsKey(function.code);
|
|
return ListTile(
|
|
tileColor:
|
|
isSelected ? Colors.grey.shade100 : null,
|
|
leading: SvgPicture.asset(
|
|
function.icon,
|
|
width: 24,
|
|
height: 24,
|
|
),
|
|
title: Text(
|
|
function.operationName,
|
|
style: context.textTheme.bodyMedium,
|
|
),
|
|
trailing: isSelected
|
|
? Icon(
|
|
Icons.check_circle,
|
|
color:
|
|
ColorsManager.primaryColorWithOpacity,
|
|
size: 20,
|
|
)
|
|
: const Icon(
|
|
Icons.arrow_forward_ios,
|
|
size: 16,
|
|
color: ColorsManager.textGray,
|
|
),
|
|
onTap: () {
|
|
if (isSelected) {
|
|
selectedValues.remove(function.code);
|
|
selectedFunctions.removeWhere(
|
|
(f) => f.function == function.code);
|
|
}
|
|
(context as Element).markNeedsBuild();
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Builder(
|
|
builder: (context) {
|
|
final selectedFunction = acFunctions.firstWhere(
|
|
(f) => selectedValues.containsKey(f.code),
|
|
orElse: () => acFunctions.first,
|
|
);
|
|
return _buildValueSelector(
|
|
context,
|
|
selectedFunction,
|
|
selectedValues[selectedFunction.code],
|
|
(value) {
|
|
selectedValues[selectedFunction.code] = value;
|
|
// Update or add the function data
|
|
final functionData = DeviceFunctionData(
|
|
entityId: selectedFunction.deviceId,
|
|
function: selectedFunction.code,
|
|
operationName: selectedFunction.operationName,
|
|
value: value,
|
|
valueDescription: _getValueDescription(
|
|
selectedFunction, value),
|
|
);
|
|
|
|
final existingIndex =
|
|
selectedFunctions.indexWhere((f) =>
|
|
f.function == selectedFunction.code);
|
|
if (existingIndex != -1) {
|
|
selectedFunctions[existingIndex] =
|
|
functionData;
|
|
} else {
|
|
selectedFunctions.add(functionData);
|
|
}
|
|
|
|
(context as Element).markNeedsBuild();
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Container(
|
|
height: 1,
|
|
width: double.infinity,
|
|
color: ColorsManager.greyColor,
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
child: Text(
|
|
'Cancel',
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.bodyMedium!
|
|
.copyWith(color: ColorsManager.greyColor),
|
|
),
|
|
),
|
|
TextButton(
|
|
onPressed: selectedFunctions.isNotEmpty
|
|
? () {
|
|
// Add all selected functions to the bloc
|
|
for (final function in selectedFunctions) {
|
|
context
|
|
.read<RoutineBloc>()
|
|
.add(AddFunction(function));
|
|
}
|
|
Navigator.pop(context, true);
|
|
}
|
|
: null,
|
|
child: Text(
|
|
'Confirm',
|
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
color: ColorsManager.primaryColorWithOpacity,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
static Widget _buildValueSelector(
|
|
BuildContext context,
|
|
ACFunction function,
|
|
dynamic selectedValue,
|
|
Function(dynamic) onValueSelected,
|
|
) {
|
|
final values = function.getOperationalValues();
|
|
return Container(
|
|
height: 200,
|
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
child: ListView.builder(
|
|
itemCount: values.length,
|
|
itemBuilder: (context, index) {
|
|
final value = values[index];
|
|
return RadioListTile<dynamic>(
|
|
value: value.value,
|
|
groupValue: selectedValue,
|
|
onChanged: onValueSelected,
|
|
title: Text(value.description),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
static String _getValueDescription(ACFunction function, dynamic value) {
|
|
final values = function.getOperationalValues();
|
|
final selectedValue = values.firstWhere((v) => v.value == value);
|
|
return selectedValue.description;
|
|
}
|
|
}
|