forked from Support/sp-hydra-veil-gui
Merge branch 'master' of https://git.simplifiedprivacy.com/SimplifiedPrivacy/hydraveil-gui
This commit is contained in:
commit
33301b0da8
7 changed files with 264 additions and 51 deletions
|
|
@ -27,8 +27,15 @@ from gui.v2.infrastructure import orm
|
||||||
from gui.v2.infrastructure.navigator import Navigator
|
from gui.v2.infrastructure.navigator import Navigator
|
||||||
from gui.v2.infrastructure.setup_observers import setup_observers
|
from gui.v2.infrastructure.setup_observers import setup_observers
|
||||||
from gui.v2.infrastructure.connection_manager import ConnectionManager
|
from gui.v2.infrastructure.connection_manager import ConnectionManager
|
||||||
from gui.v2.infrastructure.page_registry import PRELOAD_ORDER, PRELOAD_SKIP
|
from gui.v2.infrastructure.page_registry import (
|
||||||
|
PRELOAD_ORDER,
|
||||||
|
PRELOAD_SKIP,
|
||||||
|
ASYNC_PREPARE,
|
||||||
|
REGULAR_FLOW_ONLY,
|
||||||
|
PAGE_REGISTRY,
|
||||||
|
)
|
||||||
from gui.v2.workers.worker_thread import WorkerThread
|
from gui.v2.workers.worker_thread import WorkerThread
|
||||||
|
from gui.v2.workers.page_data_worker import PageDataWorker
|
||||||
from gui.v2.ui.builders.bottom_section import create_bottom_section
|
from gui.v2.ui.builders.bottom_section import create_bottom_section
|
||||||
from gui.v2.ui.builders.top_section import create_top_section
|
from gui.v2.ui.builders.top_section import create_top_section
|
||||||
from gui.v2.ui.builders.system_tray import init_system_tray
|
from gui.v2.ui.builders.system_tray import init_system_tray
|
||||||
|
|
@ -49,6 +56,7 @@ from gui.v2.actions.flags import (
|
||||||
has_shown_fast_mode_prompt,
|
has_shown_fast_mode_prompt,
|
||||||
mark_fast_mode_prompt_shown,
|
mark_fast_mode_prompt_shown,
|
||||||
set_fast_mode_enabled,
|
set_fast_mode_enabled,
|
||||||
|
is_fast_registration_enabled,
|
||||||
check_first_launch,
|
check_first_launch,
|
||||||
)
|
)
|
||||||
from gui.v2.actions.profile_data import (
|
from gui.v2.actions.profile_data import (
|
||||||
|
|
@ -174,6 +182,10 @@ class CustomWindow(QMainWindow):
|
||||||
self._preload_done = 0
|
self._preload_done = 0
|
||||||
self._preload_failed = 0
|
self._preload_failed = 0
|
||||||
self._preload_skipped_runtime = 0
|
self._preload_skipped_runtime = 0
|
||||||
|
self._preload_dispatched = 0
|
||||||
|
self._preload_inflight = 0
|
||||||
|
self._preload_workers = {}
|
||||||
|
self._preload_summary_emitted = False
|
||||||
self._preload_t_start = 0.0
|
self._preload_t_start = 0.0
|
||||||
self._preload_timer = QTimer(self)
|
self._preload_timer = QTimer(self)
|
||||||
self._preload_timer.setSingleShot(True)
|
self._preload_timer.setSingleShot(True)
|
||||||
|
|
@ -206,15 +218,26 @@ class CustomWindow(QMainWindow):
|
||||||
def _start_background_preload(self):
|
def _start_background_preload(self):
|
||||||
import time
|
import time
|
||||||
self._preload_queue = [n for n in PRELOAD_ORDER if n not in PRELOAD_SKIP]
|
self._preload_queue = [n for n in PRELOAD_ORDER if n not in PRELOAD_SKIP]
|
||||||
|
fast_mode = is_fast_registration_enabled(self.gui_config_file)
|
||||||
|
skipped_regular = []
|
||||||
|
if fast_mode:
|
||||||
|
skipped_regular = [n for n in self._preload_queue if n in REGULAR_FLOW_ONLY]
|
||||||
|
self._preload_queue = [n for n in self._preload_queue if n not in REGULAR_FLOW_ONLY]
|
||||||
self._preload_total = len(self._preload_queue)
|
self._preload_total = len(self._preload_queue)
|
||||||
self._preload_done = 0
|
self._preload_done = 0
|
||||||
self._preload_failed = 0
|
self._preload_failed = 0
|
||||||
self._preload_skipped_runtime = 0
|
self._preload_skipped_runtime = 0
|
||||||
|
self._preload_dispatched = 0
|
||||||
|
self._preload_inflight = 0
|
||||||
|
self._preload_summary_emitted = False
|
||||||
self._preload_t_start = time.perf_counter()
|
self._preload_t_start = time.perf_counter()
|
||||||
print(f"[preload] ============================================================", flush=True)
|
print(f"[preload] ============================================================", flush=True)
|
||||||
print(f"[preload] starting background preload: {self._preload_total} pages queued", flush=True)
|
print(f"[preload] starting background preload: {self._preload_total} pages queued", flush=True)
|
||||||
print(f"[preload] order : {', '.join(self._preload_queue)}", flush=True)
|
print(f"[preload] order : {', '.join(self._preload_queue)}", flush=True)
|
||||||
print(f"[preload] skipped : {', '.join(sorted(PRELOAD_SKIP))} (unsafe init)", flush=True)
|
print(f"[preload] skipped : {', '.join(sorted(PRELOAD_SKIP))} (unsafe init)", flush=True)
|
||||||
|
if fast_mode:
|
||||||
|
print(f"[preload] fastmode: ON -> skipping regular-flow pages: "
|
||||||
|
f"{', '.join(skipped_regular) if skipped_regular else '(none)'}", flush=True)
|
||||||
print(f"[preload] gap : 250 ms between loads, 700 ms initial delay", flush=True)
|
print(f"[preload] gap : 250 ms between loads, 700 ms initial delay", flush=True)
|
||||||
print(f"[preload] ============================================================", flush=True)
|
print(f"[preload] ============================================================", flush=True)
|
||||||
self._preload_timer.start(700)
|
self._preload_timer.start(700)
|
||||||
|
|
@ -225,11 +248,15 @@ class CustomWindow(QMainWindow):
|
||||||
self._preload_skipped_runtime += 1
|
self._preload_skipped_runtime += 1
|
||||||
print(f"[preload] {skipped:30s} SKIP (user navigated here first)", flush=True)
|
print(f"[preload] {skipped:30s} SKIP (user navigated here first)", flush=True)
|
||||||
if not self._preload_queue:
|
if not self._preload_queue:
|
||||||
self._emit_preload_summary()
|
self._maybe_emit_preload_summary()
|
||||||
return
|
return
|
||||||
idx = self._preload_done + self._preload_failed + 1
|
self._preload_dispatched += 1
|
||||||
|
idx = self._preload_dispatched
|
||||||
name = self._preload_queue.pop(0)
|
name = self._preload_queue.pop(0)
|
||||||
print(f"[preload] ---- {idx}/{self._preload_total} ----", flush=True)
|
print(f"[preload] ---- {idx}/{self._preload_total} ----", flush=True)
|
||||||
|
if name in ASYNC_PREPARE:
|
||||||
|
self._dispatch_async_preload(name)
|
||||||
|
else:
|
||||||
ok = self.navigator.preload(name)
|
ok = self.navigator.preload(name)
|
||||||
if ok:
|
if ok:
|
||||||
self._preload_done += 1
|
self._preload_done += 1
|
||||||
|
|
@ -238,6 +265,56 @@ class CustomWindow(QMainWindow):
|
||||||
if self._preload_queue:
|
if self._preload_queue:
|
||||||
self._preload_timer.start(250)
|
self._preload_timer.start(250)
|
||||||
else:
|
else:
|
||||||
|
self._maybe_emit_preload_summary()
|
||||||
|
|
||||||
|
def _dispatch_async_preload(self, name):
|
||||||
|
module_path, class_name = PAGE_REGISTRY[name]
|
||||||
|
print(f"[preload] {name:30s} ASYNC {module_path}.{class_name}", flush=True)
|
||||||
|
worker = PageDataWorker(name, module_path, class_name, self)
|
||||||
|
worker.data_ready.connect(self._on_preload_data_ready)
|
||||||
|
worker.failed.connect(self._on_preload_failed)
|
||||||
|
worker.finished.connect(lambda n=name: self._cleanup_preload_worker(n))
|
||||||
|
self._preload_workers[name] = worker
|
||||||
|
self._preload_inflight += 1
|
||||||
|
worker.start()
|
||||||
|
|
||||||
|
def _on_preload_data_ready(self, name, payload):
|
||||||
|
self._preload_inflight -= 1
|
||||||
|
if name in self.navigator._instances:
|
||||||
|
print(f"[preload] {name:30s} SKIP (already cached, async result dropped)", flush=True)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
page = self.navigator._instantiate(name, prepared=payload)
|
||||||
|
self.navigator.register_instance(name, page)
|
||||||
|
self._preload_done += 1
|
||||||
|
print(f"[preload] {name:30s} OK (async, cached={len(self.navigator._instances)}, "
|
||||||
|
f"stack_size={self.page_stack.count()})", flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
self._preload_failed += 1
|
||||||
|
print(f"[preload] {name:30s} FAIL (async build) {type(e).__name__}: {e}", flush=True)
|
||||||
|
self._maybe_emit_preload_summary()
|
||||||
|
|
||||||
|
def _on_preload_failed(self, name, error):
|
||||||
|
self._preload_inflight -= 1
|
||||||
|
print(f"[preload] {name:30s} FAIL (async prepare) {error}", flush=True)
|
||||||
|
if name not in self.navigator._instances:
|
||||||
|
ok = self.navigator.preload(name)
|
||||||
|
if ok:
|
||||||
|
self._preload_done += 1
|
||||||
|
else:
|
||||||
|
self._preload_failed += 1
|
||||||
|
self._maybe_emit_preload_summary()
|
||||||
|
|
||||||
|
def _cleanup_preload_worker(self, name):
|
||||||
|
worker = self._preload_workers.pop(name, None)
|
||||||
|
if worker is not None:
|
||||||
|
worker.deleteLater()
|
||||||
|
|
||||||
|
def _maybe_emit_preload_summary(self):
|
||||||
|
if self._preload_summary_emitted:
|
||||||
|
return
|
||||||
|
if not self._preload_queue and self._preload_inflight == 0:
|
||||||
|
self._preload_summary_emitted = True
|
||||||
self._emit_preload_summary()
|
self._emit_preload_summary()
|
||||||
|
|
||||||
def _emit_preload_summary(self):
|
def _emit_preload_summary(self):
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,13 @@ def mark_fast_mode_prompt_shown(gui_config_file):
|
||||||
save_gui_config(gui_config_file, config)
|
save_gui_config(gui_config_file, config)
|
||||||
|
|
||||||
|
|
||||||
|
def is_fast_registration_enabled(gui_config_file):
|
||||||
|
config = load_gui_config(gui_config_file)
|
||||||
|
if not config:
|
||||||
|
return False
|
||||||
|
return config.get("registrations", {}).get("fast_registration_enabled", False)
|
||||||
|
|
||||||
|
|
||||||
def set_fast_mode_enabled(gui_config_file, enabled):
|
def set_fast_mode_enabled(gui_config_file, enabled):
|
||||||
config = load_gui_config(gui_config_file)
|
config = load_gui_config(gui_config_file)
|
||||||
if config is None:
|
if config is None:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import importlib
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from gui.v2.infrastructure.page_registry import PAGE_REGISTRY
|
from gui.v2.infrastructure.page_registry import PAGE_REGISTRY, ASYNC_PREPARE
|
||||||
|
|
||||||
|
|
||||||
class Navigator:
|
class Navigator:
|
||||||
|
|
@ -11,18 +11,29 @@ class Navigator:
|
||||||
self.custom_window = custom_window
|
self.custom_window = custom_window
|
||||||
self._instances = {}
|
self._instances = {}
|
||||||
|
|
||||||
|
def get_class(self, name):
|
||||||
|
module_path, class_name = PAGE_REGISTRY[name]
|
||||||
|
module = importlib.import_module(module_path)
|
||||||
|
return getattr(module, class_name)
|
||||||
|
|
||||||
|
def _instantiate(self, name, prepared=None):
|
||||||
|
cls = self.get_class(name)
|
||||||
|
if name in ASYNC_PREPARE:
|
||||||
|
return cls(self.page_stack, self.custom_window, prepared=prepared)
|
||||||
|
return cls(self.page_stack, self.custom_window)
|
||||||
|
|
||||||
|
def register_instance(self, name, page):
|
||||||
|
self.page_stack.addWidget(page)
|
||||||
|
self._instances[name] = page
|
||||||
|
|
||||||
def navigate(self, name):
|
def navigate(self, name):
|
||||||
page = self._instances.get(name)
|
page = self._instances.get(name)
|
||||||
if page is None:
|
if page is None:
|
||||||
if name not in PAGE_REGISTRY:
|
if name not in PAGE_REGISTRY:
|
||||||
self._warn_not_migrated(name)
|
self._warn_not_migrated(name)
|
||||||
return
|
return
|
||||||
module_path, class_name = PAGE_REGISTRY[name]
|
page = self._instantiate(name)
|
||||||
module = importlib.import_module(module_path)
|
self.register_instance(name, page)
|
||||||
cls = getattr(module, class_name)
|
|
||||||
page = cls(self.page_stack, self.custom_window)
|
|
||||||
self.page_stack.addWidget(page)
|
|
||||||
self._instances[name] = page
|
|
||||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(page))
|
self.page_stack.setCurrentIndex(self.page_stack.indexOf(page))
|
||||||
|
|
||||||
def preload(self, name):
|
def preload(self, name):
|
||||||
|
|
@ -36,11 +47,8 @@ class Navigator:
|
||||||
print(f"[preload] {name:30s} LOAD {module_path}.{class_name}", flush=True)
|
print(f"[preload] {name:30s} LOAD {module_path}.{class_name}", flush=True)
|
||||||
t0 = time.perf_counter()
|
t0 = time.perf_counter()
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module(module_path)
|
page = self._instantiate(name)
|
||||||
cls = getattr(module, class_name)
|
self.register_instance(name, page)
|
||||||
page = cls(self.page_stack, self.custom_window)
|
|
||||||
self.page_stack.addWidget(page)
|
|
||||||
self._instances[name] = page
|
|
||||||
dt_ms = (time.perf_counter() - t0) * 1000.0
|
dt_ms = (time.perf_counter() - t0) * 1000.0
|
||||||
print(f"[preload] {name:30s} OK ({dt_ms:6.1f} ms, "
|
print(f"[preload] {name:30s} OK ({dt_ms:6.1f} ms, "
|
||||||
f"cached={len(self._instances)}, stack_size={self.page_stack.count()})",
|
f"cached={len(self._instances)}, stack_size={self.page_stack.count()})",
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,23 @@ PRELOAD_SKIP = {
|
||||||
"ticket_prep",
|
"ticket_prep",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASYNC_PREPARE = {
|
||||||
|
"settings",
|
||||||
|
}
|
||||||
|
|
||||||
|
REGULAR_FLOW_ONLY = {
|
||||||
|
"protocol",
|
||||||
|
"location",
|
||||||
|
"hidetor",
|
||||||
|
"residential",
|
||||||
|
"tor",
|
||||||
|
"connection",
|
||||||
|
"screen",
|
||||||
|
"browser",
|
||||||
|
"wireguard",
|
||||||
|
"sync_screen",
|
||||||
|
}
|
||||||
|
|
||||||
PRELOAD_ORDER = [
|
PRELOAD_ORDER = [
|
||||||
"settings",
|
"settings",
|
||||||
"editor",
|
"editor",
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ class Page(QWidget):
|
||||||
self.selected_residential = []
|
self.selected_residential = []
|
||||||
self.buttons = []
|
self.buttons = []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def prepare_data(custom_window):
|
||||||
|
return None
|
||||||
|
|
||||||
def add_selected_profile(self, profile):
|
def add_selected_profile(self, profile):
|
||||||
self.selected_profiles.clear()
|
self.selected_profiles.clear()
|
||||||
self.selected_wireguard.clear()
|
self.selected_wireguard.clear()
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ from core.errors.logger import logger as core_logger
|
||||||
|
|
||||||
from gui.v2.actions.key_interpretation import interpret_key_results
|
from gui.v2.actions.key_interpretation import interpret_key_results
|
||||||
from gui.v2.actions.profile_order import normalize_profile_order
|
from gui.v2.actions.profile_order import normalize_profile_order
|
||||||
|
from gui.v2.infrastructure.page_registry import PAGE_REGISTRY
|
||||||
from gui.v2.infrastructure.setup_observers import ticket_observer
|
from gui.v2.infrastructure.setup_observers import ticket_observer
|
||||||
from gui.v2.ui.pages.Page import Page
|
from gui.v2.ui.pages.Page import Page
|
||||||
from gui.v2.ui.popups.confirmation_popup import ConfirmationPopup
|
from gui.v2.ui.popups.confirmation_popup import ConfirmationPopup
|
||||||
|
|
@ -46,17 +47,21 @@ from gui.v2.ui.styles.styles import (
|
||||||
)
|
)
|
||||||
from gui.v2.ui.widgets.clickable_label import ClickableValueLabel
|
from gui.v2.ui.widgets.clickable_label import ClickableValueLabel
|
||||||
from gui.v2.ui.widgets.terminal_widget import TerminalWidget
|
from gui.v2.ui.widgets.terminal_widget import TerminalWidget
|
||||||
|
from gui.v2.workers.page_data_worker import PageDataWorker
|
||||||
from gui.v2.workers.ticketing_worker_thread import TicketingWorkerThread
|
from gui.v2.workers.ticketing_worker_thread import TicketingWorkerThread
|
||||||
from gui.v2.workers.worker_thread import WorkerThread
|
from gui.v2.workers.worker_thread import WorkerThread
|
||||||
|
|
||||||
|
|
||||||
class Settings(Page):
|
class Settings(Page):
|
||||||
def __init__(self, page_stack, main_window, parent=None):
|
def __init__(self, page_stack, main_window, parent=None, prepared=None):
|
||||||
super().__init__("Settings", page_stack, main_window, parent)
|
super().__init__("Settings", page_stack, main_window, parent)
|
||||||
self.font_style = f"font-family: '{self.custom_window.open_sans_family}';"
|
self.font_style = f"font-family: '{self.custom_window.open_sans_family}';"
|
||||||
|
|
||||||
self.update_status = main_window
|
self.update_status = main_window
|
||||||
self.update_logging = main_window
|
self.update_logging = main_window
|
||||||
|
self._prepared = prepared if prepared is not None else self.prepare_data(main_window)
|
||||||
|
self._settings_refresh_seq = 0
|
||||||
|
self._settings_workers = set()
|
||||||
self.button_reverse.setVisible(True)
|
self.button_reverse.setVisible(True)
|
||||||
self.button_reverse.setEnabled(True)
|
self.button_reverse.setEnabled(True)
|
||||||
self.button_reverse.clicked.connect(self.reverse)
|
self.button_reverse.clicked.connect(self.reverse)
|
||||||
|
|
@ -64,6 +69,52 @@ class Settings(Page):
|
||||||
self.title.setText("Settings")
|
self.title.setText("Settings")
|
||||||
self.setup_ui()
|
self.setup_ui()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def prepare_data(custom_window):
|
||||||
|
profiles = ProfileController.get_all()
|
||||||
|
profile_order = normalize_profile_order(
|
||||||
|
getattr(custom_window, 'gui_config_file', None), profiles.keys())
|
||||||
|
current_connection = custom_window.get_current_connection()
|
||||||
|
try:
|
||||||
|
endpoint_verification_enabled = ConfigurationController.get_endpoint_verification_enabled()
|
||||||
|
except Exception:
|
||||||
|
endpoint_verification_enabled = False
|
||||||
|
return {
|
||||||
|
"profiles": profiles,
|
||||||
|
"profile_order": profile_order,
|
||||||
|
"current_connection": current_connection,
|
||||||
|
"endpoint_verification_enabled": endpoint_verification_enabled,
|
||||||
|
"systemwide_enabled": Settings._read_systemwide_enabled(),
|
||||||
|
"bwrap_enabled": Settings._read_bwrap_enabled(),
|
||||||
|
"gui_config": custom_window._load_gui_config(),
|
||||||
|
"ticket_failure": custom_window.get_ticket_verification_failure(),
|
||||||
|
}
|
||||||
|
|
||||||
|
def _prepared_value(self, key, loader):
|
||||||
|
if self._prepared is not None and key in self._prepared:
|
||||||
|
return self._prepared[key]
|
||||||
|
return loader()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _read_systemwide_enabled():
|
||||||
|
try:
|
||||||
|
privilege_policy = PolicyController.get('privilege')
|
||||||
|
if privilege_policy is not None:
|
||||||
|
return PolicyController.is_instated(privilege_policy)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _read_bwrap_enabled():
|
||||||
|
try:
|
||||||
|
capability_policy = PolicyController.get('capability')
|
||||||
|
if capability_policy is not None:
|
||||||
|
return PolicyController.is_instated(capability_policy)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
main_container = QWidget(self)
|
main_container = QWidget(self)
|
||||||
main_container.setGeometry(0, 0, 800, 520)
|
main_container.setGeometry(0, 0, 800, 520)
|
||||||
|
|
@ -198,11 +249,13 @@ class Settings(Page):
|
||||||
return page
|
return page
|
||||||
|
|
||||||
def create_delete_profile_buttons(self):
|
def create_delete_profile_buttons(self):
|
||||||
profiles = ProfileController.get_all()
|
profiles = self._prepared_value("profiles", ProfileController.get_all)
|
||||||
|
|
||||||
profile_ids = normalize_profile_order(
|
profile_ids = self._prepared_value(
|
||||||
|
"profile_order",
|
||||||
|
lambda: normalize_profile_order(
|
||||||
getattr(self.update_status, 'gui_config_file', None),
|
getattr(self.update_status, 'gui_config_file', None),
|
||||||
profiles.keys())
|
profiles.keys()))
|
||||||
|
|
||||||
for index, profile_id in enumerate(profile_ids):
|
for index, profile_id in enumerate(profile_ids):
|
||||||
profile = profiles[profile_id]
|
profile = profiles[profile_id]
|
||||||
|
|
@ -600,7 +653,7 @@ class Settings(Page):
|
||||||
|
|
||||||
def update_debug_profile_list(self):
|
def update_debug_profile_list(self):
|
||||||
self.debug_profile_selector.clear()
|
self.debug_profile_selector.clear()
|
||||||
profiles = ProfileController.get_all()
|
profiles = self._prepared_value("profiles", ProfileController.get_all)
|
||||||
system_profiles = {pid: profile for pid, profile in profiles.items(
|
system_profiles = {pid: profile for pid, profile in profiles.items(
|
||||||
) if isinstance(profile, SystemProfile)}
|
) if isinstance(profile, SystemProfile)}
|
||||||
|
|
||||||
|
|
@ -904,7 +957,7 @@ class Settings(Page):
|
||||||
|
|
||||||
self.profile_selector = QComboBox()
|
self.profile_selector = QComboBox()
|
||||||
self.profile_selector.setStyleSheet(self.get_combobox_style())
|
self.profile_selector.setStyleSheet(self.get_combobox_style())
|
||||||
profiles = ProfileController.get_all()
|
profiles = self._prepared_value("profiles", ProfileController.get_all)
|
||||||
if profiles:
|
if profiles:
|
||||||
for profile_id, profile in profiles.items():
|
for profile_id, profile in profiles.items():
|
||||||
self.profile_selector.addItem(
|
self.profile_selector.addItem(
|
||||||
|
|
@ -1039,7 +1092,7 @@ class Settings(Page):
|
||||||
self.verification_profile_selector = QComboBox()
|
self.verification_profile_selector = QComboBox()
|
||||||
self.verification_profile_selector.setStyleSheet(
|
self.verification_profile_selector.setStyleSheet(
|
||||||
self.get_combobox_style())
|
self.get_combobox_style())
|
||||||
profiles = ProfileController.get_all()
|
profiles = self._prepared_value("profiles", ProfileController.get_all)
|
||||||
if profiles:
|
if profiles:
|
||||||
for profile_id, profile in profiles.items():
|
for profile_id, profile in profiles.items():
|
||||||
self.verification_profile_selector.addItem(
|
self.verification_profile_selector.addItem(
|
||||||
|
|
@ -1134,7 +1187,9 @@ class Settings(Page):
|
||||||
self.endpoint_verification_checkbox = QCheckBox(page)
|
self.endpoint_verification_checkbox = QCheckBox(page)
|
||||||
self.endpoint_verification_checkbox.setGeometry(180, 415, 30, 30)
|
self.endpoint_verification_checkbox.setGeometry(180, 415, 30, 30)
|
||||||
self.endpoint_verification_checkbox.setChecked(
|
self.endpoint_verification_checkbox.setChecked(
|
||||||
ConfigurationController.get_endpoint_verification_enabled())
|
self._prepared_value(
|
||||||
|
"endpoint_verification_enabled",
|
||||||
|
ConfigurationController.get_endpoint_verification_enabled))
|
||||||
self.endpoint_verification_checkbox.setStyleSheet(
|
self.endpoint_verification_checkbox.setStyleSheet(
|
||||||
self.get_checkbox_style())
|
self.get_checkbox_style())
|
||||||
self.endpoint_verification_checkbox.show()
|
self.endpoint_verification_checkbox.show()
|
||||||
|
|
@ -1295,6 +1350,31 @@ class Settings(Page):
|
||||||
|
|
||||||
def showEvent(self, event):
|
def showEvent(self, event):
|
||||||
super().showEvent(event)
|
super().showEvent(event)
|
||||||
|
self._settings_refresh_seq += 1
|
||||||
|
seq = self._settings_refresh_seq
|
||||||
|
module_path, class_name = PAGE_REGISTRY["settings"]
|
||||||
|
worker = PageDataWorker(
|
||||||
|
"settings", module_path, class_name, self.custom_window)
|
||||||
|
worker.data_ready.connect(
|
||||||
|
lambda name, payload, s=seq: self._on_settings_data_ready(payload, s))
|
||||||
|
worker.failed.connect(
|
||||||
|
lambda name, error: self._on_settings_data_failed(error))
|
||||||
|
worker.finished.connect(
|
||||||
|
lambda w=worker: self._cleanup_settings_worker(w))
|
||||||
|
self._settings_workers.add(worker)
|
||||||
|
worker.start()
|
||||||
|
|
||||||
|
def _on_settings_data_failed(self, error):
|
||||||
|
core_logger.warning(f"Settings data refresh failed: {error}")
|
||||||
|
|
||||||
|
def _cleanup_settings_worker(self, worker):
|
||||||
|
self._settings_workers.discard(worker)
|
||||||
|
worker.deleteLater()
|
||||||
|
|
||||||
|
def _on_settings_data_ready(self, payload, seq):
|
||||||
|
if seq != self._settings_refresh_seq:
|
||||||
|
return
|
||||||
|
self._prepared = payload
|
||||||
|
|
||||||
current_index = self.content_layout.currentIndex()
|
current_index = self.content_layout.currentIndex()
|
||||||
|
|
||||||
|
|
@ -1407,7 +1487,7 @@ class Settings(Page):
|
||||||
layout = QGridLayout(widget)
|
layout = QGridLayout(widget)
|
||||||
layout.setSpacing(10)
|
layout.setSpacing(10)
|
||||||
|
|
||||||
profiles = ProfileController.get_all()
|
profiles = self._prepared_value("profiles", ProfileController.get_all)
|
||||||
total_profiles = len(profiles)
|
total_profiles = len(profiles)
|
||||||
session_profiles = sum(1 for p in profiles.values()
|
session_profiles = sum(1 for p in profiles.values()
|
||||||
if isinstance(p, SessionProfile))
|
if isinstance(p, SessionProfile))
|
||||||
|
|
@ -1439,7 +1519,8 @@ class Settings(Page):
|
||||||
|
|
||||||
config_path = Constants.HV_CONFIG_HOME
|
config_path = Constants.HV_CONFIG_HOME
|
||||||
|
|
||||||
current_connection = self.update_status.get_current_connection()
|
current_connection = self._prepared_value(
|
||||||
|
"current_connection", self.update_status.get_current_connection)
|
||||||
|
|
||||||
if current_connection is not None:
|
if current_connection is not None:
|
||||||
current_connection = current_connection.capitalize()
|
current_connection = current_connection.capitalize()
|
||||||
|
|
@ -1697,7 +1778,8 @@ class Settings(Page):
|
||||||
inventory_layout.addWidget(self.refresh_tickets_button)
|
inventory_layout.addWidget(self.refresh_tickets_button)
|
||||||
layout.addWidget(inventory_group)
|
layout.addWidget(inventory_group)
|
||||||
|
|
||||||
saved_failure = self.update_status.get_ticket_verification_failure()
|
saved_failure = self._prepared_value(
|
||||||
|
"ticket_failure", self.update_status.get_ticket_verification_failure)
|
||||||
has_failure = saved_failure is not None
|
has_failure = saved_failure is not None
|
||||||
|
|
||||||
recovery_group = QGroupBox("Verification Failure Recovery")
|
recovery_group = QGroupBox("Verification Failure Recovery")
|
||||||
|
|
@ -1954,7 +2036,8 @@ class Settings(Page):
|
||||||
|
|
||||||
def load_logs_settings(self) -> None:
|
def load_logs_settings(self) -> None:
|
||||||
try:
|
try:
|
||||||
config = self.update_status._load_gui_config()
|
config = self._prepared_value(
|
||||||
|
"gui_config", self.update_status._load_gui_config)
|
||||||
if config and "logging" in config:
|
if config and "logging" in config:
|
||||||
self.enable_gui_logging.setChecked(
|
self.enable_gui_logging.setChecked(
|
||||||
config["logging"]["gui_logging_enabled"])
|
config["logging"]["gui_logging_enabled"])
|
||||||
|
|
@ -2103,7 +2186,8 @@ class Settings(Page):
|
||||||
layout.addLayout(button_layout)
|
layout.addLayout(button_layout)
|
||||||
|
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
self.load_systemwide_settings()
|
self.load_systemwide_settings(
|
||||||
|
self._prepared_value("systemwide_enabled", self._read_systemwide_enabled))
|
||||||
return page
|
return page
|
||||||
|
|
||||||
def create_bwrap_page(self):
|
def create_bwrap_page(self):
|
||||||
|
|
@ -2155,17 +2239,13 @@ class Settings(Page):
|
||||||
layout.addLayout(button_layout)
|
layout.addLayout(button_layout)
|
||||||
|
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
self.load_bwrap_settings()
|
self.load_bwrap_settings(
|
||||||
|
self._prepared_value("bwrap_enabled", self._read_bwrap_enabled))
|
||||||
return page
|
return page
|
||||||
|
|
||||||
def load_systemwide_settings(self):
|
def load_systemwide_settings(self, enabled=None):
|
||||||
enabled = False
|
if enabled is None:
|
||||||
try:
|
enabled = self._read_systemwide_enabled()
|
||||||
privilege_policy = PolicyController.get('privilege')
|
|
||||||
if privilege_policy is not None:
|
|
||||||
enabled = PolicyController.is_instated(privilege_policy)
|
|
||||||
except Exception:
|
|
||||||
enabled = False
|
|
||||||
self.systemwide_toggle.setChecked(enabled)
|
self.systemwide_toggle.setChecked(enabled)
|
||||||
if enabled:
|
if enabled:
|
||||||
self.systemwide_status_value.setText("Enabled")
|
self.systemwide_status_value.setText("Enabled")
|
||||||
|
|
@ -2202,14 +2282,9 @@ class Settings(Page):
|
||||||
self.systemwide_status_value.setStyleSheet(
|
self.systemwide_status_value.setStyleSheet(
|
||||||
f"color: red; font-size: 14px; {self.font_style}")
|
f"color: red; font-size: 14px; {self.font_style}")
|
||||||
|
|
||||||
def load_bwrap_settings(self):
|
def load_bwrap_settings(self, enabled=None):
|
||||||
enabled = False
|
if enabled is None:
|
||||||
try:
|
enabled = self._read_bwrap_enabled()
|
||||||
capability_policy = PolicyController.get('capability')
|
|
||||||
if capability_policy is not None:
|
|
||||||
enabled = PolicyController.is_instated(capability_policy)
|
|
||||||
except Exception:
|
|
||||||
enabled = False
|
|
||||||
self.bwrap_toggle.setChecked(enabled)
|
self.bwrap_toggle.setChecked(enabled)
|
||||||
if enabled:
|
if enabled:
|
||||||
self.bwrap_status_value.setText("Enabled")
|
self.bwrap_status_value.setText("Enabled")
|
||||||
|
|
@ -2248,7 +2323,8 @@ class Settings(Page):
|
||||||
|
|
||||||
def load_registrations_settings(self) -> None:
|
def load_registrations_settings(self) -> None:
|
||||||
try:
|
try:
|
||||||
config = self.update_status._load_gui_config()
|
config = self._prepared_value(
|
||||||
|
"gui_config", self.update_status._load_gui_config)
|
||||||
if config and "registrations" in config:
|
if config and "registrations" in config:
|
||||||
registrations = config["registrations"]
|
registrations = config["registrations"]
|
||||||
auto_sync = registrations.get("auto_sync_enabled", False)
|
auto_sync = registrations.get("auto_sync_enabled", False)
|
||||||
|
|
|
||||||
24
gui/v2/workers/page_data_worker.py
Executable file
24
gui/v2/workers/page_data_worker.py
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
from PyQt6.QtCore import QThread, pyqtSignal
|
||||||
|
|
||||||
|
|
||||||
|
class PageDataWorker(QThread):
|
||||||
|
data_ready = pyqtSignal(str, object)
|
||||||
|
failed = pyqtSignal(str, str)
|
||||||
|
|
||||||
|
def __init__(self, name, module_path, class_name, custom_window):
|
||||||
|
super().__init__()
|
||||||
|
self.name = name
|
||||||
|
self.module_path = module_path
|
||||||
|
self.class_name = class_name
|
||||||
|
self.custom_window = custom_window
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
module = importlib.import_module(self.module_path)
|
||||||
|
cls = getattr(module, self.class_name)
|
||||||
|
payload = cls.prepare_data(self.custom_window)
|
||||||
|
self.data_ready.emit(self.name, payload)
|
||||||
|
except Exception as error:
|
||||||
|
self.failed.emit(self.name, f"{type(error).__name__}: {error}")
|
||||||
Loading…
Reference in a new issue