124 lines
3.9 KiB
Python
124 lines
3.9 KiB
Python
from __future__ import annotations
|
||
|
||
import asyncio
|
||
|
||
import flet as ft
|
||
from vpn_native_bridge import NativeBridge
|
||
|
||
from app.models import PaymentInfo
|
||
from app.screens.safe_area import safe_area
|
||
from app.screens.settings import build_settings_screen
|
||
from app.screens.vpn import build_vpn_screen
|
||
from app.screens.white_lists import build_white_lists_screen
|
||
from app.services.billing import month_key, payment_banner
|
||
from app.services.controller import RuntimeController
|
||
from app.services.settings_registry import SettingsRegistry
|
||
from app.services.state_store import StateStore
|
||
from app.theme import apply_accent
|
||
|
||
|
||
def main(page: ft.Page) -> None:
|
||
page.title = "VPN App"
|
||
page.padding = 0
|
||
page.scroll = ft.ScrollMode.AUTO
|
||
page.theme_mode = ft.ThemeMode.SYSTEM
|
||
store = StateStore()
|
||
persisted = store.load()
|
||
native_bridge = (
|
||
NativeBridge()
|
||
if page.platform in {ft.PagePlatform.ANDROID, ft.PagePlatform.ANDROID_TV}
|
||
else None
|
||
)
|
||
controller = RuntimeController(native_bridge=native_bridge)
|
||
registry = SettingsRegistry()
|
||
payment = PaymentInfo(
|
||
monthly_price_rub=int(persisted.get("monthly_price_rub", 0)),
|
||
payment_day=int(persisted.get("payment_day", 1)),
|
||
)
|
||
banner = ft.Ref[ft.Banner]()
|
||
|
||
def dismiss_payment(_: ft.ControlEvent) -> None:
|
||
state = store.load()
|
||
state["payment_banner_dismissed"] = month_key()
|
||
store.save(state)
|
||
page.close(banner.current)
|
||
|
||
def maybe_show_payment() -> None:
|
||
if payment.monthly_price_rub <= 0:
|
||
return
|
||
if persisted.get("payment_banner_dismissed") == month_key():
|
||
return
|
||
message = payment_banner(payment)
|
||
if message:
|
||
page.open(
|
||
ft.Banner(
|
||
ref=banner,
|
||
leading=ft.Icon(ft.Icons.INFO_OUTLINE),
|
||
content=ft.Text(message),
|
||
actions=[
|
||
ft.TextButton("Не показывать в этом месяце", on_click=dismiss_payment)
|
||
],
|
||
)
|
||
)
|
||
|
||
def set_theme(key: str) -> None:
|
||
apply_accent(page, key)
|
||
|
||
vpn_screen = build_vpn_screen(page, controller, registry, set_theme)
|
||
white_lists_screen = build_white_lists_screen(
|
||
page, controller, registry, lambda _: set_theme("freeturn")
|
||
)
|
||
settings_screen = build_settings_screen(page, registry)
|
||
|
||
def open_settings(_: ft.ControlEvent) -> None:
|
||
dialog = ft.AlertDialog(
|
||
modal=True,
|
||
title=ft.Text("Настройки"),
|
||
content=ft.Container(settings_screen, width=460, height=520),
|
||
actions=[ft.TextButton("Закрыть", on_click=lambda _: page.close(dialog))],
|
||
)
|
||
page.open(dialog)
|
||
|
||
def tab_changed(event: ft.ControlEvent) -> None:
|
||
index = event.control.selected_index
|
||
set_theme("freeturn" if index == 1 else "basic")
|
||
|
||
page.appbar = ft.AppBar(
|
||
title=ft.Text("VPN App"),
|
||
actions=[ft.IconButton(ft.Icons.SETTINGS_OUTLINED, on_click=open_settings)],
|
||
)
|
||
tabs = ft.Tabs(
|
||
expand=True,
|
||
selected_index=0,
|
||
tabs=[
|
||
ft.Tab(text="VPN", content=vpn_screen),
|
||
ft.Tab(text="Белые списки", content=white_lists_screen),
|
||
],
|
||
on_change=tab_changed,
|
||
)
|
||
page.add(
|
||
safe_area(
|
||
ft.Column(
|
||
[tabs],
|
||
expand=True,
|
||
)
|
||
)
|
||
)
|
||
apply_accent(page, "basic")
|
||
maybe_show_payment()
|
||
|
||
if native_bridge is not None:
|
||
async def restore_native_state() -> None:
|
||
while True:
|
||
await controller.refresh()
|
||
if controller.engine_kind.value == "freeturn":
|
||
tabs.selected_index = 1
|
||
set_theme("freeturn")
|
||
page.update()
|
||
await asyncio.sleep(2)
|
||
|
||
page.run_task(restore_native_state)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
ft.run(main)
|