diff --git a/gui/__main__.py b/gui/__main__.py index 9f58b5e..9930cb3 100755 --- a/gui/__main__.py +++ b/gui/__main__.py @@ -26,6 +26,7 @@ core_logger.propagate = False from gui.v2.infrastructure.navigator import Navigator from gui.v2.infrastructure.setup_observers import setup_observers from gui.v2.infrastructure.connection_manager import ConnectionManager +from gui.v2.infrastructure.page_registry import PRELOAD_ORDER, PRELOAD_SKIP from gui.v2.workers.worker_thread import WorkerThread from gui.v2.ui.builders.bottom_section import create_bottom_section from gui.v2.ui.builders.top_section import create_top_section @@ -163,6 +164,17 @@ class CustomWindow(QMainWindow): self.check_logging() self.navigator = Navigator(self.page_stack, self) + + self._preload_queue = [] + self._preload_total = 0 + self._preload_done = 0 + self._preload_failed = 0 + self._preload_skipped_runtime = 0 + self._preload_t_start = 0.0 + self._preload_timer = QTimer(self) + self._preload_timer.setSingleShot(True) + self._preload_timer.timeout.connect(self._preload_next) + self.page_stack.currentChanged.connect(self.page_changed) self.show() @@ -185,6 +197,55 @@ class CustomWindow(QMainWindow): self.navigator.navigate("welcome") else: self.navigator.navigate("menu") + self._start_background_preload() + + def _start_background_preload(self): + import time + self._preload_queue = [n for n in PRELOAD_ORDER if n not in PRELOAD_SKIP] + self._preload_total = len(self._preload_queue) + self._preload_done = 0 + self._preload_failed = 0 + self._preload_skipped_runtime = 0 + self._preload_t_start = time.perf_counter() + print(f"[preload] ============================================================", 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] skipped : {', '.join(sorted(PRELOAD_SKIP))} (unsafe init)", flush=True) + print(f"[preload] gap : 250 ms between loads, 700 ms initial delay", flush=True) + print(f"[preload] ============================================================", flush=True) + self._preload_timer.start(700) + + def _preload_next(self): + while self._preload_queue and self._preload_queue[0] in self.navigator._instances: + skipped = self._preload_queue.pop(0) + self._preload_skipped_runtime += 1 + print(f"[preload] {skipped:30s} SKIP (user navigated here first)", flush=True) + if not self._preload_queue: + self._emit_preload_summary() + return + idx = self._preload_done + self._preload_failed + 1 + name = self._preload_queue.pop(0) + print(f"[preload] ---- {idx}/{self._preload_total} ----", flush=True) + ok = self.navigator.preload(name) + if ok: + self._preload_done += 1 + else: + self._preload_failed += 1 + if self._preload_queue: + self._preload_timer.start(250) + else: + self._emit_preload_summary() + + def _emit_preload_summary(self): + import time + total_s = time.perf_counter() - self._preload_t_start + print(f"[preload] ============================================================", flush=True) + print(f"[preload] complete: {self._preload_done} loaded, " + f"{self._preload_failed} failed, " + f"{self._preload_skipped_runtime} skipped (user beat us to it) " + f"in {total_s:.2f}s", flush=True) + print(f"[preload] cached pages now: {sorted(self.navigator._instances.keys())}", flush=True) + print(f"[preload] ============================================================", flush=True) def perform_update_check(self): from core.controllers.ClientController import ClientController diff --git a/gui/v2/infrastructure/navigator.py b/gui/v2/infrastructure/navigator.py index 9f7cbaf..140fac9 100755 --- a/gui/v2/infrastructure/navigator.py +++ b/gui/v2/infrastructure/navigator.py @@ -1,4 +1,6 @@ import importlib +import time +import traceback from gui.v2.infrastructure.page_registry import PAGE_REGISTRY @@ -23,6 +25,37 @@ class Navigator: self._instances[name] = page self.page_stack.setCurrentIndex(self.page_stack.indexOf(page)) + def preload(self, name): + if name in self._instances: + print(f"[preload] {name:30s} SKIP (already cached)", flush=True) + return False + if name not in PAGE_REGISTRY: + print(f"[preload] {name:30s} SKIP (not in registry)", flush=True) + return False + module_path, class_name = PAGE_REGISTRY[name] + print(f"[preload] {name:30s} LOAD {module_path}.{class_name}", flush=True) + t0 = time.perf_counter() + try: + module = importlib.import_module(module_path) + cls = getattr(module, class_name) + 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 + print(f"[preload] {name:30s} OK ({dt_ms:6.1f} ms, " + f"cached={len(self._instances)}, stack_size={self.page_stack.count()})", + flush=True) + return True + except Exception as e: + dt_ms = (time.perf_counter() - t0) * 1000.0 + print(f"[preload] {name:30s} FAIL ({dt_ms:6.1f} ms) " + f"{type(e).__name__}: {e}", flush=True) + traceback.print_exc() + from core.errors.logger import logger as core_logger + core_logger.warning(f"Background preload failed for '{name}': " + f"{type(e).__name__}: {e}") + return False + def get_cached(self, name): return self._instances.get(name) diff --git a/gui/v2/infrastructure/page_registry.py b/gui/v2/infrastructure/page_registry.py index 774ca6e..8ce2b06 100755 --- a/gui/v2/infrastructure/page_registry.py +++ b/gui/v2/infrastructure/page_registry.py @@ -30,3 +30,38 @@ PAGE_REGISTRY = { "fast_registration": ("gui.v2.ui.pages.fast_registration_page", "FastRegistrationPage"), "fast_mode_prompt": ("gui.v2.ui.pages.fast_mode_prompt_page", "FastModePromptPage"), } + +PRELOAD_SKIP = { + "blank", + "welcome", + "payment_confirmed", + "ticket_prep", +} + +PRELOAD_ORDER = [ + "settings", + "editor", + "ticket_or_billing_choice", + "payment_details", + "plan_picker", + "ticket_crypto_picker", + "duration_selection", + "currency_selection", + "policy_suggestion", + "systemwide_prompt", + "fast_mode_prompt", + "fast_registration", + "id", + "protocol", + "location", + "hidetor", + "residential", + "tor", + "connection", + "screen", + "browser", + "resume", + "wireguard", + "install_system_package", + "sync_screen", +] diff --git a/gui/v2/workers/worker_thread.py b/gui/v2/workers/worker_thread.py index 7caa34b..dfea4d7 100755 --- a/gui/v2/workers/worker_thread.py +++ b/gui/v2/workers/worker_thread.py @@ -231,6 +231,7 @@ class WorkerThread(QThread): self.check_for_update() locations = LocationController.get_all() browser = ApplicationVersionController.get_all() + print('the browser is: ', browser) all_browser_versions = [ f"{browser.application_code}:{browser.version_number}" for browser in browser if browser.supported] all_location_codes = [