flet-routing 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flet_routing-1.0.0/PKG-INFO +617 -0
- flet_routing-1.0.0/README.md +607 -0
- flet_routing-1.0.0/pyproject.toml +22 -0
- flet_routing-1.0.0/setup.cfg +4 -0
- flet_routing-1.0.0/src/flet_routing/__init__.py +28 -0
- flet_routing-1.0.0/src/flet_routing/builtin/__init__.py +9 -0
- flet_routing-1.0.0/src/flet_routing/builtin/middlewares/logger.py +16 -0
- flet_routing-1.0.0/src/flet_routing/builtin/views/not_auth.py +35 -0
- flet_routing-1.0.0/src/flet_routing/builtin/views/not_found.py +35 -0
- flet_routing-1.0.0/src/flet_routing/components/__init__.py +7 -0
- flet_routing-1.0.0/src/flet_routing/components/base_view.py +110 -0
- flet_routing-1.0.0/src/flet_routing/components/middleware.py +3 -0
- flet_routing-1.0.0/src/flet_routing/components/middleware_base.py +13 -0
- flet_routing-1.0.0/src/flet_routing/py.typed +0 -0
- flet_routing-1.0.0/src/flet_routing/router.py +629 -0
- flet_routing-1.0.0/src/flet_routing/types/__init__.py +19 -0
- flet_routing-1.0.0/src/flet_routing/types/types.py +47 -0
- flet_routing-1.0.0/src/flet_routing.egg-info/PKG-INFO +617 -0
- flet_routing-1.0.0/src/flet_routing.egg-info/SOURCES.txt +20 -0
- flet_routing-1.0.0/src/flet_routing.egg-info/dependency_links.txt +1 -0
- flet_routing-1.0.0/src/flet_routing.egg-info/requires.txt +2 -0
- flet_routing-1.0.0/src/flet_routing.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flet-routing
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A powerful routing library for Flet applications with authentication, middleware, and type safety
|
|
5
|
+
Author-email: MasterA5 <agustin090806090806@gmail.com>
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: flet==0.28.3
|
|
9
|
+
Requires-Dist: cryptography
|
|
10
|
+
|
|
11
|
+
# Flet Router
|
|
12
|
+
|
|
13
|
+
[](https://pypi.org/project/flet-router/)
|
|
14
|
+
[](https://opensource.org/licenses/MIT)
|
|
15
|
+
[](https://www.python.org/downloads/)
|
|
16
|
+
|
|
17
|
+
A powerful and flexible routing library for Flet applications, enabling seamless navigation between pages and views with support for deep linking, route parameters, authentication, and middleware.
|
|
18
|
+
|
|
19
|
+
## Overview
|
|
20
|
+
|
|
21
|
+
Flet Router simplifies navigation management in Flet applications by providing a declarative routing system. It handles page transitions, state management, and URL-based navigation, allowing developers to build multi-page applications with ease. Built with type safety, performance, and extensibility in mind.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **Declarative Routing**: Define routes using a clean, intuitive API
|
|
26
|
+
- **Page Navigation**: Seamless transitions between different pages and views
|
|
27
|
+
- **Route Parameters**: Support for dynamic URL parameters with automatic type casting
|
|
28
|
+
- **Query Parameters**: Handle URL query strings
|
|
29
|
+
- **Private Parameters**: Securely pass sensitive data between routes using encryption
|
|
30
|
+
- **Deep Linking**: Navigate directly to specific routes with parameters
|
|
31
|
+
- **History Management**: Built-in back/forward navigation support with stack management
|
|
32
|
+
- **Authentication & Guards**: Protect routes with authentication checks and custom guards
|
|
33
|
+
- **Middleware Support**: Execute custom logic before route transitions
|
|
34
|
+
- **Named Routes**: Navigate using human-readable route names
|
|
35
|
+
- **Route Preloading**: Preload views for improved performance
|
|
36
|
+
- **View Caching**: Optional caching system for frequently accessed views
|
|
37
|
+
- **Session Management**: Built-in session handling for user state
|
|
38
|
+
- **Async Support**: Full support for asynchronous operations and data loading
|
|
39
|
+
- **Type Safety**: Full type hints for better IDE support and error detection
|
|
40
|
+
- **Lightweight**: Minimal dependencies and overhead
|
|
41
|
+
- **Extensible**: Plugin system with middleware and guards
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
Install Flet Router using pip:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install flet-router
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Requirements
|
|
52
|
+
|
|
53
|
+
- Python 3.9+
|
|
54
|
+
- Flet 0.28.3+
|
|
55
|
+
|
|
56
|
+
### Async Support
|
|
57
|
+
|
|
58
|
+
Flet Router fully supports asynchronous operations in your route handlers and middleware. Use `page.run_task()` or `asyncio.run()` for async data loading:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import httpx
|
|
62
|
+
import asyncio
|
|
63
|
+
|
|
64
|
+
@router.route("/products")
|
|
65
|
+
def products_view(params):
|
|
66
|
+
products_list = ft.Column()
|
|
67
|
+
|
|
68
|
+
async def load_products():
|
|
69
|
+
async with httpx.AsyncClient() as client:
|
|
70
|
+
response = await client.get("https://api.example.com/products")
|
|
71
|
+
products = response.json()
|
|
72
|
+
# Update UI with loaded data
|
|
73
|
+
products_list.controls = [ft.Text(p["name"]) for p in products]
|
|
74
|
+
params.page.update()
|
|
75
|
+
|
|
76
|
+
# Start async task
|
|
77
|
+
params.page.run_task(load_products)
|
|
78
|
+
|
|
79
|
+
return ft.View(
|
|
80
|
+
route="/products",
|
|
81
|
+
controls=[
|
|
82
|
+
ft.Text("Products", size=30),
|
|
83
|
+
products_list,
|
|
84
|
+
]
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
### Basic Usage with Decorators
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
import flet as ft
|
|
94
|
+
from flet_router import FletRouter
|
|
95
|
+
|
|
96
|
+
def main(page: ft.Page):
|
|
97
|
+
router = FletRouter(page=page)
|
|
98
|
+
|
|
99
|
+
@router.route("/")
|
|
100
|
+
def home_view(params):
|
|
101
|
+
return ft.View(
|
|
102
|
+
route="/",
|
|
103
|
+
controls=[
|
|
104
|
+
ft.Text("Home Page", size=30),
|
|
105
|
+
ft.ElevatedButton(
|
|
106
|
+
"Go to About",
|
|
107
|
+
on_click=lambda e: router.push("/about")
|
|
108
|
+
)
|
|
109
|
+
]
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@router.route("/about")
|
|
113
|
+
def about_view(params):
|
|
114
|
+
return ft.View(
|
|
115
|
+
route="/about",
|
|
116
|
+
controls=[
|
|
117
|
+
ft.Text("About Page", size=30),
|
|
118
|
+
ft.ElevatedButton(
|
|
119
|
+
"Go Back",
|
|
120
|
+
on_click=lambda e: router.back()
|
|
121
|
+
)
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
router.push("/")
|
|
126
|
+
|
|
127
|
+
ft.app(target=main)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Alternative: Using Route Class
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from flet_router import FletRouter, Route
|
|
134
|
+
|
|
135
|
+
def main(page: ft.Page):
|
|
136
|
+
def home_view(params):
|
|
137
|
+
return ft.View(route="/", controls=[ft.Text("Home Page")])
|
|
138
|
+
|
|
139
|
+
def about_view(params):
|
|
140
|
+
return ft.View(route="/about", controls=[ft.Text("About Page")])
|
|
141
|
+
|
|
142
|
+
router = FletRouter(
|
|
143
|
+
page=page,
|
|
144
|
+
routes=[
|
|
145
|
+
Route("/", home_view),
|
|
146
|
+
Route("/about", about_view),
|
|
147
|
+
]
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
router.push("/")
|
|
151
|
+
|
|
152
|
+
ft.app(target=main)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Route Parameters
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
def user_view(params):
|
|
159
|
+
user_id = params.path["id"]
|
|
160
|
+
return ft.View(
|
|
161
|
+
route="/user/:id",
|
|
162
|
+
controls=[
|
|
163
|
+
ft.Text(f"User Profile: {user_id}", size=30),
|
|
164
|
+
ft.ElevatedButton("Back", on_click=lambda e: params.router.back())
|
|
165
|
+
]
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
router = FletRouter(
|
|
169
|
+
page=page,
|
|
170
|
+
routes=[
|
|
171
|
+
Route("/user/:id", user_view),
|
|
172
|
+
]
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Navigate with parameters
|
|
176
|
+
router.push("/user/123")
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Authentication & Protected Routes
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
import flet as ft
|
|
183
|
+
from flet_router import FletRouter, Route, MiddlewareContext
|
|
184
|
+
|
|
185
|
+
# Session state
|
|
186
|
+
class Session:
|
|
187
|
+
def __init__(self):
|
|
188
|
+
self.authenticated = False
|
|
189
|
+
self.user = None
|
|
190
|
+
|
|
191
|
+
session = Session()
|
|
192
|
+
|
|
193
|
+
# Authentication middleware
|
|
194
|
+
def auth_middleware(ctx: MiddlewareContext) -> bool:
|
|
195
|
+
if ctx.route and ctx.route.protected and not session.authenticated:
|
|
196
|
+
ctx.router.replace("/login", {"redirect": ctx.full_path})
|
|
197
|
+
return False
|
|
198
|
+
return True
|
|
199
|
+
|
|
200
|
+
# Custom guard for user profiles
|
|
201
|
+
def user_profile_guard(ctx: MiddlewareContext) -> bool:
|
|
202
|
+
if not session.authenticated:
|
|
203
|
+
return False
|
|
204
|
+
# Users can only view their own profile
|
|
205
|
+
user_id = ctx.params.path.get("id")
|
|
206
|
+
return str(session.user_id) == str(user_id)
|
|
207
|
+
|
|
208
|
+
def login_view(params):
|
|
209
|
+
username_field = ft.TextField(label="Username")
|
|
210
|
+
password_field = ft.TextField(label="Password", password=True)
|
|
211
|
+
|
|
212
|
+
def do_login(e):
|
|
213
|
+
# Your authentication logic here
|
|
214
|
+
session.authenticated = True
|
|
215
|
+
session.user = username_field.value
|
|
216
|
+
# Redirect to intended page or home
|
|
217
|
+
redirect_to = params.private.get("redirect", "/")
|
|
218
|
+
params.router.replace(redirect_to)
|
|
219
|
+
|
|
220
|
+
return ft.View(
|
|
221
|
+
route="/login",
|
|
222
|
+
controls=[
|
|
223
|
+
ft.Text("Login", size=30),
|
|
224
|
+
username_field,
|
|
225
|
+
password_field,
|
|
226
|
+
ft.ElevatedButton("Login", on_click=do_login),
|
|
227
|
+
]
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
def dashboard_view(params):
|
|
231
|
+
return ft.View(
|
|
232
|
+
route="/dashboard",
|
|
233
|
+
controls=[
|
|
234
|
+
ft.Text(f"Welcome, {session.user}!", size=30),
|
|
235
|
+
ft.ElevatedButton("Logout", on_click=lambda e: logout_and_redirect(params.router)),
|
|
236
|
+
]
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
def user_profile_view(params):
|
|
240
|
+
user_id = params.path["id"]
|
|
241
|
+
return ft.View(
|
|
242
|
+
route=f"/user/{user_id}",
|
|
243
|
+
controls=[
|
|
244
|
+
ft.Text(f"Profile for user {user_id}", size=30),
|
|
245
|
+
]
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
def logout_and_redirect(router):
|
|
249
|
+
session.authenticated = False
|
|
250
|
+
session.user = None
|
|
251
|
+
router.replace("/")
|
|
252
|
+
|
|
253
|
+
router = FletRouter(
|
|
254
|
+
page=page,
|
|
255
|
+
routes=[
|
|
256
|
+
Route("/login", login_view),
|
|
257
|
+
Route("/dashboard", dashboard_view, protected=True),
|
|
258
|
+
Route("/user/:id", user_profile_view, protected=True, guard=user_profile_guard),
|
|
259
|
+
],
|
|
260
|
+
auth_checker=lambda: session.authenticated,
|
|
261
|
+
not_auth_redirect_route="/login"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
router.use(auth_middleware)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Middleware
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
def logging_middleware(ctx):
|
|
271
|
+
print(f"Navigating to: {ctx.path}")
|
|
272
|
+
return True # Continue navigation
|
|
273
|
+
|
|
274
|
+
def auth_middleware(ctx):
|
|
275
|
+
if ctx.route and ctx.route.protected and not ctx.router.checker():
|
|
276
|
+
return False # Block navigation
|
|
277
|
+
return True
|
|
278
|
+
|
|
279
|
+
router = FletRouter(page=page, routes=routes)
|
|
280
|
+
router.use(logging_middleware)
|
|
281
|
+
router.use(auth_middleware)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Named Routes
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
router = FletRouter(
|
|
288
|
+
page=page,
|
|
289
|
+
routes=[
|
|
290
|
+
Route("/user/:id", user_view, name="user_profile"),
|
|
291
|
+
]
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# Navigate using name
|
|
295
|
+
router.push_named("user_profile", path_params={"id": "123"})
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
#### Decorators vs Route Class
|
|
299
|
+
|
|
300
|
+
You can define routes using either decorators or the `Route` class. Both approaches are equivalent:
|
|
301
|
+
|
|
302
|
+
**Using Decorators (Recommended):**
|
|
303
|
+
```python
|
|
304
|
+
@router.route("/user/:id", protected=True, name="user_profile")
|
|
305
|
+
def user_view(params):
|
|
306
|
+
return ft.View(route=f"/user/{params.path['id']}", ...)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Using Route Class:**
|
|
310
|
+
```python
|
|
311
|
+
def user_view(params):
|
|
312
|
+
return ft.View(route=f"/user/{params.path['id']}", ...)
|
|
313
|
+
|
|
314
|
+
routes = [
|
|
315
|
+
Route("/user/:id", user_view, protected=True, name="user_profile"),
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
router = FletRouter(page=page, routes=routes)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**When to use decorators:**
|
|
322
|
+
- When you have many routes in one file
|
|
323
|
+
- For cleaner, more readable code
|
|
324
|
+
- When routes are closely tied to their view functions
|
|
325
|
+
- For dynamic route registration
|
|
326
|
+
|
|
327
|
+
**When to use Route class:**
|
|
328
|
+
- When defining routes in configuration files
|
|
329
|
+
- When routes are defined separately from view functions
|
|
330
|
+
- For programmatic route generation
|
|
331
|
+
- When working with route metadata
|
|
332
|
+
|
|
333
|
+
#### Integration with Guards and Middleware
|
|
334
|
+
|
|
335
|
+
Decorated routes work seamlessly with the authentication and middleware system:
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
def admin_guard(ctx: MiddlewareContext) -> bool:
|
|
339
|
+
"""Only allow admin users"""
|
|
340
|
+
return session.user_role == "admin"
|
|
341
|
+
|
|
342
|
+
def logging_middleware(ctx: MiddlewareContext) -> bool:
|
|
343
|
+
"""Log all navigation"""
|
|
344
|
+
print(f"Navigating to: {ctx.path}")
|
|
345
|
+
return True
|
|
346
|
+
|
|
347
|
+
# Routes with guards
|
|
348
|
+
@router.route("/admin", protected=True, guard=admin_guard)
|
|
349
|
+
def admin_panel(params):
|
|
350
|
+
return ft.View(route="/admin", controls=[ft.Text("Admin Panel")])
|
|
351
|
+
|
|
352
|
+
@router.route("/user/:id", protected=True, guard=user_owns_resource)
|
|
353
|
+
def user_profile(params):
|
|
354
|
+
return ft.View(route=f"/user/{params.path['id']}", ...)
|
|
355
|
+
|
|
356
|
+
# Add global middleware
|
|
357
|
+
router.use(logging_middleware)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
The `protected=True` parameter automatically applies authentication checks, while custom `guard` functions provide additional authorization logic.
|
|
361
|
+
|
|
362
|
+
#### Async Routes with Decorators
|
|
363
|
+
|
|
364
|
+
Decorators work perfectly with async view functions for data loading:
|
|
365
|
+
|
|
366
|
+
```python
|
|
367
|
+
import httpx
|
|
368
|
+
|
|
369
|
+
@router.route("/products", name="products")
|
|
370
|
+
def products_view(params):
|
|
371
|
+
products_list = ft.Column(scroll="auto")
|
|
372
|
+
loading = ft.Text("Loading products...")
|
|
373
|
+
|
|
374
|
+
async def load_products():
|
|
375
|
+
try:
|
|
376
|
+
async with httpx.AsyncClient() as client:
|
|
377
|
+
response = await client.get("https://api.example.com/products")
|
|
378
|
+
products = response.json()
|
|
379
|
+
|
|
380
|
+
products_list.controls = [
|
|
381
|
+
ft.Card(
|
|
382
|
+
content=ft.Container(
|
|
383
|
+
content=ft.Text(product["name"]),
|
|
384
|
+
padding=10
|
|
385
|
+
)
|
|
386
|
+
) for product in products
|
|
387
|
+
]
|
|
388
|
+
loading.visible = False
|
|
389
|
+
params.page.update()
|
|
390
|
+
except Exception as e:
|
|
391
|
+
loading.value = f"Error: {e}"
|
|
392
|
+
params.page.update()
|
|
393
|
+
|
|
394
|
+
# Start async loading
|
|
395
|
+
params.page.run_task(load_products)
|
|
396
|
+
|
|
397
|
+
return ft.View(
|
|
398
|
+
route="/products",
|
|
399
|
+
controls=[
|
|
400
|
+
ft.Text("Products", size=30, weight=ft.FontWeight.BOLD),
|
|
401
|
+
loading,
|
|
402
|
+
products_list,
|
|
403
|
+
]
|
|
404
|
+
)
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## API Reference
|
|
408
|
+
|
|
409
|
+
### FletRouter Class
|
|
410
|
+
|
|
411
|
+
The main router class that manages navigation and routing.
|
|
412
|
+
|
|
413
|
+
#### Constructor Parameters
|
|
414
|
+
|
|
415
|
+
- `page` (Page): The Flet page instance
|
|
416
|
+
- `routes` (List[Route]): List of route definitions
|
|
417
|
+
- `auth_checker` (Optional[AuthChecker]): Authentication checker function or boolean
|
|
418
|
+
- `not_found_view` (Optional[ViewFactory]): Custom 404 view
|
|
419
|
+
- `not_auth_view` (Optional[ViewFactory]): Custom 401 view
|
|
420
|
+
- `not_auth_redirect_route` (Optional[str]): Route to redirect on auth failure
|
|
421
|
+
- `initial_route` (Optional[str]): Initial route to navigate to
|
|
422
|
+
- `enable_view_cache` (bool): Enable view caching (default: False)
|
|
423
|
+
|
|
424
|
+
#### Methods
|
|
425
|
+
|
|
426
|
+
- `push(path, private_params)`: Navigate to a new route
|
|
427
|
+
- `replace(path, private_params)`: Replace current route
|
|
428
|
+
- `back(steps)`: Go back in navigation history
|
|
429
|
+
- `push_named(name, path_params, private_params)`: Navigate using route name
|
|
430
|
+
- `use(middleware)`: Add middleware
|
|
431
|
+
- `route(path, **options)`: Decorator for defining routes (alternative to Route class)
|
|
432
|
+
|
|
433
|
+
#### Decorator Usage
|
|
434
|
+
|
|
435
|
+
The `@router.route()` decorator provides a clean, Pythonic way to define routes. It's an alternative to creating `Route` objects manually.
|
|
436
|
+
|
|
437
|
+
```python
|
|
438
|
+
router = FletRouter(page=page)
|
|
439
|
+
|
|
440
|
+
# Basic route
|
|
441
|
+
@router.route("/home")
|
|
442
|
+
def home_view(params):
|
|
443
|
+
return ft.View(route="/home", controls=[ft.Text("Home Page")])
|
|
444
|
+
|
|
445
|
+
# Route with parameters
|
|
446
|
+
@router.route("/user/:id")
|
|
447
|
+
def user_view(params):
|
|
448
|
+
user_id = params.path["id"]
|
|
449
|
+
return ft.View(route=f"/user/{user_id}", controls=[ft.Text(f"User {user_id}")])
|
|
450
|
+
|
|
451
|
+
# Protected route with authentication
|
|
452
|
+
@router.route("/dashboard", protected=True)
|
|
453
|
+
def dashboard_view(params):
|
|
454
|
+
return ft.View(route="/dashboard", controls=[ft.Text("Dashboard")])
|
|
455
|
+
|
|
456
|
+
# Named route for easy navigation
|
|
457
|
+
@router.route("/profile", name="user_profile")
|
|
458
|
+
def profile_view(params):
|
|
459
|
+
return ft.View(route="/profile", controls=[ft.Text("Profile")])
|
|
460
|
+
|
|
461
|
+
# Route with custom guard
|
|
462
|
+
@router.route("/admin", protected=True, guard=admin_guard)
|
|
463
|
+
def admin_view(params):
|
|
464
|
+
return ft.View(route="/admin", controls=[ft.Text("Admin Panel")])
|
|
465
|
+
|
|
466
|
+
# Route with preloading for better performance
|
|
467
|
+
@router.route("/settings", preload=True)
|
|
468
|
+
def settings_view(params):
|
|
469
|
+
return ft.View(route="/settings", controls=[ft.Text("Settings")])
|
|
470
|
+
|
|
471
|
+
# Combined options
|
|
472
|
+
@router.route("/user/:id/posts",
|
|
473
|
+
name="user_posts",
|
|
474
|
+
protected=True,
|
|
475
|
+
guard=user_owns_resource)
|
|
476
|
+
def user_posts_view(params):
|
|
477
|
+
user_id = params.path["id"]
|
|
478
|
+
return ft.View(route=f"/user/{user_id}/posts",
|
|
479
|
+
controls=[ft.Text(f"Posts by user {user_id}")])
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### Decorator Parameters
|
|
483
|
+
|
|
484
|
+
- `path` (str): Route path pattern (required)
|
|
485
|
+
- `protected` (bool): Requires authentication (default: False)
|
|
486
|
+
- `guard` (Callable): Custom guard function for additional checks
|
|
487
|
+
- `preload` (bool): Preload view on router initialization (default: False)
|
|
488
|
+
- `name` (str): Named route identifier for `push_named()` navigation
|
|
489
|
+
|
|
490
|
+
#### Navigation with Named Routes
|
|
491
|
+
|
|
492
|
+
```python
|
|
493
|
+
# Navigate using route names
|
|
494
|
+
router.push_named("user_profile")
|
|
495
|
+
router.push_named("user_posts", path_params={"id": "123"})
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Route Class
|
|
499
|
+
|
|
500
|
+
Defines a route configuration.
|
|
501
|
+
|
|
502
|
+
#### Parameters
|
|
503
|
+
|
|
504
|
+
- `path` (str): Route path pattern (e.g., "/user/:id")
|
|
505
|
+
- `view` (ViewFactory): View factory function
|
|
506
|
+
- `protected` (bool): Whether route requires authentication
|
|
507
|
+
- `guard` (Optional[Callable]): Custom guard function
|
|
508
|
+
- `preload` (bool): Whether to preload the view
|
|
509
|
+
- `name` (Optional[str]): Named route identifier
|
|
510
|
+
|
|
511
|
+
### Params Class
|
|
512
|
+
|
|
513
|
+
Container for route parameters.
|
|
514
|
+
|
|
515
|
+
#### Attributes
|
|
516
|
+
|
|
517
|
+
- `path` (Dict[str, Any]): URL path parameters
|
|
518
|
+
- `private` (Dict[str, Any]): Encrypted private parameters
|
|
519
|
+
- `router` (FletRouter): Router instance
|
|
520
|
+
|
|
521
|
+
## Examples
|
|
522
|
+
|
|
523
|
+
The `examples` directory contains sample applications demonstrating various features:
|
|
524
|
+
|
|
525
|
+
### Complete Demo Application
|
|
526
|
+
|
|
527
|
+
The `examples/example_app.py` provides a comprehensive demonstration of Flet Router's capabilities:
|
|
528
|
+
|
|
529
|
+
- **Authentication Integration**: Login/logout with DummyJSON API
|
|
530
|
+
- **Protected Routes**: User profiles and cart pages with authentication guards
|
|
531
|
+
- **Route Guards**: Custom logic to verify user permissions (e.g., users can only view their own profiles)
|
|
532
|
+
- **Middleware**: Global authentication middleware
|
|
533
|
+
- **Named Routes**: Navigation using human-readable route names
|
|
534
|
+
- **Async Data Loading**: Fetching data from APIs with httpx
|
|
535
|
+
- **Session Management**: Persistent user sessions across navigation
|
|
536
|
+
- **Error Handling**: Proper error states and user feedback
|
|
537
|
+
- **Real-world UI**: Cards, images, avatars, and responsive layouts
|
|
538
|
+
|
|
539
|
+
#### Running the Example
|
|
540
|
+
|
|
541
|
+
```bash
|
|
542
|
+
# Install additional dependencies for the example
|
|
543
|
+
pip install httpx
|
|
544
|
+
|
|
545
|
+
# Run the example application
|
|
546
|
+
python examples/example_app.py
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Demo Credentials:**
|
|
550
|
+
- Username: `kminchelle`
|
|
551
|
+
- Password: `0lelplR`
|
|
552
|
+
|
|
553
|
+
The example includes:
|
|
554
|
+
- Public pages (home, products)
|
|
555
|
+
- Protected pages (user profile, cart)
|
|
556
|
+
- Authentication flow with redirects
|
|
557
|
+
- API integration with real data
|
|
558
|
+
- Responsive design with dark theme
|
|
559
|
+
|
|
560
|
+
### Basic Examples
|
|
561
|
+
|
|
562
|
+
- Basic navigation between pages
|
|
563
|
+
- Route parameters and query strings
|
|
564
|
+
- Authentication flows with guards
|
|
565
|
+
- Middleware usage for logging and validation
|
|
566
|
+
- Named routes for cleaner navigation
|
|
567
|
+
- Dynamic page creation with data fetching
|
|
568
|
+
|
|
569
|
+
## Contributing
|
|
570
|
+
|
|
571
|
+
We welcome contributions! Please follow these steps:
|
|
572
|
+
|
|
573
|
+
1. Fork the repository
|
|
574
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
575
|
+
3. Write tests for your changes
|
|
576
|
+
4. Ensure all tests pass
|
|
577
|
+
5. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
578
|
+
6. Push to the branch (`git push origin feature/amazing-feature`)
|
|
579
|
+
7. Open a Pull Request
|
|
580
|
+
|
|
581
|
+
### Development Setup
|
|
582
|
+
|
|
583
|
+
```bash
|
|
584
|
+
git clone https://github.com/MasterA5/flet_router.git
|
|
585
|
+
cd flet_router
|
|
586
|
+
pip install -e .[dev]
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
## License
|
|
590
|
+
|
|
591
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
592
|
+
|
|
593
|
+
## Support
|
|
594
|
+
|
|
595
|
+
- 📖 [Documentation](https://github.com/MasterA5/flet_router/wiki)
|
|
596
|
+
- 🐛 [Issue Tracker](https://github.com/MasterA5/flet_router/issues)
|
|
597
|
+
- 💬 [Discussions](https://github.com/MasterA5/flet_router/discussions)
|
|
598
|
+
|
|
599
|
+
For questions or suggestions, please open an issue on GitHub.
|
|
600
|
+
|
|
601
|
+
## Changelog
|
|
602
|
+
|
|
603
|
+
### v0.1.0
|
|
604
|
+
- Initial release
|
|
605
|
+
- Basic routing functionality
|
|
606
|
+
- Authentication support with guards and middleware
|
|
607
|
+
- Route parameters and private parameters with encryption
|
|
608
|
+
- View caching and preloading
|
|
609
|
+
- Named routes for cleaner navigation
|
|
610
|
+
- Session management
|
|
611
|
+
- Async support for data loading
|
|
612
|
+
- Comprehensive example application with DummyJSON API integration
|
|
613
|
+
- Type safety with full type hints
|
|
614
|
+
|
|
615
|
+
## Acknowledgments
|
|
616
|
+
|
|
617
|
+
Built with [Flet](https://flet.dev) - A framework for building beautiful multi-platform apps with Python.
|