Skip to content

Commit 7a5c9af

Browse files
ndonkoHenriCopilotFeodorFitsner
authored
fix(ResponsiveRow): handle unbounded width and child controls with col=0 (#6354)
* add error handling for unbounded width in ResponsiveRow * add test for unbounded width error in ResponsiveRow * add tests for unbounded height in various components * improve logging.md * revert `NavigationRailDestination.icon` type change Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix #3805: treat ResponsiveRow child controls with `col=0` as hidden * docs: clarify behavior of `col=0` in ResponsiveRow * fix: add validation rules for ResponsiveRow columns to ensure positive values * fix #5209: clarify possible container expansion due to alignment being set * Update changelogs with ResponsiveRow fixes Add entries to top-level and packages/flet CHANGELOGs documenting fixes: explicit error for unbounded width in ResponsiveRow, treating child controls with col=0 as hidden at the current breakpoint, and clarifying Container expansion behavior when alignment is set. References issues/PRs #1951, #3805, #5209, #6354 and author @ndonkoHenri. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Feodor Fitsner <feodor@appveyor.com>
1 parent 4fd3098 commit 7a5c9af

20 files changed

Lines changed: 283 additions & 15 deletions

File tree

.agents/skills/flet-validation/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ When a property has validation, document it in that property’s docstring (goog
141141
`sdk/python/packages/flet/src/flet/utils/validation.py`.
142142
- Each `V.*` helper includes `Property docstring Raises wording`.
143143
- Keep property `Raises` entries as negations of the annotation rule.
144+
- For strict inequalities, say `"strictly"`.
145+
For example: `V.gt(x)` -> `ValueError: If it is not strictly greater than \`x\`.`
144146
- For sign-neutral divisibility helpers (`factor_of`, `multiple_of`), add
145147
explicit sign rules (`V.gt(0)` or `V.lt(0)`) when direction matters, and
146148
include separate `Raises` entries for those sign rules.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
### Bug fixes
1212

1313
* Fix `flet build` and `flet publish` dependency parsing for `project.dependencies` and Poetry constraints with `<`/`<=`, and add coverage for normalized requirement handling ([#6332](https://github.com/flet-dev/flet/issues/6332), [#6340](https://github.com/flet-dev/flet/pull/6340)) by @td3447.
14+
* Handle unbounded width in `ResponsiveRow` with an explicit error, treat child controls with `col=0` as hidden, and clarify `Container` expansion behavior when `alignment` is set ([#1951](https://github.com/flet-dev/flet/issues/1951), [#3805](https://github.com/flet-dev/flet/issues/3805), [#5209](https://github.com/flet-dev/flet/issues/5209), [#6354](https://github.com/flet-dev/flet/pull/6354)) by @ndonkoHenri.
1415
* Fix `find_platform_image` selecting incompatible icon formats (e.g. `.icns` on Windows) by ranking glob results per target platform ([#6381](https://github.com/flet-dev/flet/pull/6381)) by @HG-ha.
1516

1617
### Other changes

packages/flet/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
### Bug fixes
88

9+
* Handle unbounded width in `ResponsiveRow` with an explicit error and treat child controls with `col=0` as hidden at the current breakpoint ([#1951](https://github.com/flet-dev/flet/issues/1951), [#3805](https://github.com/flet-dev/flet/issues/3805), [#6354](https://github.com/flet-dev/flet/pull/6354)) by @ndonkoHenri.
10+
911
### Other changes
1012

1113
## 0.84.0

packages/flet/lib/src/controls/responsive_row.dart

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,17 @@ class ResponsiveRowControl extends StatelessWidget with FletStoreMixin {
2525
return withPageSize((context, view) {
2626
var result = LayoutBuilder(
2727
builder: (BuildContext context, BoxConstraints constraints) {
28-
// breakpoints
28+
if (!constraints.hasBoundedWidth) {
29+
return const ErrorControl(
30+
"Error displaying ResponsiveRow: width is unbounded.",
31+
description:
32+
"Set a fixed width, a non-zero expand, or place it inside a control with bounded width.",
33+
);
34+
}
35+
36+
// Resolve the active breakpoint map once per layout pass. Responsive
37+
// properties such as `columns`, `spacing`, and child `col` values are
38+
// all interpreted against this map.
2939
final rawBreakpoints =
3040
control.get<Map>("breakpoints", view.breakpoints)!;
3141
final breakpoints = <String, double>{};
@@ -45,13 +55,28 @@ class ResponsiveRowControl extends StatelessWidget with FletStoreMixin {
4555
for (var ctrl in control.children("controls")) {
4656
final col = ctrl.getResponsiveNumber("col", 12)!;
4757
var bpCol = getBreakpointNumber(col, view.size.width, breakpoints);
58+
59+
// `col=0` means "do not occupy any columns" for the current
60+
// breakpoint, so the child should not participate in layout.
61+
if (bpCol <= 0) {
62+
continue;
63+
}
64+
4865
totalCols += bpCol;
4966

50-
// calculate child width
67+
// Convert virtual columns into a fixed pixel width for this child.
68+
// We first remove the total horizontal gaps from the available width,
69+
// then divide the remaining width across the configured columns.
5170
var colWidth =
5271
(constraints.maxWidth - bpSpacing * (bpColumns - 1)) / bpColumns;
5372
var childWidth = colWidth * bpCol + bpSpacing * (bpCol - 1);
5473

74+
// Guard against tiny/invalid available widths so Flutter never sees
75+
// negative box constraints.
76+
if (childWidth < 0) {
77+
childWidth = 0;
78+
}
79+
5580
controls.add(ConstrainedBox(
5681
constraints:
5782
BoxConstraints(minWidth: childWidth, maxWidth: childWidth),
@@ -62,6 +87,8 @@ class ResponsiveRowControl extends StatelessWidget with FletStoreMixin {
6287
var wrap = (totalCols > bpColumns);
6388

6489
try {
90+
// Keep a single row when everything fits; otherwise switch to Wrap so
91+
// children can continue on the next line.
6592
return wrap
6693
? Wrap(
6794
direction: Axis.horizontal,
19.5 KB
Loading
19.6 KB
Loading
20.5 KB
Loading
Loading

sdk/python/packages/flet/integration_tests/controls/core/test_page_view.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
import pytest
2+
import pytest_asyncio
23

34
import flet as ft
45
import flet.testing as ftt
56

67

7-
@pytest.mark.asyncio(loop_scope="module")
8+
# Create a new flet_app instance for each test method
9+
@pytest_asyncio.fixture(scope="function", autouse=True)
10+
def flet_app(flet_app_function):
11+
return flet_app_function
12+
13+
14+
@pytest.mark.asyncio(loop_scope="function")
815
async def test_basic(flet_app: ftt.FletTestApp, request):
916
await flet_app.assert_control_screenshot(
1017
request.node.name,
@@ -30,3 +37,29 @@ async def test_basic(flet_app: ftt.FletTestApp, request):
3037
],
3138
),
3239
)
40+
41+
42+
@pytest.mark.asyncio(loop_scope="function")
43+
async def test_unbounded_height(flet_app: ftt.FletTestApp, request):
44+
flet_app.page.theme_mode = ft.ThemeMode.LIGHT
45+
await flet_app.assert_control_screenshot(
46+
request.node.name,
47+
ft.Column(
48+
controls=[
49+
ft.PageView(
50+
controls=[
51+
ft.Container(
52+
bgcolor=ft.Colors.PURPLE,
53+
alignment=ft.Alignment.CENTER,
54+
content=ft.Text("One", color=ft.Colors.WHITE),
55+
),
56+
ft.Container(
57+
bgcolor=ft.Colors.TEAL,
58+
alignment=ft.Alignment.CENTER,
59+
content=ft.Text("Two", color=ft.Colors.WHITE),
60+
),
61+
],
62+
)
63+
]
64+
),
65+
)

sdk/python/packages/flet/integration_tests/controls/core/test_pagelet.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,19 @@ async def test_cupertino_adaptive(flet_app: ftt.FletTestApp, request):
111111
),
112112
),
113113
)
114+
115+
116+
@pytest.mark.asyncio(loop_scope="function")
117+
async def test_unbounded_height(flet_app: ftt.FletTestApp, request):
118+
flet_app.page.theme_mode = ft.ThemeMode.LIGHT
119+
await flet_app.assert_control_screenshot(
120+
request.node.name,
121+
ft.Column(
122+
controls=[
123+
ft.Pagelet(
124+
appbar=ft.AppBar(title="Pagelet AppBar"),
125+
content=ft.Text("Pagelet Content"),
126+
)
127+
]
128+
),
129+
)

0 commit comments

Comments
 (0)