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,11 +59,15 @@ class ThreeGangSwitchHelper {
), ),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final function = switchFunctions[index]; final function = switchFunctions[index];
return ValueListenableBuilder<String?>(
valueListenable: selectedFunctionNotifier,
builder: (context, selectedFunction, _) {
final isSelected = final isSelected =
selectedValues.containsKey(function.code); selectedFunction == function.code;
return ListTile( return ListTile(
tileColor: tileColor: isSelected
isSelected ? Colors.grey.shade100 : null, ? Colors.grey.shade100
: null,
leading: SvgPicture.asset( leading: SvgPicture.asset(
function.icon, function.icon,
width: 24, width: 24,
@ -85,80 +77,180 @@ class ThreeGangSwitchHelper {
function.operationName, function.operationName,
style: context.textTheme.bodyMedium, style: context.textTheme.bodyMedium,
), ),
trailing: isSelected trailing: const Icon(
? Icon(
Icons.check_circle,
color: ColorsManager
.primaryColorWithOpacity,
size: 20,
)
: const Icon(
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
size: 16, size: 16,
color: ColorsManager.textGray, color: ColorsManager.textGray,
), ),
onTap: () { onTap: () {
if (isSelected) { selectedFunctionNotifier.value =
selectedValues.remove(function.code); function.code;
selectedFunctions.removeWhere( selectedValueNotifier.value = function
(f) => f.function == function.code); is ThreeGangCountdown1Function ||
} function
(context as Element).markNeedsBuild(); is ThreeGangCountdown2Function ||
function
is ThreeGangCountdown3Function
? 0
: null;
},
);
}, },
); );
}, },
), ),
), ),
// Right side: Value selector // Right side: Value selector
if (selectedFunction != null)
Expanded( Expanded(
child: Builder( child: ValueListenableBuilder<dynamic>(
builder: (context) { valueListenable: selectedValueNotifier,
builder: (context, selectedValue, _) {
final selectedFn = switchFunctions.firstWhere( final selectedFn = switchFunctions.firstWhere(
(f) => selectedValues.containsKey(f.code), (f) => f.code == selectedFunction,
orElse: () => switchFunctions.first, );
) as BaseSwitchFunction; return selectedFn
is ThreeGangCountdown1Function ||
if (selectedFn is ThreeGangCountdown1Function || selectedFn
selectedFn is ThreeGangCountdown2Function || is ThreeGangCountdown2Function ||
selectedFn is ThreeGangCountdown3Function) { selectedFn
return _buildCountDownSelector( is ThreeGangCountdown3Function
? _buildCountDownSelector(
context, context,
setState, selectedValueNotifier,
selectedValues[selectedFn.code] ?? 0, selectedConditionNotifier,
selectedCondition, selectedConditionsNotifier,
selectedConditions, )
(value) { : _buildOperationalValuesList(
selectedValues[selectedFn.code] = value; context,
selectedFn as BaseSwitchFunction,
selectedValueNotifier,
);
},
),
),
],
),
),
DialogFooter(
onCancel: () => Navigator.pop(context),
onConfirm: selectedFunctionNotifier.value != null &&
selectedValueNotifier.value != null
? () {
final selectedFn = switchFunctions.firstWhere(
(f) => f.code == selectedFunctionNotifier.value,
);
final value = selectedValueNotifier.value;
final functionData = DeviceFunctionData( final functionData = DeviceFunctionData(
entityId: selectedFn.deviceId, entityId: selectedFn.deviceId,
function: selectedFn.code, function: selectedFn.code,
operationName: selectedFn.operationName, operationName: selectedFn.operationName,
value: value, value: value,
condition: selectedCondition, condition: selectedConditionNotifier.value,
valueDescription: '${value} sec', valueDescription: selectedFn
is ThreeGangCountdown1Function ||
selectedFn
is ThreeGangCountdown2Function ||
selectedFn
is ThreeGangCountdown3Function
? '${value} sec'
: ((selectedFn as BaseSwitchFunction)
.getOperationalValues()
.firstWhere((v) => v.value == value)
.description),
); );
Navigator.pop(
final existingIndex = context, {selectedFn.code: functionData});
selectedFunctions.indexWhere((f) =>
f.function == selectedFn.code);
if (existingIndex != -1) {
selectedFunctions[existingIndex] =
functionData;
} else {
selectedFunctions.add(functionData);
} }
(context as Element).markNeedsBuild(); : null,
isConfirmEnabled: selectedFunctionNotifier.value != null,
),
],
),
),
);
}, },
(condition) { );
setState(() { },
selectedCondition = condition; ).then((value) {
selectedFunctionNotifier.dispose();
selectedValueNotifier.dispose();
selectedConditionNotifier.dispose();
selectedConditionsNotifier.dispose();
return value;
}); });
}
static Widget _buildCountDownSelector(
BuildContext context,
ValueNotifier<dynamic> valueNotifier,
ValueNotifier<String?> conditionNotifier,
ValueNotifier<List<bool>> conditionsNotifier,
) {
return ValueListenableBuilder<dynamic>(
valueListenable: valueNotifier,
builder: (context, value, _) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ValueListenableBuilder<List<bool>>(
valueListenable: conditionsNotifier,
builder: (context, selectedConditions, _) {
return ToggleButtons(
onPressed: (int index) {
final newConditions = List<bool>.filled(3, false);
newConditions[index] = true;
conditionsNotifier.value = newConditions;
conditionNotifier.value = index == 0
? "<"
: index == 1
? "=="
: ">";
},
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(">")],
);
},
),
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();
},
),
],
);
}, },
); );
} }
final values = static Widget _buildOperationalValuesList(
selectedFn.getOperationalValues(); BuildContext context,
BaseSwitchFunction function,
ValueNotifier<dynamic> valueNotifier,
) {
final values = function.getOperationalValues();
return ValueListenableBuilder<dynamic>(
valueListenable: valueNotifier,
builder: (context, selectedValue, _) {
return ListView.builder( return ListView.builder(
itemCount: values.length, itemCount: values.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
@ -175,166 +267,15 @@ class ThreeGangSwitchHelper {
), ),
trailing: Radio<dynamic>( trailing: Radio<dynamic>(
value: value.value, value: value.value,
groupValue: groupValue: selectedValue,
selectedValues[selectedFn.code],
onChanged: (newValue) { onChanged: (newValue) {
selectedValues[selectedFn.code] = valueNotifier.value = newValue;
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();
}, },
), ),
); );
}, },
); );
}, },
),
),
],
),
),
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
? () {
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,
),
),
),
],
),
],
),
),
);
},
);
},
);
}
/// Build countdown selector for switch functions dialog
static Widget _buildCountDownSelector(
BuildContext context,
StateSetter setState,
dynamic selectedValue,
String? selectedCondition,
List<bool> selectedConditions,
Function(dynamic) onValueSelected,
Function(String?) onConditionSelected,
) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildConditionToggle(
context,
setState,
selectedConditions,
onConditionSelected,
),
const SizedBox(height: 20),
Text(
'${selectedValue.toString()} sec',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 20),
Slider(
value: selectedValue.toDouble(),
min: 0,
max: 300, // 5 minutes in seconds
divisions: 300,
onChanged: (value) {
setState(() {
onValueSelected(value.toInt());
});
},
),
],
);
}
/// Build condition toggle for AC functions dialog
static Widget _buildConditionToggle(
BuildContext context,
StateSetter setState,
List<bool> selectedConditions,
Function(String?) onConditionSelected,
) {
return ToggleButtons(
onPressed: (int index) {
setState(() {
for (int i = 0; i < selectedConditions.length; i++) {
selectedConditions[i] = i == index;
}
onConditionSelected(index == 0
? "<"
: index == 1
? "=="
: ">");
});
},
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';