Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* Add `ft.use_dialog()` hook for declarative dialog management from within `@ft.component` functions, with frozen-diff reactive updates and automatic open/close lifecycle ([#6335](https://github.com/flet-dev/flet/pull/6335)) by @FeodorFitsner.
* Add `scrollable`, `pin_leading_to_top`, and `pin_trailing_to_bottom` properties to `NavigationRail` for scrollable content with optional pinned leading/trailing controls ([#1923](https://github.com/flet-dev/flet/issues/1923), [#6356](https://github.com/flet-dev/flet/pull/6356)) by @ndonkoHenri.
* Add `Page.pop_views_until()` to pop multiple views and return a result to the destination view ([#6326](https://github.com/flet-dev/flet/issues/6326), [#6347](https://github.com/flet-dev/flet/pull/6347)) by [@brunobrown](https://github.com/brunobrown).

### Improvements

Expand Down
18 changes: 9 additions & 9 deletions client/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.0"
charcode:
dependency: transitive
description:
Expand Down Expand Up @@ -359,7 +359,7 @@ packages:
path: "../packages/flet"
relative: true
source: path
version: "0.85.0"
version: "0.82.2"
flet_ads:
dependency: "direct main"
description:
Expand Down Expand Up @@ -911,18 +911,18 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.19"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.13.0"
version: "0.11.1"
media_kit:
dependency: transitive
description:
Expand Down Expand Up @@ -1628,10 +1628,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.7"
torch_light:
dependency: transitive
description:
Expand Down
112 changes: 112 additions & 0 deletions sdk/python/examples/apps/routing_navigation/pop_views_until/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import asyncio

import flet as ft


def main(page: ft.Page):
page.title = "Routes Example"

result_text = ft.Text("No result yet", size=18)

def route_change():
page.views.clear()

# Home View (/)
page.views.append(
ft.View(
route="/",
controls=[
ft.AppBar(title=ft.Text("Home"), bgcolor=ft.Colors.SURFACE_BRIGHT),
result_text,
ft.Button(
"Start flow",
on_click=lambda _: asyncio.create_task(
page.push_route("/step1")
),
),
],
)
)

if page.route == "/step1" or page.route == "/step2" or page.route == "/step3":
page.views.append(
ft.View(
route="/step1",
controls=[
ft.AppBar(
title=ft.Text("Step 1"),
bgcolor=ft.Colors.SURFACE_BRIGHT,
),
ft.Text("Step 1 of the flow"),
ft.Button(
"Go to Step 2",
on_click=lambda _: asyncio.create_task(
page.push_route("/step2")
),
),
],
)
)

if page.route == "/step2" or page.route == "/step3":
page.views.append(
ft.View(
route="/step2",
controls=[
ft.AppBar(
title=ft.Text("Step 2"),
bgcolor=ft.Colors.SURFACE_BRIGHT,
),
ft.Text("Step 2 of the flow"),
ft.Button(
"Go to Step 3",
on_click=lambda _: asyncio.create_task(
page.push_route("/step3")
),
),
],
)
)

if page.route == "/step3":
page.views.append(
ft.View(
route="/step3",
controls=[
ft.AppBar(
title=ft.Text("Step 3 (Final)"),
bgcolor=ft.Colors.SURFACE_BRIGHT,
),
ft.Text("Flow complete!"),
ft.Button(
"Finish and go Home",
on_click=lambda _: asyncio.create_task(
page.pop_views_until("/", result="Flow completed!")
),
),
],
)
)

page.update()

def on_pop_result(e: ft.ViewsPopUntilEvent):
result_text.value = f"Result: {e.result}"
page.show_dialog(ft.SnackBar(ft.Text(f"Got result: {e.result}")))
page.update()

async def view_pop(e: ft.ViewPopEvent):
if e.view is not None:
page.views.remove(e.view)
top_view = page.views[-1]
await page.push_route(top_view.route)

page.on_route_change = route_change
page.on_view_pop = view_pop
page.on_views_pop_until = on_pop_result

route_change()


if __name__ == "__main__":
ft.run(main)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[project]
name = "apps-routing-navigation-pop-views-until"
version = "1.0.0"
description = "Pops multiple views from the navigation stack and returns a result to the destination view."
requires-python = ">=3.10"
keywords = ["apps", "routing", "navigation", "pop", "views", "result", "async"]
authors = [{ name = "Flet team", email = "hello@flet.dev" }]
dependencies = ["flet"]

[dependency-groups]
dev = ["flet-cli", "flet-desktop", "flet-web"]

[tool.flet.gallery]
categories = ["Apps/Navigation"]

[tool.flet.metadata]
title = "Pop views until"
controls = ["View", "AppBar", "Button", "Text", "SnackBar"]
layout_pattern = "multi-step-flow"
complexity = "intermediate"
features = ["routing", "view stack", "pop views until", "result passing", "async"]

[tool.flet]
org = "dev.flet"
company = "Flet"
copyright = "Copyright (C) 2023-2026 by Flet"
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from examples.apps.routing_navigation.home_store import main as home_store
from examples.apps.routing_navigation.initial_route import main as initial_route
from examples.apps.routing_navigation.pop_view_confirm import main as pop_view_confirm
from examples.apps.routing_navigation.pop_views_until import main as pop_views_until
from examples.apps.routing_navigation.route_change_event import (
main as route_change_event,
)
Expand Down Expand Up @@ -185,3 +186,59 @@ async def test_drawer_navigation(flet_app_function: ftt.FletTestApp):
# Verify home view
home_text = await flet_app_function.tester.find_by_text("Welcome to Home Page")
assert home_text.count == 1


@pytest.mark.parametrize(
"flet_app_function",
[{"flet_app_main": pop_views_until.main}],
indirect=True,
)
@pytest.mark.asyncio(loop_scope="function")
async def test_pop_views_until(flet_app_function: ftt.FletTestApp):
# Verify initial view
button = await flet_app_function.tester.find_by_text_containing("Start flow")
assert button.count == 1
result_text = await flet_app_function.tester.find_by_text("No result yet")
assert result_text.count == 1

# Navigate to Step 1
await flet_app_function.tester.tap(button)
await flet_app_function.tester.pump_and_settle()
step1_text = await flet_app_function.tester.find_by_text("Step 1 of the flow")
assert step1_text.count == 1

# Navigate to Step 2
step2_button = await flet_app_function.tester.find_by_text_containing(
"Go to Step 2"
)
assert step2_button.count == 1
await flet_app_function.tester.tap(step2_button)
await flet_app_function.tester.pump_and_settle()
step2_text = await flet_app_function.tester.find_by_text("Step 2 of the flow")
assert step2_text.count == 1

# Navigate to Step 3
step3_button = await flet_app_function.tester.find_by_text_containing(
"Go to Step 3"
)
assert step3_button.count == 1
await flet_app_function.tester.tap(step3_button)
await flet_app_function.tester.pump_and_settle()
final_text = await flet_app_function.tester.find_by_text("Flow complete!")
assert final_text.count == 1

# Click "Finish and go Home" — triggers pop_views_until
finish_button = await flet_app_function.tester.find_by_text_containing(
"Finish and go Home"
)
assert finish_button.count == 1
await flet_app_function.tester.tap(finish_button)
await flet_app_function.tester.pump_and_settle()

# Verify back at Home with result
result_text = await flet_app_function.tester.find_by_text("Result: Flow completed!")
assert result_text.count == 1

# Verify we can start the flow again
button = await flet_app_function.tester.find_by_text_containing("Start flow")
assert button.count == 1
2 changes: 2 additions & 0 deletions sdk/python/packages/flet/src/flet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@
PlatformBrightnessChangeEvent,
RouteChangeEvent,
ViewPopEvent,
ViewsPopUntilEvent,
)
from flet.controls.painting import (
Paint,
Expand Down Expand Up @@ -1073,6 +1074,7 @@
"VerticalDivider",
"View",
"ViewPopEvent",
"ViewsPopUntilEvent",
"VisualDensity",
"Wakelock",
"WebBrowserName",
Expand Down
Loading