dispose value notfiers

This commit is contained in:
ashrafzarkanisala
2024-11-22 20:07:41 +03:00
parent fb4a4d4d6c
commit a52604360f
5 changed files with 208 additions and 262 deletions

View File

@ -151,9 +151,7 @@ class OneGangSwitchHelper {
context, {selectedFn.code: functionData}); context, {selectedFn.code: functionData});
} }
: null, : null,
isConfirmEnabled: isConfirmEnabled: selectedFunctionNotifier.value != null,
selectedFunctionNotifier.value != null &&
selectedValueNotifier.value != null,
), ),
], ],
), ),
@ -162,7 +160,13 @@ class OneGangSwitchHelper {
}, },
); );
}, },
); ).then((value) {
selectedFunctionNotifier.dispose();
selectedValueNotifier.dispose();
selectedConditionNotifier.dispose();
selectedConditionsNotifier.dispose();
return value;
});
} }
static Widget _buildCountDownSelector( static Widget _buildCountDownSelector(

View File

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.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/device_functions.dart'; import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart'; import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
import 'package:syncrow_web/pages/routiens/models/gang_switches/three_gang_switch/three_gang_switch.dart'; import 'package:syncrow_web/pages/routiens/models/gang_switches/three_gang_switch/three_gang_switch.dart';
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
@ -20,20 +20,23 @@ class ThreeGangSwitchHelper {
f is ThreeGangCountdown2Function || f is ThreeGangCountdown2Function ||
f is ThreeGangCountdown3Function) f is ThreeGangCountdown3Function)
.toList(); .toList();
Map<String, dynamic> selectedValues = {};
List<DeviceFunctionData> selectedFunctions = []; final selectedFunctionNotifier = ValueNotifier<String?>(null);
String? selectedCondition = "<"; final selectedValueNotifier = ValueNotifier<dynamic>(null);
List<bool> selectedConditions = [true, false, false]; final selectedConditionNotifier = ValueNotifier<String?>('<');
final selectedConditionsNotifier =
ValueNotifier<List<bool>>([true, false, false]);
await showDialog( await showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return StatefulBuilder( return ValueListenableBuilder<String?>(
builder: (context, setState) { valueListenable: selectedFunctionNotifier,
builder: (context, selectedFunction, _) {
return AlertDialog( return AlertDialog(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
content: Container( content: Container(
width: 600, width: selectedFunction != null ? 600 : 300,
height: 450, height: 450,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@ -43,22 +46,7 @@ class ThreeGangSwitchHelper {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( const DialogHeader('3 Gangs Light Switch Condition'),
'3 Gangs Light Switch Condition',
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( Expanded(
child: Row( child: Row(
children: [ children: [
@ -71,188 +59,111 @@ class ThreeGangSwitchHelper {
), ),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final function = switchFunctions[index]; final function = switchFunctions[index];
final isSelected = return ValueListenableBuilder<String?>(
selectedValues.containsKey(function.code); valueListenable: selectedFunctionNotifier,
return ListTile( builder: (context, selectedFunction, _) {
tileColor: final isSelected =
isSelected ? Colors.grey.shade100 : null, selectedFunction == function.code;
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();
},
);
},
),
),
// Right side: Value selector
Expanded(
child: Builder(
builder: (context) {
final selectedFn = switchFunctions.firstWhere(
(f) => selectedValues.containsKey(f.code),
orElse: () => switchFunctions.first,
) as BaseSwitchFunction;
if (selectedFn is ThreeGangCountdown1Function ||
selectedFn is ThreeGangCountdown2Function ||
selectedFn is ThreeGangCountdown3Function) {
return _buildCountDownSelector(
context,
setState,
selectedValues[selectedFn.code] ?? 0,
selectedCondition,
selectedConditions,
(value) {
selectedValues[selectedFn.code] = value;
final functionData = DeviceFunctionData(
entityId: selectedFn.deviceId,
function: selectedFn.code,
operationName: selectedFn.operationName,
value: value,
condition: selectedCondition,
valueDescription: '${value} sec',
);
final existingIndex =
selectedFunctions.indexWhere((f) =>
f.function == selectedFn.code);
if (existingIndex != -1) {
selectedFunctions[existingIndex] =
functionData;
} else {
selectedFunctions.add(functionData);
}
(context as Element).markNeedsBuild();
},
(condition) {
setState(() {
selectedCondition = condition;
});
},
);
}
final values =
selectedFn.getOperationalValues();
return ListView.builder(
itemCount: values.length,
itemBuilder: (context, index) {
final value = values[index];
return ListTile( return ListTile(
tileColor: isSelected
? Colors.grey.shade100
: null,
leading: SvgPicture.asset( leading: SvgPicture.asset(
value.icon, function.icon,
width: 24, width: 24,
height: 24, height: 24,
), ),
title: Text( title: Text(
value.description, function.operationName,
style: context.textTheme.bodyMedium, style: context.textTheme.bodyMedium,
), ),
trailing: Radio<dynamic>( trailing: const Icon(
value: value.value, Icons.arrow_forward_ios,
groupValue: size: 16,
selectedValues[selectedFn.code], color: ColorsManager.textGray,
onChanged: (newValue) {
selectedValues[selectedFn.code] =
newValue;
final functionData =
DeviceFunctionData(
entityId: selectedFn.deviceId,
function: selectedFn.code,
operationName:
selectedFn.operationName,
value: newValue,
valueDescription: value.description,
);
final existingIndex =
selectedFunctions.indexWhere(
(f) =>
f.function ==
selectedFn.code);
if (existingIndex != -1) {
selectedFunctions[existingIndex] =
functionData;
} else {
selectedFunctions.add(functionData);
}
(context as Element).markNeedsBuild();
},
), ),
onTap: () {
selectedFunctionNotifier.value =
function.code;
selectedValueNotifier.value = function
is ThreeGangCountdown1Function ||
function
is ThreeGangCountdown2Function ||
function
is ThreeGangCountdown3Function
? 0
: null;
},
); );
}, },
); );
}, },
), ),
), ),
// Right side: Value selector
if (selectedFunction != null)
Expanded(
child: ValueListenableBuilder<dynamic>(
valueListenable: selectedValueNotifier,
builder: (context, selectedValue, _) {
final selectedFn = switchFunctions.firstWhere(
(f) => f.code == selectedFunction,
);
return selectedFn
is ThreeGangCountdown1Function ||
selectedFn
is ThreeGangCountdown2Function ||
selectedFn
is ThreeGangCountdown3Function
? _buildCountDownSelector(
context,
selectedValueNotifier,
selectedConditionNotifier,
selectedConditionsNotifier,
)
: _buildOperationalValuesList(
context,
selectedFn as BaseSwitchFunction,
selectedValueNotifier,
);
},
),
),
], ],
), ),
), ),
Container( DialogFooter(
height: 1, onCancel: () => Navigator.pop(context),
width: double.infinity, onConfirm: selectedFunctionNotifier.value != null &&
color: ColorsManager.greyColor, selectedValueNotifier.value != null
), ? () {
Row( final selectedFn = switchFunctions.firstWhere(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, (f) => f.code == selectedFunctionNotifier.value,
children: [ );
TextButton( final value = selectedValueNotifier.value;
onPressed: () => Navigator.pop(context), final functionData = DeviceFunctionData(
child: Text( entityId: selectedFn.deviceId,
'Cancel', function: selectedFn.code,
style: Theme.of(context) operationName: selectedFn.operationName,
.textTheme value: value,
.bodyMedium! condition: selectedConditionNotifier.value,
.copyWith(color: ColorsManager.greyColor), valueDescription: selectedFn
), is ThreeGangCountdown1Function ||
), selectedFn
TextButton( is ThreeGangCountdown2Function ||
onPressed: selectedFunctions.isNotEmpty selectedFn
? () { is ThreeGangCountdown3Function
for (final function in selectedFunctions) { ? '${value} sec'
context : ((selectedFn as BaseSwitchFunction)
.read<RoutineBloc>() .getOperationalValues()
.add(AddFunction(function)); .firstWhere((v) => v.value == value)
} .description),
Navigator.pop(context, true); );
} Navigator.pop(
: null, context, {selectedFn.code: functionData});
child: Text( }
'Confirm', : null,
style: Theme.of(context) isConfirmEnabled: selectedFunctionNotifier.value != null,
.textTheme
.bodyMedium!
.copyWith(
color: ColorsManager.primaryColorWithOpacity,
),
),
),
],
), ),
], ],
), ),
@ -261,80 +172,110 @@ class ThreeGangSwitchHelper {
}, },
); );
}, },
); ).then((value) {
selectedFunctionNotifier.dispose();
selectedValueNotifier.dispose();
selectedConditionNotifier.dispose();
selectedConditionsNotifier.dispose();
return value;
});
} }
/// Build countdown selector for switch functions dialog
static Widget _buildCountDownSelector( static Widget _buildCountDownSelector(
BuildContext context, BuildContext context,
StateSetter setState, ValueNotifier<dynamic> valueNotifier,
dynamic selectedValue, ValueNotifier<String?> conditionNotifier,
String? selectedCondition, ValueNotifier<List<bool>> conditionsNotifier,
List<bool> selectedConditions,
Function(dynamic) onValueSelected,
Function(String?) onConditionSelected,
) { ) {
return Column( return ValueListenableBuilder<dynamic>(
mainAxisAlignment: MainAxisAlignment.center, valueListenable: valueNotifier,
children: [ builder: (context, value, _) {
_buildConditionToggle( return Column(
context, mainAxisAlignment: MainAxisAlignment.center,
setState, children: [
selectedConditions, ValueListenableBuilder<List<bool>>(
onConditionSelected, valueListenable: conditionsNotifier,
), builder: (context, selectedConditions, _) {
const SizedBox(height: 20), return ToggleButtons(
Text( onPressed: (int index) {
'${selectedValue.toString()} sec', final newConditions = List<bool>.filled(3, false);
style: Theme.of(context).textTheme.headlineMedium, newConditions[index] = true;
), conditionsNotifier.value = newConditions;
const SizedBox(height: 20), conditionNotifier.value = index == 0
Slider( ? "<"
value: selectedValue.toDouble(), : index == 1
min: 0, ? "=="
max: 300, // 5 minutes in seconds : ">";
divisions: 300, },
onChanged: (value) { borderRadius: const BorderRadius.all(Radius.circular(8)),
setState(() { selectedBorderColor: ColorsManager.primaryColorWithOpacity,
onValueSelected(value.toInt()); selectedColor: Colors.white,
}); fillColor: ColorsManager.primaryColorWithOpacity,
}, color: ColorsManager.primaryColorWithOpacity,
), constraints: const BoxConstraints(
], minHeight: 40.0,
minWidth: 40.0,
),
isSelected: selectedConditions,
children: const [Text("<"), Text("="), Text(">")],
);
},
),
const SizedBox(height: 20),
Text(
'${value ?? 0} sec',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 20),
Slider(
value: (value ?? 0).toDouble(),
min: 0,
max: 300,
divisions: 300,
onChanged: (newValue) {
valueNotifier.value = newValue.toInt();
},
),
],
);
},
); );
} }
/// Build condition toggle for AC functions dialog static Widget _buildOperationalValuesList(
static Widget _buildConditionToggle(
BuildContext context, BuildContext context,
StateSetter setState, BaseSwitchFunction function,
List<bool> selectedConditions, ValueNotifier<dynamic> valueNotifier,
Function(String?) onConditionSelected,
) { ) {
return ToggleButtons( final values = function.getOperationalValues();
onPressed: (int index) { return ValueListenableBuilder<dynamic>(
setState(() { valueListenable: valueNotifier,
for (int i = 0; i < selectedConditions.length; i++) { builder: (context, selectedValue, _) {
selectedConditions[i] = i == index; return ListView.builder(
} itemCount: values.length,
onConditionSelected(index == 0 itemBuilder: (context, index) {
? "<" final value = values[index];
: index == 1 return ListTile(
? "==" leading: SvgPicture.asset(
: ">"); value.icon,
}); width: 24,
height: 24,
),
title: Text(
value.description,
style: context.textTheme.bodyMedium,
),
trailing: Radio<dynamic>(
value: value.value,
groupValue: selectedValue,
onChanged: (newValue) {
valueNotifier.value = newValue;
},
),
);
},
);
}, },
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: selectedConditions,
children: const [Text("<"), Text("="), Text(">")],
); );
} }
} }

View File

@ -1,7 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.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/device_functions.dart'; import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart'; import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
import 'package:syncrow_web/pages/routiens/models/gang_switches/two_gang_switch/two_gang_switch.dart'; import 'package:syncrow_web/pages/routiens/models/gang_switches/two_gang_switch/two_gang_switch.dart';
@ -166,7 +164,13 @@ class TwoGangSwitchHelper {
}, },
); );
}, },
); ).then((value) {
selectedFunctionNotifier.dispose();
selectedValueNotifier.dispose();
selectedConditionNotifier.dispose();
selectedConditionsNotifier.dispose();
return value;
});
} }
static Widget _buildOperationalValuesList( static Widget _buildOperationalValuesList(

View File

@ -1,6 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routiens/widgets/conditions_routines_devices_view.dart'; import 'package:syncrow_web/pages/routiens/widgets/conditions_routines_devices_view.dart';
import 'package:syncrow_web/pages/routiens/widgets/if_container.dart'; import 'package:syncrow_web/pages/routiens/widgets/if_container.dart';
import 'package:syncrow_web/pages/routiens/widgets/routine_search_and_buttons.dart'; import 'package:syncrow_web/pages/routiens/widgets/routine_search_and_buttons.dart';

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart'; import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';