Skip to content

Commit a29e682

Browse files
authored
Use Hero app as example
1 parent beb4972 commit a29e682

5 files changed

Lines changed: 228 additions & 18 deletions

File tree

.github/workflows/all-builds.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# docs: https://docs.flet.dev/publish/#github-actions/
2+
13
name: Build Flet App
24

35
on:

.github/workflows/web-build-and-gh-pages-deploy.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# docs: https://docs.flet.dev/publish/web/static-website/hosting/github-pages/
2+
13
name: Web Build + Deploy to GitHub Pages
24

35
on:

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ Android (`aab`, `apk`), iOS (`ipa`), Linux, macOS, Windows, and Web.
66

77
Feel free to reuse them and customize to your specific usecases and needs.
88

9+
View the [demo web app](https://ndonkohenri.github.io/flet-github-action-workflows/)
10+
deployed to GitHub Pages by the [`web-build-and-gh-pages-deploy.yml`](#what-is-in-this-repo) workflow.
11+
912
## What is in this repo
1013

11-
| File | Purpose |
12-
|------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
13-
| [`.github/workflows/all-builds.yml`](.github/workflows/all-builds.yml) | Builds for Linux, macOS, Windows, AAB, APK, IPA, and Web.<br>More details [here](https://docs.flet.dev/publish/#github-actions). |
14-
| [`.github/workflows/web-build-and-github-pages-deploy.yml`](.github/workflows/web-build-and-gh-pages-deploy.yml) | Builds the web app and deploys it to GitHub Pages.<br>Uses:<br>• `--base-url ${GITHUB_REPOSITORY#*/}` - repository name as base URL<br>`--route-url-strategy hash` - recommended for static hosts like GitHub Pages |
15-
| [`pyproject.toml`](pyproject.toml) | Example Flet project configuration |
16-
| [`src/main.py`](src/main.py) | Example Flet app to test the workflows |
14+
| File | Purpose |
15+
|------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
16+
| [`.github/workflows/all-builds.yml`](.github/workflows/all-builds.yml) | Builds for Linux, macOS, Windows, AAB, APK, IPA, and Web.<br>More details [here](https://docs.flet.dev/publish/#github-actions). |
17+
| [`.github/workflows/web-build-and-github-pages-deploy.yml`](.github/workflows/web-build-and-gh-pages-deploy.yml) | Builds the web app and deploys it to GitHub Pages.<br>More details [here](https://docs.flet.dev/publish/web/static-website/hosting/github-pages/).<br> **Demo [here](https://ndonkohenri.github.io/flet-github-action-workflows/)**. |
18+
| [`pyproject.toml`](pyproject.toml) | Example Flet project configuration |
19+
| [`src/main.py`](src/main.py) | Example Flet app to test the workflows |
1720

1821

1922
**Quick start:**

pyproject.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ authors = [
88
{ name = "TheEthicalBoy", email = "me@ethicalboy.com" }
99
]
1010
dependencies = [
11-
"flet==0.80.6.dev7577"
11+
"flet==0.80.6.dev7664"
1212
]
1313

1414
[dependency-groups]
1515
dev = [
16-
"flet[all]==0.80.6.dev7577",
16+
"flet[all]==0.80.6.dev7664",
1717
]
1818

1919
# Docs: https://docs.flet.dev/publish
@@ -24,3 +24,6 @@ product = "Flet GHA Example"
2424

2525
[tool.flet.app]
2626
path = "src"
27+
28+
[tool.flet.flutter.pubspec.dependency_overrides]
29+
flet = { git = { url = "https://github.com/flet-dev/flet.git", ref = "main", path = "packages/flet" } }

src/main.py

Lines changed: 210 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,221 @@
11
"""
2-
Flet Placeholder Example: https://docs.flet.dev/controls/placeholder/#basic-example
2+
Flet Hero Example: https://docs.flet.dev/controls/hero/#gallery
33
"""
44

55
import flet as ft
66

7+
PRODUCTS = [
8+
{
9+
"id": 1,
10+
"name": "Comet",
11+
"subtitle": "Fast launch profile",
12+
"description": "Balanced setup for quick iteration and lightweight payloads.",
13+
"icon": ft.Icons.ROCKET_LAUNCH,
14+
"start_color": ft.Colors.BLUE_700,
15+
"end_color": ft.Colors.CYAN_400,
16+
},
17+
{
18+
"id": 2,
19+
"name": "Nebula",
20+
"subtitle": "Visual pipeline",
21+
"description": "Optimized for rich UI transitions and animated data surfaces.",
22+
"icon": ft.Icons.AUTO_AWESOME,
23+
"start_color": ft.Colors.DEEP_PURPLE_700,
24+
"end_color": ft.Colors.PINK_400,
25+
},
26+
{
27+
"id": 3,
28+
"name": "Orbit",
29+
"subtitle": "Reliable baseline",
30+
"description": "Stable profile focused on consistency and performance.",
31+
"icon": ft.Icons.PUBLIC,
32+
"start_color": ft.Colors.GREEN_700,
33+
"end_color": ft.Colors.LIGHT_GREEN_400,
34+
},
35+
{
36+
"id": 4,
37+
"name": "Aurora",
38+
"subtitle": "Analytics focus",
39+
"description": "Configured for telemetry-heavy apps and live metrics.",
40+
"icon": ft.Icons.ANALYTICS,
41+
"start_color": ft.Colors.ORANGE_700,
42+
"end_color": ft.Colors.AMBER_400,
43+
},
44+
{
45+
"id": 5,
46+
"name": "Pulse",
47+
"subtitle": "Real-time profile",
48+
"description": "Tuned for frequent updates, messaging, and event streams.",
49+
"icon": ft.Icons.BOLT,
50+
"start_color": ft.Colors.RED_700,
51+
"end_color": ft.Colors.DEEP_ORANGE_400,
52+
},
53+
]
54+
55+
56+
def hero_tag(product_id: int) -> str:
57+
return f"product-hero-{product_id}"
58+
759

860
def main(page: ft.Page):
9-
page.add(
10-
ft.Placeholder(
11-
expand=True,
12-
color=ft.Colors.GREEN_ACCENT,
13-
fallback_height=200,
14-
fallback_width=300,
15-
stroke_width=20,
61+
def product_by_id(product_id: int):
62+
for product in PRODUCTS:
63+
if product["id"] == product_id:
64+
return product
65+
return None
66+
67+
def route_product_id(route: str):
68+
segments = [segment for segment in route.split("/") if segment]
69+
if len(segments) != 2 or segments[0] != "product":
70+
return None
71+
try:
72+
return int(segments[1])
73+
except ValueError:
74+
return None
75+
76+
async def open_product(product_id: int):
77+
await page.push_route(f"/product/{product_id}")
78+
79+
async def back_to_gallery(e: ft.Event[ft.Button]):
80+
await page.push_route("/")
81+
82+
def build_hero_tile(product: dict, size: int) -> ft.Hero:
83+
icon_size = max(24, int(size * 0.4))
84+
return ft.Hero(
85+
tag=hero_tag(product["id"]),
86+
transition_on_user_gestures=True,
87+
content=ft.Container(
88+
width=size,
89+
height=size,
90+
border_radius=ft.BorderRadius.all(20),
91+
gradient=ft.LinearGradient(
92+
begin=ft.Alignment.TOP_LEFT,
93+
end=ft.Alignment.BOTTOM_RIGHT,
94+
colors=[product["start_color"], product["end_color"]],
95+
),
96+
alignment=ft.Alignment.CENTER,
97+
content=ft.Icon(product["icon"], color=ft.Colors.WHITE, size=icon_size),
98+
),
1699
)
17-
)
100+
101+
def build_home_view() -> ft.View:
102+
rows: list[ft.Control] = []
103+
for product in PRODUCTS:
104+
rows.append(
105+
ft.GestureDetector(
106+
mouse_cursor=ft.MouseCursor.CLICK,
107+
on_tap=lambda _, pid=product["id"]: page.run_task(
108+
open_product, pid
109+
),
110+
content=ft.Card(
111+
content=ft.Container(
112+
padding=12,
113+
content=ft.Row(
114+
vertical_alignment=ft.CrossAxisAlignment.CENTER,
115+
spacing=12,
116+
controls=[
117+
build_hero_tile(product, 78),
118+
ft.Column(
119+
spacing=4,
120+
controls=[
121+
ft.Text(
122+
product["name"],
123+
size=18,
124+
weight=ft.FontWeight.W_600,
125+
),
126+
ft.Text(
127+
product["subtitle"],
128+
color=ft.Colors.ON_SURFACE_VARIANT,
129+
),
130+
ft.Text(
131+
"Tap to view details",
132+
size=12,
133+
color=ft.Colors.PRIMARY,
134+
),
135+
],
136+
),
137+
],
138+
),
139+
)
140+
),
141+
)
142+
)
143+
144+
return ft.View(
145+
route="/",
146+
appbar=ft.AppBar(title=ft.Text("Hero gallery")),
147+
controls=[
148+
ft.Column(
149+
expand=True,
150+
spacing=10,
151+
scroll=ft.ScrollMode.AUTO,
152+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
153+
controls=[
154+
ft.Text(
155+
"Each card has a unique Hero tag. "
156+
"Open any item to see a matched transition.",
157+
color=ft.Colors.ON_SURFACE_VARIANT,
158+
),
159+
*rows,
160+
],
161+
)
162+
],
163+
)
164+
165+
def build_details_view(product: dict) -> ft.View:
166+
return ft.View(
167+
route=f"/product/{product['id']}",
168+
appbar=ft.AppBar(title=ft.Text(product["name"])),
169+
controls=[
170+
ft.Column(
171+
expand=True,
172+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
173+
spacing=16,
174+
scroll=ft.ScrollMode.AUTO,
175+
controls=[
176+
ft.Container(height=8),
177+
build_hero_tile(product, 220),
178+
ft.Text(
179+
product["subtitle"],
180+
size=20,
181+
weight=ft.FontWeight.W_600,
182+
text_align=ft.TextAlign.CENTER,
183+
),
184+
ft.Container(
185+
width=520,
186+
content=ft.Text(
187+
product["description"],
188+
text_align=ft.TextAlign.CENTER,
189+
color=ft.Colors.ON_SURFACE_VARIANT,
190+
),
191+
),
192+
ft.Button("Back to gallery", on_click=back_to_gallery),
193+
],
194+
)
195+
],
196+
)
197+
198+
def route_change(e: ft.RouteChangeEvent = None):
199+
page.views.clear()
200+
page.views.append(build_home_view())
201+
202+
pid = route_product_id(page.route)
203+
if pid is not None:
204+
product = product_by_id(pid)
205+
if product is not None:
206+
page.views.append(build_details_view(product))
207+
208+
page.update()
209+
210+
async def view_pop(e: ft.ViewPopEvent):
211+
if e.view is not None:
212+
page.views.remove(e.view)
213+
await page.push_route(page.views[-1].route)
214+
215+
page.on_route_change = route_change
216+
page.on_view_pop = view_pop
217+
route_change()
18218

19219

20220
if __name__ == "__main__":
21-
ft.run(main)
221+
ft.run(main)

0 commit comments

Comments
 (0)