Files
elmprodvpn/selective-vpn-gui/main_window/ui_tabs_main_mixin.py

245 lines
8.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
QFormLayout,
QGroupBox,
QHBoxLayout,
QLabel,
QLineEdit,
QPlainTextEdit,
QListView,
QPushButton,
QStackedWidget,
QStyle,
QTabWidget,
QToolButton,
QVBoxLayout,
QWidget,
QComboBox,
)
class UITabsMainMixin:
def _build_ui(self) -> None:
root = QWidget()
root_layout = QVBoxLayout(root)
root.setLayout(root_layout)
self.setCentralWidget(root)
# top bar ---------------------------------------------------------
top = QHBoxLayout()
root_layout.addLayout(top)
# клик по этому баннеру показывает whoami
self.btn_login_banner = QPushButton("AdGuard VPN: —")
self.btn_login_banner.setFlat(True)
self.btn_login_banner.setStyleSheet(
"text-align: left; border: none; color: gray;"
)
self.btn_login_banner.clicked.connect(self.on_login_banner_clicked)
top.addWidget(self.btn_login_banner, stretch=1)
self.btn_auth = QPushButton("Login")
self.btn_auth.clicked.connect(self.on_auth_button)
top.addWidget(self.btn_auth)
self.btn_refresh_all = QPushButton("Refresh all")
self.btn_refresh_all.clicked.connect(self.refresh_everything)
top.addWidget(self.btn_refresh_all)
# tabs -------------------------------------------------------------
self.tabs = QTabWidget()
root_layout.addWidget(self.tabs, stretch=1)
self._build_tab_status()
self._build_tab_vpn()
self._build_tab_singbox()
self._build_tab_multiif()
self._build_tab_routes()
self._build_tab_dns()
self._build_tab_domains()
self._build_tab_trace()
# ---------------- STATUS TAB ----------------
def _build_tab_status(self) -> None:
tab = QWidget()
layout = QVBoxLayout(tab)
grid = QFormLayout()
layout.addLayout(grid)
self.st_timestamp = QLabel("")
self.st_counts = QLabel("")
self.st_iface = QLabel("")
self.st_route = QLabel("")
self.st_routes_service = QLabel("")
self.st_smartdns_service = QLabel("")
self.st_vpn_service = QLabel("")
grid.addRow("Timestamp:", self.st_timestamp)
grid.addRow("Counts:", self.st_counts)
grid.addRow("Iface / table / mark:", self.st_iface)
grid.addRow("Policy route:", self.st_route)
grid.addRow("Routes service:", self.st_routes_service)
grid.addRow("SmartDNS:", self.st_smartdns_service)
grid.addRow("VPN service:", self.st_vpn_service)
btns = QHBoxLayout()
layout.addLayout(btns)
btn_refresh = QPushButton("Refresh")
btn_refresh.clicked.connect(self.refresh_status_tab)
btns.addWidget(btn_refresh)
btns.addStretch(1)
self.tabs.addTab(tab, "Status")
# ---------------- VPN TAB ----------------
def _build_tab_vpn(self) -> None:
tab = QWidget()
self.tab_vpn = tab # нужно, чтобы переключаться сюда из шапки
layout = QVBoxLayout(tab)
# stack: main vs login-flow page
self.vpn_stack = QStackedWidget()
layout.addWidget(self.vpn_stack, stretch=1)
# ---- main page
page_main = QWidget()
main_layout = QVBoxLayout(page_main)
# Autoconnect group
auto_group = QGroupBox("Autoconnect (AdGuardVPN autoloop)")
auto_layout = QHBoxLayout(auto_group)
self.btn_autoconnect_toggle = QPushButton("Enable autoconnect")
self.btn_autoconnect_toggle.clicked.connect(self.on_toggle_autoconnect)
auto_layout.addWidget(self.btn_autoconnect_toggle)
auto_layout.addStretch(1)
# справа текст "unit: active/inactive" с цветом
self.lbl_autoconnect_state = QLabel("unit: —")
self.lbl_autoconnect_state.setStyleSheet("color: gray;")
auto_layout.addWidget(self.lbl_autoconnect_state)
main_layout.addWidget(auto_group)
# Locations group
loc_group = QGroupBox("Location")
loc_layout = QVBoxLayout(loc_group)
loc_row = QHBoxLayout()
loc_layout.addLayout(loc_row)
self.cmb_locations = QComboBox()
# компактный popup со скроллом, а не на весь экран
self.cmb_locations.setMaxVisibleItems(12)
self.cmb_locations.setStyleSheet("combobox-popup: 0;")
self.cmb_locations.setFocusPolicy(Qt.StrongFocus)
view = QListView()
view.setUniformItemSizes(True)
self.cmb_locations.setView(view)
self.cmb_locations.activated.connect(self.on_location_activated)
self.cmb_locations.installEventFilter(self)
view.installEventFilter(self)
loc_row.addWidget(self.cmb_locations, stretch=1)
self.cmb_locations_sort = QComboBox()
self.cmb_locations_sort.addItem("Sort: Ping", "ping")
self.cmb_locations_sort.addItem("Sort: Ping (slow first)", "ping_desc")
self.cmb_locations_sort.addItem("Sort: Name", "name")
self.cmb_locations_sort.addItem("Sort: Name (Z-A)", "name_desc")
self.cmb_locations_sort.currentIndexChanged.connect(
self.on_locations_sort_changed
)
loc_row.addWidget(self.cmb_locations_sort)
self.btn_locations_refresh = QToolButton()
self.btn_locations_refresh.setAutoRaise(True)
self.btn_locations_refresh.setIcon(
self.style().standardIcon(QStyle.SP_BrowserReload)
)
self.btn_locations_refresh.setToolTip("Refresh locations now")
self.btn_locations_refresh.setCursor(Qt.PointingHandCursor)
self.btn_locations_refresh.setFocusPolicy(Qt.NoFocus)
self.btn_locations_refresh.clicked.connect(self.on_locations_refresh_click)
loc_row.addWidget(self.btn_locations_refresh)
self.lbl_locations_meta = QLabel("Locations: loading...")
self.lbl_locations_meta.setStyleSheet("color: gray;")
loc_layout.addWidget(self.lbl_locations_meta)
self.lbl_vpn_egress = QLabel("Egress: n/a")
self.lbl_vpn_egress.setStyleSheet("color: gray;")
loc_layout.addWidget(self.lbl_vpn_egress)
main_layout.addWidget(loc_group)
# Status output
self.txt_vpn = QPlainTextEdit()
self.txt_vpn.setReadOnly(True)
main_layout.addWidget(self.txt_vpn, stretch=1)
self.vpn_stack.addWidget(page_main)
# ---- login page
page_login = QWidget()
lf_layout = QVBoxLayout(page_login)
top = QHBoxLayout()
lf_layout.addLayout(top)
self.lbl_login_flow_status = QLabel("Status: —")
top.addWidget(self.lbl_login_flow_status)
self.lbl_login_flow_email = QLabel("")
self.lbl_login_flow_email.setStyleSheet("color: gray;")
top.addWidget(self.lbl_login_flow_email)
top.addStretch(1)
# URL + buttons row
row2 = QHBoxLayout()
lf_layout.addLayout(row2)
row2.addWidget(QLabel("URL:"))
self.edit_login_url = QLineEdit()
row2.addWidget(self.edit_login_url, stretch=1)
self.btn_login_open = QPushButton("Open")
self.btn_login_open.clicked.connect(self.on_login_open)
row2.addWidget(self.btn_login_open)
self.btn_login_copy = QPushButton("Copy")
self.btn_login_copy.clicked.connect(self.on_login_copy)
row2.addWidget(self.btn_login_copy)
self.btn_login_check = QPushButton("Check")
self.btn_login_check.clicked.connect(self.on_login_check)
row2.addWidget(self.btn_login_check)
self.btn_login_close = QPushButton("Cancel")
self.btn_login_close.clicked.connect(self.on_login_cancel)
row2.addWidget(self.btn_login_close)
self.btn_login_stop = QPushButton("Stop session")
self.btn_login_stop.clicked.connect(self.on_login_stop)
row2.addWidget(self.btn_login_stop)
# log text
self.txt_login_flow = QPlainTextEdit()
self.txt_login_flow.setReadOnly(True)
lf_layout.addWidget(self.txt_login_flow, stretch=1)
# bottom buttons
bottom = QHBoxLayout()
lf_layout.addLayout(bottom)
# Start login визуально убираем, но объект оставим на всякий
self.btn_login_start = QPushButton("Start login")
self.btn_login_start.clicked.connect(self.on_start_login)
self.btn_login_start.setVisible(False)
bottom.addWidget(self.btn_login_start)
btn_back = QPushButton("Back to VPN")
btn_back.clicked.connect(lambda: self._show_vpn_page("main"))
bottom.addWidget(btn_back)
bottom.addStretch(1)
self.vpn_stack.addWidget(page_login)
self.tabs.addTab(tab, "AdGuardVPN")