mirror of
https://github.com/ihmily/StreamCap.git
synced 2026-05-06 21:51:36 +08:00
- Update deprecated APIs - Adapt breaking changes in flet 0.80+ - Test UI components compatibility
238 lines
8.1 KiB
Python
238 lines
8.1 KiB
Python
import argparse
|
|
import multiprocessing
|
|
import os
|
|
|
|
import flet as ft
|
|
from dotenv import load_dotenv
|
|
from screeninfo import get_monitors
|
|
|
|
from app.app_manager import App, execute_dir
|
|
from app.auth.auth_manager import AuthManager
|
|
from app.lifecycle.app_close_handler import handle_app_close
|
|
from app.lifecycle.tray_manager import TrayManager
|
|
from app.ui.components.common.save_progress_overlay import SaveProgressOverlay
|
|
from app.ui.layout.responsive_layout import setup_responsive_layout
|
|
from app.ui.views.login_view import LoginPage
|
|
from app.utils.logger import logger
|
|
|
|
DEFAULT_HOST = "127.0.0.1"
|
|
DEFAULT_PORT = 6006
|
|
WINDOW_SCALE = 0.65
|
|
MIN_WIDTH = 950
|
|
ASSETS_DIR = "assets"
|
|
|
|
|
|
class GlobalState:
|
|
periodic_tasks_started = False
|
|
|
|
|
|
global_state = GlobalState()
|
|
|
|
|
|
async def setup_window(page: ft.Page, app: App) -> None:
|
|
page.window.icon = os.path.join(execute_dir, ASSETS_DIR, "icon.ico")
|
|
page.window.skip_task_bar = False
|
|
page.window.always_on_top = False
|
|
page.focused = True
|
|
|
|
if not page.web:
|
|
try:
|
|
await page.window.center()
|
|
await page.window.to_front()
|
|
if app.settings.user_config.get("remember_window_size"):
|
|
window_width = app.settings.user_config.get("window_width")
|
|
window_height = app.settings.user_config.get("window_height")
|
|
if window_width and window_height:
|
|
page.window.width = int(window_width)
|
|
page.window.height = int(window_height)
|
|
return
|
|
|
|
screen = get_monitors()[0]
|
|
page.window.width = int(screen.width * WINDOW_SCALE)
|
|
page.window.height = int(screen.height * WINDOW_SCALE)
|
|
except IndexError:
|
|
logger.warning("No monitors detected, using default window size.")
|
|
|
|
|
|
def get_route_handler() -> dict[str, str]:
|
|
return {
|
|
"/": "home",
|
|
"/home": "home",
|
|
"/recordings": "recordings",
|
|
"/settings": "settings",
|
|
"/storage": "storage",
|
|
"/about": "about",
|
|
}
|
|
|
|
|
|
def handle_route_change(page: ft.Page, app: App) -> callable:
|
|
route_map = get_route_handler()
|
|
|
|
def route_change(e: ft.RouteChangeEvent) -> None:
|
|
tr = ft.TemplateRoute(e.route)
|
|
page_name = route_map.get(tr.route)
|
|
if page_name:
|
|
page.run_task(app.switch_page, page_name)
|
|
|
|
return route_change
|
|
|
|
|
|
def handle_window_event(page: ft.Page, app: App, save_progress_overlay: "SaveProgressOverlay") -> callable:
|
|
async def on_window_event(e) -> None:
|
|
if e.type == ft.WindowEventType.CLOSE:
|
|
if app.settings.user_config.get("remember_window_size"):
|
|
app.settings.user_config["window_width"] = page.window.width
|
|
app.settings.user_config["window_height"] = page.window.height
|
|
await app.config_manager.save_user_config(app.settings.user_config)
|
|
await handle_app_close(page, app, save_progress_overlay)
|
|
|
|
return on_window_event
|
|
|
|
|
|
def handle_disconnect(page: ft.Page, app: App) -> callable:
|
|
"""Handle disconnection for web mode."""
|
|
|
|
async def disconnect(_: ft.ControlEvent) -> None:
|
|
page.pubsub.unsubscribe_all()
|
|
app.settings.user_config["last_route"] = page.route
|
|
await app.config_manager.save_user_config(app.settings.user_config)
|
|
logger.info(f"Saved last route: {page.route}")
|
|
|
|
return disconnect
|
|
|
|
|
|
def handle_page_resize(page: ft.Page, app: App) -> callable:
|
|
"""handle page resize"""
|
|
|
|
def on_resize(_: ft.ControlEvent) -> None:
|
|
setup_responsive_layout(page, app)
|
|
page.update()
|
|
|
|
return on_resize
|
|
|
|
|
|
async def main(page: ft.Page) -> None:
|
|
page.title = "StreamCap"
|
|
page.window.min_width = MIN_WIDTH
|
|
page.window.min_height = MIN_WIDTH * WINDOW_SCALE
|
|
|
|
app = App(page)
|
|
page.data = app
|
|
app.is_web_mode = page.web
|
|
app.is_mobile = False
|
|
await setup_window(page, app)
|
|
|
|
if not page.web:
|
|
try:
|
|
app.tray_manager = TrayManager(app)
|
|
logger.info("Tray manager initialized successfully")
|
|
except Exception as e:
|
|
logger.error(f"Failed to initialize tray manager: {e}")
|
|
|
|
theme_mode = app.settings.user_config.get("theme_mode", "light")
|
|
if theme_mode == "dark":
|
|
page.theme_mode = ft.ThemeMode.DARK
|
|
else:
|
|
page.theme_mode = ft.ThemeMode.LIGHT
|
|
|
|
save_progress_overlay = SaveProgressOverlay(app)
|
|
page.overlay.append(save_progress_overlay.overlay)
|
|
|
|
async def load_app():
|
|
if page.web:
|
|
setup_responsive_layout(page, app)
|
|
page.on_resize = handle_page_resize(page, app)
|
|
page.on_disconnect = handle_disconnect(page, app)
|
|
|
|
page.add(app.complete_page)
|
|
|
|
page.on_route_change = handle_route_change(page, app)
|
|
page.window.prevent_close = True
|
|
page.window.on_event = handle_window_event(page, app, save_progress_overlay)
|
|
if page.web:
|
|
global global_state
|
|
if not global_state.periodic_tasks_started:
|
|
global_state.periodic_tasks_started = True
|
|
logger.info("Starting periodic tasks for the first time in web mode")
|
|
page.run_task(app.start_periodic_tasks)
|
|
else:
|
|
logger.info("Periodic tasks already running in web mode, skipping initialization")
|
|
else:
|
|
logger.info("Starting periodic tasks in desktop mode")
|
|
page.run_task(app.start_periodic_tasks)
|
|
|
|
if page.platform.value == "windows":
|
|
if hasattr(app, "tray_manager"):
|
|
try:
|
|
app.tray_manager.start(page)
|
|
except Exception as err:
|
|
logger.error(f"Failed to start tray manager: {err}")
|
|
|
|
page.update()
|
|
|
|
if page.route in ["/", ""]:
|
|
last_route = app.settings.user_config.get("last_route", "/home")
|
|
logger.info(f"Restored last route: {last_route}")
|
|
await page.push_route(last_route)
|
|
|
|
if page.web:
|
|
page.run_task(app.switch_page, page.route[1:])
|
|
|
|
if page.web:
|
|
auth_manager = AuthManager(app)
|
|
app.auth_manager = auth_manager
|
|
await auth_manager.initialize()
|
|
|
|
login_required = app.settings.get_config_value("login_required", False)
|
|
|
|
if login_required:
|
|
session_token = await page.shared_preferences.get("session_token")
|
|
if not session_token or not auth_manager.validate_session(session_token):
|
|
|
|
async def on_login_success(token):
|
|
_session_info = auth_manager.active_sessions.get(token, {})
|
|
app.current_username = _session_info.get("username")
|
|
|
|
page.controls.clear()
|
|
await load_app()
|
|
|
|
page.controls.clear()
|
|
|
|
login_page = LoginPage(page, auth_manager, on_login_success)
|
|
page.add(login_page.get_view())
|
|
return
|
|
else:
|
|
session_info = auth_manager.active_sessions.get(session_token, {})
|
|
app.current_username = session_info.get("username")
|
|
else:
|
|
app.current_username = "admin"
|
|
|
|
await load_app()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
load_dotenv()
|
|
platform = os.getenv("PLATFORM")
|
|
default_host = os.getenv("HOST", DEFAULT_HOST)
|
|
default_port = int(os.getenv("PORT", DEFAULT_PORT))
|
|
|
|
parser = argparse.ArgumentParser(description="Run the Flet app with optional web mode.")
|
|
parser.add_argument("--web", action="store_true", help="Run the app in web mode")
|
|
parser.add_argument("--host", type=str, default=default_host, help=f"Host address (default: {default_host})")
|
|
parser.add_argument("--port", type=int, default=default_port, help=f"Port number (default: {default_port})")
|
|
args = parser.parse_args()
|
|
|
|
multiprocessing.freeze_support()
|
|
if args.web or platform == "web":
|
|
logger.debug("Running in web mode on http://" + args.host + ":" + str(args.port))
|
|
ft.run(
|
|
main=main,
|
|
view=ft.AppView.WEB_BROWSER,
|
|
host=args.host,
|
|
port=args.port,
|
|
assets_dir=ASSETS_DIR,
|
|
web_renderer=ft.WebRenderer.CANVAS_KIT,
|
|
)
|
|
else:
|
|
ft.run(main=main, assets_dir=ASSETS_DIR)
|