From 0e735866ad33bcf0ffae2ae81a1431143d73cd4c Mon Sep 17 00:00:00 2001 From: TheEthicalBoy <98978078+ndonkoHenri@users.noreply.github.com> Date: Thu, 12 Dec 2024 23:35:23 +0100 Subject: [PATCH] fix:`ControlState` should be resolved based on user-defined order (#4556) * ControlState: rename "" to "default" * resolve ControlState on user-defined order * fix failing tests * remove breaking line --- .../flet/lib/src/utils/material_state.dart | 42 +++++++++---------- .../flet/src/flet/core/popup_menu_button.py | 1 - .../packages/flet/src/flet/core/types.py | 2 +- .../packages/flet/tests/test_datatable.py | 15 ++++--- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/packages/flet/lib/src/utils/material_state.dart b/packages/flet/lib/src/utils/material_state.dart index c6c19dbc4..564a9ebf9 100644 --- a/packages/flet/lib/src/utils/material_state.dart +++ b/packages/flet/lib/src/utils/material_state.dart @@ -1,3 +1,4 @@ +import 'dart:collection'; import 'package:flutter/material.dart'; WidgetStateProperty? getWidgetStateProperty( @@ -8,43 +9,42 @@ WidgetStateProperty? getWidgetStateProperty( } var j = jsonDictValue; if (j is! Map) { - j = {"": j}; + j = {"default": j}; } return WidgetStateFromJSON(j, converterFromJson, defaultValue); } class WidgetStateFromJSON extends WidgetStateProperty { - late final Map _states; + late final LinkedHashMap _states; late final T? _defaultValue; WidgetStateFromJSON(Map? jsonDictValue, T Function(dynamic) converterFromJson, T? defaultValue) { _defaultValue = defaultValue; - _states = {}; - if (jsonDictValue != null) { - jsonDictValue.forEach((stateStr, jv) { - stateStr.split(",").map((s) => s.trim().toLowerCase()).forEach((state) { - _states[state] = converterFromJson(jv); - }); - }); - } + + // preserve user-defined order + _states = LinkedHashMap.from( + jsonDictValue?.map((key, value) { + var normalizedKey = key.trim().toLowerCase(); + // "" is now deprecated; use "default" instead + if (normalizedKey == "") normalizedKey = "default"; + return MapEntry(normalizedKey, converterFromJson(value)); + }) ?? + {}, + ); } @override T? resolve(Set states) { - //debugPrint("WidgetStateFromJSON states: $states, _states: $_states"); - // find specific state - for (var state in states) { - if (_states.containsKey(state.name)) { - return _states[state.name]!; + // Resolve using user-defined order in _states + for (var stateName in _states.keys) { + if (stateName == "default") continue; // Skip "default"; handled last + if (states.any((state) => state.name == stateName)) { + return _states[stateName]; } } - // catch-all value - if (_states.containsKey("")) { - return _states[""]; - } - - return _defaultValue; + // Default state + return _states["default"] ?? _defaultValue; } } diff --git a/sdk/python/packages/flet/src/flet/core/popup_menu_button.py b/sdk/python/packages/flet/src/flet/core/popup_menu_button.py index 57a2e157e..9c7049e0a 100644 --- a/sdk/python/packages/flet/src/flet/core/popup_menu_button.py +++ b/sdk/python/packages/flet/src/flet/core/popup_menu_button.py @@ -285,7 +285,6 @@ def __init__( self.items = items self.icon = icon self.on_cancel = on_cancel - self.on_cancelled = on_cancelled self.on_open = on_open self.shape = shape self.padding = padding diff --git a/sdk/python/packages/flet/src/flet/core/types.py b/sdk/python/packages/flet/src/flet/core/types.py index 814476c29..ba1b0b9bf 100644 --- a/sdk/python/packages/flet/src/flet/core/types.py +++ b/sdk/python/packages/flet/src/flet/core/types.py @@ -136,7 +136,7 @@ class ControlState(Enum): SCROLLED_UNDER = "scrolledUnder" DISABLED = "disabled" ERROR = "error" - DEFAULT = "" + DEFAULT = "default" class MainAxisAlignment(Enum): diff --git a/sdk/python/packages/flet/tests/test_datatable.py b/sdk/python/packages/flet/tests/test_datatable.py index fd15969d6..1b0864576 100644 --- a/sdk/python/packages/flet/tests/test_datatable.py +++ b/sdk/python/packages/flet/tests/test_datatable.py @@ -1,6 +1,7 @@ -import flet as ft from flet.core.protocol import Command +import flet as ft + def test_datatable_instance_no_attrs_set(): r = ft.DataTable(columns=[ft.DataColumn(label=ft.Text("Header"))]) @@ -38,7 +39,7 @@ def test_datarow_color_literal_material_state_as_string(): indent=0, name=None, values=["datarow"], - attrs={"color": '{"":"yellow"}'}, + attrs={"color": '{"default":"yellow"}'}, commands=[], ), Command(indent=2, name=None, values=["datacell"], attrs={}, commands=[]), @@ -51,7 +52,11 @@ def test_datarow_color_literal_material_state_as_string(): def test_datarow_color_multiple_material_states_as_strings(): r = ft.DataRow( cells=[ft.DataCell(content=ft.Text("Cell"))], - color={"selected": "red", "hovered": "blue", "": "yellow"}, + color={ + ft.ControlState.SELECTED: "red", + ft.ControlState.HOVERED: "blue", + ft.ControlState.DEFAULT: "yellow", + }, ) assert isinstance(r, ft.Control) assert r._build_add_commands() == [ @@ -59,7 +64,7 @@ def test_datarow_color_multiple_material_states_as_strings(): indent=0, name=None, values=["datarow"], - attrs={"color": '{"selected":"red","hovered":"blue","":"yellow"}'}, + attrs={"color": '{"selected":"red","hovered":"blue","default":"yellow"}'}, commands=[], ), Command(indent=2, name=None, values=["datacell"], attrs={}, commands=[]), @@ -84,7 +89,7 @@ def test_datarow_color_multiple_material_states(): indent=0, name=None, values=["datarow"], - attrs={"color": '{"selected":"red","hovered":"blue","":"yellow"}'}, + attrs={"color": '{"selected":"red","hovered":"blue","default":"yellow"}'}, commands=[], ), Command(indent=2, name=None, values=["datacell"], attrs={}, commands=[]),