feat: implement adaptive layout and sync navigation state
This commit is contained in:
+21
-7
@@ -1,17 +1,31 @@
|
||||
import flet as ft
|
||||
|
||||
from app.widgets.adaptive_menu import adaptive_menu
|
||||
from app.widgets.adaptive_menu import adaptive_menu, get_selected_index_from_route
|
||||
|
||||
MOBILE_BREAKPOINT = 600
|
||||
|
||||
def get_layout_mode(page: ft.Page):
|
||||
width = page.width if page.width and page.width > 0 else 1024
|
||||
return "mobile" if width < MOBILE_BREAKPOINT else "desktop"
|
||||
|
||||
def main_layout(page: ft.Page, content_container: ft.Container):
|
||||
print(">>> ENTER main_layout")
|
||||
menu = adaptive_menu(page)
|
||||
|
||||
# ตรวจสอบโหมด (ป้องกันหน้าจอขาวจาก width=0)
|
||||
width = page.width if page.width > 0 else 1024 # default ไว้ที่ desktop ก่อนถ้ายังไม่รู้ width
|
||||
is_mobile = width < 600
|
||||
print(f">>> Device mode: {'MOBILE' if is_mobile else 'DESKTOP'} (Width: {page.width})")
|
||||
mode = get_layout_mode(page)
|
||||
|
||||
if is_mobile:
|
||||
# เก็บ mode instance ไว้ที่ page
|
||||
page._layout_mode = mode
|
||||
|
||||
selected_index = get_selected_index_from_route(page.route)
|
||||
|
||||
menu = adaptive_menu(page, selected_index)
|
||||
|
||||
# เก็บ menu instance ไว้ที่ page
|
||||
page._menu_control = menu
|
||||
|
||||
print(f">>> Device mode: {mode}")
|
||||
|
||||
if mode == "mobile":
|
||||
return ft.Column(
|
||||
controls=[
|
||||
content_container,
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import flet as ft
|
||||
|
||||
def adaptive_menu(page: ft.Page):
|
||||
is_mobile = page.width < 600
|
||||
MENU_KEYS = ['articles', 'courses', 'my_courses', 'progress', 'profile', 'logout']
|
||||
|
||||
menu_keys = ['articles', 'courses', 'my_courses', 'progress', 'profile', 'logout']
|
||||
def get_selected_index_from_route(route: str):
|
||||
key = route.replace("/", "").split("/")[0]
|
||||
if key in MENU_KEYS:
|
||||
return MENU_KEYS.index(key)
|
||||
return 0
|
||||
|
||||
def adaptive_menu(page: ft.Page, selected_index: int):
|
||||
is_mobile = page.width < 600
|
||||
|
||||
async def handle_change(e):
|
||||
index = int(e.control.selected_index)
|
||||
key = menu_keys[index]
|
||||
key = MENU_KEYS[index]
|
||||
|
||||
if key == "logout":
|
||||
from app.state import state
|
||||
@@ -15,17 +21,7 @@ def adaptive_menu(page: ft.Page):
|
||||
await page.push_route("/login") # หรือ page.go
|
||||
return
|
||||
|
||||
route = f"/{menu_keys[index]}"
|
||||
print(f">>> Navigating to: {route}")
|
||||
await page.push_route(route)
|
||||
|
||||
# sync selected index กับ route
|
||||
current_route = page.route.replace("/", "") or "articles"
|
||||
|
||||
if current_route not in menu_keys:
|
||||
current_route = "articles"
|
||||
|
||||
current_selected_index = menu_keys.index(current_route)
|
||||
await page.push_route(f"/{key}")
|
||||
|
||||
if is_mobile:
|
||||
return ft.NavigationBar(
|
||||
@@ -38,7 +34,7 @@ def adaptive_menu(page: ft.Page):
|
||||
ft.NavigationBarDestination(icon=ft.Icons.LOGOUT, label="ออกจากระบบ"
|
||||
),
|
||||
],
|
||||
selected_index=current_selected_index,
|
||||
selected_index=selected_index,
|
||||
on_change=handle_change,
|
||||
)
|
||||
else:
|
||||
@@ -52,7 +48,7 @@ def adaptive_menu(page: ft.Page):
|
||||
ft.NavigationRailDestination(icon=ft.Icons.LOGOUT, label="Logout"
|
||||
),
|
||||
],
|
||||
selected_index=current_selected_index,
|
||||
selected_index=selected_index,
|
||||
on_change=handle_change,
|
||||
extended=True,
|
||||
)
|
||||
@@ -9,8 +9,11 @@ from app.pages.my_courses import my_courses_page
|
||||
from app.pages.progress import progress_page
|
||||
from app.pages.profile import profile_page
|
||||
from app.state import state
|
||||
from app.widgets.adaptive_menu import get_selected_index_from_route
|
||||
|
||||
|
||||
async def main(page: ft.Page):
|
||||
|
||||
page.title = "LMS Frontend"
|
||||
|
||||
# register font
|
||||
@@ -23,7 +26,7 @@ async def main(page: ft.Page):
|
||||
page.theme = ft.Theme(font_family="NotoSansThai")
|
||||
|
||||
# GLOBAL CONTAINER (รองรับ Persistent Layout + Dynamic Content)
|
||||
main_container = ft.Container(expand=True)
|
||||
main_container = ft.Container(expand=True, padding=10)
|
||||
|
||||
# ROUTES MAP
|
||||
routes = {
|
||||
@@ -88,6 +91,10 @@ async def main(page: ft.Page):
|
||||
else:
|
||||
main_container.content = ft.Text("404 NOT FOUND")
|
||||
|
||||
# หลังจาก set main_container.content แล้ว ให้อับเดตเมนูที่เลือก รองรับกรณี Back/Forward
|
||||
if hasattr(page, "_menu_control"):
|
||||
page._menu_control.selected_index = get_selected_index_from_route(page.route)
|
||||
|
||||
page.update()
|
||||
|
||||
# LOGIN SUCCESS
|
||||
@@ -97,6 +104,21 @@ async def main(page: ft.Page):
|
||||
|
||||
page.on_route_change = route_change
|
||||
|
||||
def on_resize(e):
|
||||
width = page.width if page.width and page.width > 0 else 1024
|
||||
new_mode = "mobile" if width < 600 else "desktop"
|
||||
|
||||
if getattr(page, "_layout_mode", None) == new_mode:
|
||||
return
|
||||
|
||||
print(f">>> Layout mode changed: {page._layout_mode} -> {new_mode}")
|
||||
|
||||
if page.views and page.views[-1].route == "/main":
|
||||
page.views[-1].controls[0] = main_layout(page, main_container)
|
||||
page.update()
|
||||
|
||||
page.on_resize = on_resize
|
||||
|
||||
# start app
|
||||
await page.push_route("/login")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user