from __future__ import annotations import flet as ft import flet_webview as fwv from app.models import FreeTurnProfile from app.screens.components import connection_card, section_title from app.services.controller import RuntimeController from app.services.settings_registry import SettingsRegistry from app.theme import card PRESET_TEXT = { 1: "4/4 · для сообщений", 2: "8/4 · для простого интернет-сёрфинга", 3: "12/6 · для видео в невысоком качестве", 4: "24/6 · для всего · ультра скорость, повышенная нагрузка", } CAPTCHA_ENTRY_URL = "https://vk.com" def build_white_lists_screen( page: ft.Page, controller: RuntimeController, registry: SettingsRegistry, on_theme: callable, ) -> ft.Control: content = ft.Column(expand=True, scroll=ft.ScrollMode.AUTO, spacing=14) async def slide(event: ft.ControlEvent) -> None: if float(event.control.value or 0) < 0.8: return try: controller.select_freeturn() await controller.connect() except Exception as exc: controller.snapshot = controller.snapshot.model_copy( update={"state": "error", "message": controller.error_text(exc)} ) render() async def stop(_: ft.ControlEvent) -> None: await controller.stop() render() def preset_change(event: ft.ControlEvent) -> None: controller.freeturn.preset = int(round(float(event.control.value))) render() def stability_change(event: ft.ControlEvent) -> None: controller.freeturn.stability_over_load = bool(event.control.value) render() def captcha_settings() -> ft.Control: captcha_url = controller.snapshot.captcha_url or CAPTCHA_ENTRY_URL def open_captcha(_: ft.ControlEvent, in_browser: bool = False) -> None: if in_browser or controller.freeturn.captcha_always_browser: page.launch_url(captcha_url) return dialog = ft.AlertDialog( modal=True, title=ft.Text("CAPTCHA"), content=ft.Container( fwv.WebView(url=captcha_url, expand=True), width=520, height=620, ), actions=[ ft.TextButton( "Открыть в браузере", on_click=lambda _: page.launch_url(captcha_url), ), ft.TextButton("Закрыть", on_click=lambda _: page.close(dialog)), ], ) page.open(dialog) return card( ft.Column( [ ft.Text("CAPTCHA", weight=ft.FontWeight.W_600), ft.Text( "Встроенное окно доступно на Android. На desktop используйте браузер.", color=ft.Colors.OUTLINE, ), ft.Switch( label="Всегда открывать CAPTCHA в браузере", value=controller.freeturn.captcha_always_browser, on_change=lambda e: setattr( controller.freeturn, "captcha_always_browser", bool(e.control.value) ), ), ft.Row( [ ft.FilledButton( "Открыть внутри приложения", on_click=open_captcha, ), ft.OutlinedButton( "Открыть в браузере", on_click=lambda e: open_captcha(e, True), ), ] ), ], spacing=8, ) ) def render() -> None: profile: FreeTurnProfile = controller.freeturn threads, per_credential = profile.stream_settings content.controls = [ section_title("Белые списки", "FreeTurn · отдельный runtime"), connection_card(controller.snapshot.state, controller.mode, "FreeTurn", slide), card( ft.Column( [ ft.Text("Скорость", weight=ft.FontWeight.W_600), ft.Text( PRESET_TEXT[profile.preset], color=ft.Colors.ERROR if profile.preset == 4 else None, ), ft.Slider( min=1, max=4, divisions=3, value=profile.preset, label="Уровень {value}", on_change=preset_change, ), ft.Text(f"Потоки: {threads}/{per_credential}", color=ft.Colors.OUTLINE), ft.Switch( label="Повысить стабильность ценой нагрузки", value=profile.stability_over_load, disabled=profile.preset < 3, on_change=stability_change, ), ], spacing=8, ) ), captcha_settings(), ft.OutlinedButton("Остановить", icon=ft.Icons.STOP, on_click=stop), ft.Text( controller.snapshot.message or "", color=ft.Colors.ERROR if controller.snapshot.message else None, ), ] page.update() registry.register("white-lists", "Белые списки", lambda: content) controller.add_listener(render) render() return content