diff --git a/client/pubspec.lock b/client/pubspec.lock index 2ef3a23aa7..a6032bd936 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: audioplayers - sha256: e653f162ddfcec1da2040ba2d8553fff1662b5c2a5c636f4c21a3b11bee497de + sha256: "5441fa0ceb8807a5ad701199806510e56afde2b4913d9d17c2f19f2902cf0ae4" url: "https://pub.dev" source: hosted - version: "6.5.0" + version: "6.5.1" audioplayers_android: dependency: transitive description: @@ -1108,10 +1108,10 @@ packages: dependency: transitive description: name: screen_brightness_android - sha256: fb5fa43cb89d0c9b8534556c427db1e97e46594ac5d66ebdcf16063b773d54ed + sha256: d34f5321abd03bc3474f4c381f53d189117eba0b039eac1916aa92cca5fd0a96 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" screen_brightness_platform_interface: dependency: transitive description: diff --git a/packages/flet/lib/src/controls/checkbox.dart b/packages/flet/lib/src/controls/checkbox.dart index 12a9420688..71082a3cc4 100644 --- a/packages/flet/lib/src/controls/checkbox.dart +++ b/packages/flet/lib/src/controls/checkbox.dart @@ -34,6 +34,12 @@ class _CheckboxControlState extends State { _focusNode.addListener(_onFocusChange); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + ListTileClicks.of(context)?.notifier.addListener(_toggleValue); + } + void _onFocusChange() { widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @@ -41,6 +47,7 @@ class _CheckboxControlState extends State { @override void dispose() { _focusNode.removeListener(_onFocusChange); + ListTileClicks.of(context)?.notifier.removeListener(_toggleValue); _focusNode.dispose(); super.dispose(); } @@ -98,11 +105,6 @@ class _CheckboxControlState extends State { ? (bool? value) => _onChange(value) : null); - // Add listener to ListTile clicks - ListTileClicks.of(context)?.notifier.addListener(() { - _toggleValue(); - }); - Widget result = checkbox; var labelStyle = diff --git a/packages/flet/lib/src/controls/cupertino_checkbox.dart b/packages/flet/lib/src/controls/cupertino_checkbox.dart index 3589ddcebd..2b56470c9e 100644 --- a/packages/flet/lib/src/controls/cupertino_checkbox.dart +++ b/packages/flet/lib/src/controls/cupertino_checkbox.dart @@ -34,6 +34,12 @@ class _CheckboxControlState extends State { _focusNode.addListener(_onFocusChange); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + ListTileClicks.of(context)?.notifier.addListener(_toggleValue); + } + void _onFocusChange() { widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @@ -41,6 +47,7 @@ class _CheckboxControlState extends State { @override void dispose() { _focusNode.removeListener(_onFocusChange); + ListTileClicks.of(context)?.notifier.removeListener(_toggleValue); _focusNode.dispose(); super.dispose(); } @@ -92,11 +99,6 @@ class _CheckboxControlState extends State { ? (bool? value) => _onChange(value) : null); - // Add listener to ListTile clicks - ListTileClicks.of(context)?.notifier.addListener(() { - _toggleValue(); - }); - Widget result = cupertinoCheckbox; var labelStyle = diff --git a/packages/flet/lib/src/controls/cupertino_radio.dart b/packages/flet/lib/src/controls/cupertino_radio.dart index 0970fb8107..20d04d19c2 100644 --- a/packages/flet/lib/src/controls/cupertino_radio.dart +++ b/packages/flet/lib/src/controls/cupertino_radio.dart @@ -33,6 +33,12 @@ class _CupertinoRadioControlState extends State _focusNode.addListener(_onFocusChange); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + ListTileClicks.of(context)?.notifier.addListener(_toggleRadio); + } + void _onFocusChange() { widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @@ -40,10 +46,19 @@ class _CupertinoRadioControlState extends State @override void dispose() { _focusNode.removeListener(_onFocusChange); + ListTileClicks.of(context)?.notifier.removeListener(_toggleRadio); _focusNode.dispose(); super.dispose(); } + void _toggleRadio() { + var radioGroup = RadioGroupProvider.of(context); + if (radioGroup != null) { + String value = widget.control.getString("value", "")!; + _onChange(radioGroup, value); + } + } + void _onChange(Control radioGroup, String? value) { radioGroup.updateProperties({"value": value}, notify: true); radioGroup.triggerEvent("change", value); @@ -62,7 +77,6 @@ class _CupertinoRadioControlState extends State debugPrint("CupertinoRadio build: ${widget.control.id}"); var radioGroup = RadioGroupProvider.of(context); - if (radioGroup == null) { return const ErrorControl( "CupertinoRadio must be enclosed within RadioGroup"); @@ -88,10 +102,6 @@ class _CupertinoRadioControlState extends State ? (String? value) => _onChange(radioGroup, value) : null); - ListTileClicks.of(context)?.notifier.addListener(() { - _onChange(radioGroup, value); - }); - Widget result = cupertinoRadio; if (label != "") { var labelWidget = widget.control.disabled diff --git a/packages/flet/lib/src/controls/cupertino_switch.dart b/packages/flet/lib/src/controls/cupertino_switch.dart index ecb065b855..01572807af 100644 --- a/packages/flet/lib/src/controls/cupertino_switch.dart +++ b/packages/flet/lib/src/controls/cupertino_switch.dart @@ -29,15 +29,21 @@ class _CupertinoSwitchControlState extends State { super.initState(); _focusNode = FocusNode(); _focusNode.addListener(_onFocusChange); + ListTileClicks.of(context)?.notifier.addListener(_toggleValue); } @override void dispose() { _focusNode.removeListener(_onFocusChange); + ListTileClicks.of(context)?.notifier.removeListener(_toggleValue); _focusNode.dispose(); super.dispose(); } + void _toggleValue() { + _onChange(!_value); + } + void _onChange(bool value) { _value = value; var props = {"value": value}; @@ -114,10 +120,6 @@ class _CupertinoSwitchControlState extends State { } : null); - ListTileClicks.of(context)?.notifier.addListener(() { - _onChange(!_value); - }); - Widget result = swtch; if (label != "") { var labelWidget = widget.control.disabled diff --git a/packages/flet/lib/src/controls/grid_view.dart b/packages/flet/lib/src/controls/grid_view.dart index 85f67791f1..481f5732a3 100644 --- a/packages/flet/lib/src/controls/grid_view.dart +++ b/packages/flet/lib/src/controls/grid_view.dart @@ -1,9 +1,9 @@ import 'package:flutter/widgets.dart'; import '../controls/control_widget.dart'; -import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/edge_insets.dart'; +import '../utils/keys.dart'; import '../utils/layout.dart'; import '../utils/misc.dart'; import '../utils/numbers.dart'; @@ -51,6 +51,7 @@ class _GridViewControlState extends State { final childAspectRatio = widget.control.getDouble("child_aspect_ratio", 1)!; final reverse = widget.control.getBool("reverse", false)!; final cacheExtent = widget.control.getDouble("cache_extent"); + final controls = widget.control.children("controls"); var clipBehavior = widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!; @@ -89,7 +90,12 @@ class _GridViewControlState extends State { shrinkWrap: shrinkWrap, padding: padding, gridDelegate: gridDelegate, - children: widget.control.buildWidgets("controls"), + children: controls + .map((item) => ControlWidget( + key: ValueKey(item.getKey("key")?.value ?? item.id), + control: item, + )) + .toList(), ) : GridView.builder( scrollDirection: horizontal ? Axis.horizontal : Axis.vertical, @@ -101,10 +107,13 @@ class _GridViewControlState extends State { shrinkWrap: shrinkWrap, padding: padding, gridDelegate: gridDelegate, - itemCount: widget.control.children("controls").length, + itemCount: controls.length, itemBuilder: (context, index) { return ControlWidget( - control: widget.control.children("controls")[index]); + key: ValueKey(controls[index].getKey("key")?.value ?? + controls[index].id), + control: controls[index], + ); }, ); diff --git a/packages/flet/lib/src/controls/list_view.dart b/packages/flet/lib/src/controls/list_view.dart index 4fed71b539..b3dabf12ae 100644 --- a/packages/flet/lib/src/controls/list_view.dart +++ b/packages/flet/lib/src/controls/list_view.dart @@ -1,13 +1,15 @@ -import 'package:flet/src/utils/layout.dart'; import 'package:flutter/material.dart'; import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/edge_insets.dart'; +import '../utils/keys.dart'; +import '../utils/layout.dart'; import '../utils/misc.dart'; import '../utils/numbers.dart'; import '../widgets/error.dart'; import 'base_controls.dart'; +import 'control_widget.dart'; import 'scroll_notification_control.dart'; import 'scrollable_control.dart'; @@ -57,7 +59,7 @@ class _ListViewControlState extends State { var prototypeItem = firstItemPrototype ? widget.control.buildWidget("prototype_item") : null; - List controls = widget.control.buildWidgets("controls"); + var controls = widget.control.children("controls"); Widget listView = LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -79,7 +81,12 @@ class _ListViewControlState extends State { semanticChildCount: semanticChildCount, itemExtent: itemExtent, prototypeItem: prototypeItem, - children: controls, + children: controls + .map((item) => ControlWidget( + key: ValueKey(item.getKey("key")?.value ?? item.id), + control: item, + )) + .toList(), ) : spacing > 0 ? ListView.separated( @@ -92,7 +99,11 @@ class _ListViewControlState extends State { padding: padding, itemCount: controls.length, itemBuilder: (context, index) { - return controls[index]; + return ControlWidget( + key: ValueKey(controls[index].getKey("key")?.value ?? + controls[index].id), + control: controls[index], + ); }, separatorBuilder: (context, index) { return horizontal @@ -118,7 +129,11 @@ class _ListViewControlState extends State { itemCount: controls.length, itemExtent: itemExtent, itemBuilder: (context, index) { - return controls[index]; + return ControlWidget( + key: ValueKey(controls[index].getKey("key")?.value ?? + controls[index].id), + control: controls[index], + ); }, prototypeItem: prototypeItem, ); diff --git a/packages/flet/lib/src/controls/radio.dart b/packages/flet/lib/src/controls/radio.dart index 3c571fa566..21d14c861a 100644 --- a/packages/flet/lib/src/controls/radio.dart +++ b/packages/flet/lib/src/controls/radio.dart @@ -32,6 +32,12 @@ class _RadioControlState extends State { _focusNode.addListener(_onFocusChange); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + ListTileClicks.of(context)?.notifier.addListener(_toggleRadio); + } + void _onFocusChange() { widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @@ -39,10 +45,19 @@ class _RadioControlState extends State { @override void dispose() { _focusNode.removeListener(_onFocusChange); + ListTileClicks.of(context)?.notifier.removeListener(_toggleRadio); _focusNode.dispose(); super.dispose(); } + void _toggleRadio() { + var radioGroup = RadioGroupProvider.of(context); + if (radioGroup != null) { + String value = widget.control.getString("value", "")!; + _onChange(radioGroup, value); + } + } + void _onChange(Control radioGroup, String? value) { radioGroup.updateProperties({"value": value}, notify: true); radioGroup.triggerEvent("change", value); @@ -95,10 +110,6 @@ class _RadioControlState extends State { ? (String? value) => _onChange(radioGroup, value) : null); - ListTileClicks.of(context)?.notifier.addListener(() { - _onChange(radioGroup, value); - }); - Widget result = radio; if (label != "") { var labelWidget = widget.control.disabled diff --git a/packages/flet/lib/src/controls/reorderable_list_view.dart b/packages/flet/lib/src/controls/reorderable_list_view.dart index 24ac158c1d..596b7fe25b 100644 --- a/packages/flet/lib/src/controls/reorderable_list_view.dart +++ b/packages/flet/lib/src/controls/reorderable_list_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/edge_insets.dart'; +import '../utils/keys.dart'; import '../utils/misc.dart'; import '../utils/mouse.dart'; import '../utils/numbers.dart'; @@ -62,14 +63,12 @@ class _ListViewControlState extends State { var anchor = widget.control.getDouble("anchor", 0.0)!; var clipBehavior = widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!; - var controls = _controls - .map((child) => ControlWidget(key: ValueKey(child.id), control: child)) - .toList(); var scrollDirection = horizontal ? Axis.horizontal : Axis.vertical; var header = widget.control.buildWidget("header"); var footer = widget.control.buildWidget("footer"); - var prototypeItem = - firstItemPrototype && controls.isNotEmpty ? controls[0] : null; + var prototypeItem = firstItemPrototype && _controls.isNotEmpty + ? ControlWidget(key: ValueKey(_controls[0].id), control: _controls[0]) + : null; var autoScrollerVelocityScalar = widget.control.getDouble("auto_scroller_velocity_scalar"); var mouseCursor = widget.control.getMouseCursor("mouse_cursor"); @@ -110,7 +109,7 @@ class _ListViewControlState extends State { scrollDirection: scrollDirection, shrinkWrap: shrinkWrap, padding: padding, - itemCount: controls.length, + itemCount: _controls.length, itemExtent: itemExtent, mouseCursor: mouseCursor, anchor: anchor, @@ -122,7 +121,11 @@ class _ListViewControlState extends State { onReorderEnd: onReorderEnd, onReorderStart: onReorderStart, itemBuilder: (context, index) { - return controls[index]; + return ControlWidget( + key: ValueKey(_controls[index].getKey("key")?.value ?? + _controls[index].id), + control: _controls[index], + ); }, ) : ReorderableListView( @@ -144,7 +147,12 @@ class _ListViewControlState extends State { onReorder: onReorder, onReorderEnd: onReorderEnd, onReorderStart: onReorderStart, - children: controls, + children: _controls + .map((item) => ControlWidget( + key: ValueKey(item.getKey("key")?.value ?? item.id), + control: item, + )) + .toList(), ); child = ScrollableControl( diff --git a/packages/flet/lib/src/controls/switch.dart b/packages/flet/lib/src/controls/switch.dart index 2e29b5eedc..42d45abdd0 100644 --- a/packages/flet/lib/src/controls/switch.dart +++ b/packages/flet/lib/src/controls/switch.dart @@ -31,15 +31,21 @@ class _SwitchControlState extends State { super.initState(); _focusNode = FocusNode(); _focusNode.addListener(_onFocusChange); + ListTileClicks.of(context)?.notifier.addListener(_toggleValue); } @override void dispose() { _focusNode.removeListener(_onFocusChange); + ListTileClicks.of(context)?.notifier.removeListener(_toggleValue); _focusNode.dispose(); super.dispose(); } + void _toggleValue() { + _onChange(!_value); + } + void _onChange(bool value) { _value = value; var props = {"value": value}; @@ -78,7 +84,7 @@ class _SwitchControlState extends State { autofocus: autofocus, padding: widget.control.getPadding("padding"), focusNode: _focusNode, - activeColor: widget.control.getColor("active_color", context), + activeThumbColor: widget.control.getColor("active_color", context), activeTrackColor: widget.control.getColor("active_track_color", context), inactiveThumbColor: @@ -105,10 +111,6 @@ class _SwitchControlState extends State { } : null); - ListTileClicks.of(context)?.notifier.addListener(() { - _onChange(!_value); - }); - Widget result = s; if (label is Control || (label is String)) {