From 86fc3ca56c64b44c038905e9e219e8ab9364880b Mon Sep 17 00:00:00 2001 From: SimplifiedPrivacy Date: Tue, 18 Aug 2026 09:48:42 -0400 Subject: [PATCH] Introduced Assassin Mode in core, and this commit added support for it in the GUI. This involved passing in ticket observers when a profile is enabled or disabled, getting the max screen size via PyQt, and adding a check prior to using a random ticket. --- gui/main_ui.py | 2 ++ gui/v2/infrastructure/screen_size.py | 31 ++++++++++++++++++++ gui/v2/ui/pages/ticket_crypto_picker_page.py | 31 ++++++++++++-------- gui/v2/workers/worker.py | 8 ++++- gui/v2/workers/worker_thread.py | 9 +++--- 5 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 gui/v2/infrastructure/screen_size.py diff --git a/gui/main_ui.py b/gui/main_ui.py index 8bdd19a..0f3fbc3 100755 --- a/gui/main_ui.py +++ b/gui/main_ui.py @@ -31,6 +31,7 @@ from gui.v2.infrastructure import orm 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.screen_size import calculate_max_screensize 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 @@ -906,5 +907,6 @@ class CustomWindow(QMainWindow): def start_ui(force_sync): app = QApplication(sys.argv) + calculate_max_screensize(app) window = CustomWindow(force_sync=force_sync) sys.exit(app.exec()) diff --git a/gui/v2/infrastructure/screen_size.py b/gui/v2/infrastructure/screen_size.py new file mode 100644 index 0000000..23f45e2 --- /dev/null +++ b/gui/v2/infrastructure/screen_size.py @@ -0,0 +1,31 @@ +from core.errors.logger import logger + +from PyQt6.QtWidgets import QApplication +from PyQt6.QtGui import QGuiApplication +import sys + +max_screen_size = None +DEFAULT_VALUE = "800x800" + +def calculate_max_screensize(app): + global max_screen_size + + try: + screen = app.primaryScreen() + available = screen.availableGeometry() + dpi_ratio = screen.devicePixelRatio() + + actual_width = int(available.width() * dpi_ratio) + actual_height = int(available.height() * dpi_ratio) + max_screen_size = f"{actual_width}x{actual_height}" + + except Exception as e: + logger.error(f"Critical Error with calculating the screen size: {str(e)}") + max_screen_size = DEFAULT_VALUE + + +def get_max_screensize(): + if max_screen_size is not None: + return max_screen_size + else: + return DEFAULT_VALUE diff --git a/gui/v2/ui/pages/ticket_crypto_picker_page.py b/gui/v2/ui/pages/ticket_crypto_picker_page.py index be110d6..5d6ed7f 100755 --- a/gui/v2/ui/pages/ticket_crypto_picker_page.py +++ b/gui/v2/ui/pages/ticket_crypto_picker_page.py @@ -6,6 +6,7 @@ from PyQt6.QtCore import QSize from PyQt6 import QtCore from core.controllers.tickets.TicketPayController import check_if_paid +from core.models.Result import Result, ResultError from gui.v2.infrastructure.setup_observers import connection_observer, ticket_observer from gui.v2.ui.pages.Page import Page @@ -103,26 +104,32 @@ class TicketCryptoPickerPage(Page): self.update_status.update_status("Could not initiate payment.") return - error_code = getattr(invoice, 'error_code', None) - if error_code == 'already_exists' and not self.bypass_existing: + if not invoice.valid: + return self._handle_api_errors(invoice) + + # error_code = getattr(invoice, 'error_code', None) + self.custom_window.navigator.navigate("payment_details") + payment_page = self.custom_window.navigator.get_cached("payment_details") + if payment_page is not None: + payment_page.set_ticket_invoice(invoice.data, self.selected_plan) + + def _handle_api_errors(self, invoice: Result): + error_code = invoice.error_type + if error_code == ResultError.ALREADY_EXISTS and not self.bypass_existing: self._prompt_wipe_existing(invoice) return - if error_code == 'billing_code_exists' and not self.bypass_existing: - temp_billing_code = getattr(invoice, 'temp_billing_code', None) + elif error_code == ResultError.BILLING_CODE_EXISTS and not self.bypass_existing: + temp_billing_code = getattr(invoice_data, 'temp_billing_code', None) print(f"temp_billing_code is {temp_billing_code}") if temp_billing_code: self._prompt_wipe_billingcode(temp_billing_code) return - if error_code: - msg = getattr(invoice, 'final_error_msg', None) or error_code - self.update_status.update_status(f"Payment error: {msg}") + else: + error_msg = invoice.message + # msg = getattr(invoice, 'final_error_msg', None) or error_code + self.update_status.update_status(error_msg) return - self.custom_window.navigator.navigate("payment_details") - payment_page = self.custom_window.navigator.get_cached("payment_details") - if payment_page is not None: - payment_page.set_ticket_invoice(invoice, self.selected_plan) - def _prompt_wipe_existing(self, invoice): msg = QMessageBox(self) msg.setWindowTitle("Existing tickets found") diff --git a/gui/v2/workers/worker.py b/gui/v2/workers/worker.py index a31ec3a..736107f 100755 --- a/gui/v2/workers/worker.py +++ b/gui/v2/workers/worker.py @@ -26,6 +26,7 @@ from core.Errors import ( from gui.v2.actions.locations import location_candidates from gui.v2.actions.database_health import GuiStorageDatabaseError +from gui.v2.infrastructure.screen_size import get_max_screensize from gui.v2.infrastructure.setup_observers import ( application_version_observer, connection_observer, @@ -106,9 +107,10 @@ class Worker(QObject): if self.profile_data.get('ignore_profile_state_conflict', False): ignore_exceptions.append(ProfileStateConflictError) ignore_tuple = tuple(ignore_exceptions) + max_resolution = get_max_screensize() ProfileController.enable(self.profile, ignore=ignore_tuple, profile_observer=profile_observer, application_version_observer=application_version_observer, - connection_observer=connection_observer) + connection_observer=connection_observer, ticket_observer=ticket_observer, max_resolution=max_resolution) except EndpointVerificationError: self.update_signal.emit( "ENDPOINT_VERIFICATION_ERROR", False, self.profile_data['id'], None, None) @@ -193,7 +195,11 @@ class Worker(QObject): print(error_msg) return None + if self.profile.assassin: + print("skipping random ticket use for the assassin, as it already has it baked in.") + return None try: + print("using a random ticket from GUI...") which_ticket, error_msg = do_we_use_a_random_ticket(ticket_observer) except Exception: return None diff --git a/gui/v2/workers/worker_thread.py b/gui/v2/workers/worker_thread.py index 3fc8502..6078f10 100755 --- a/gui/v2/workers/worker_thread.py +++ b/gui/v2/workers/worker_thread.py @@ -26,6 +26,7 @@ from gui.v2.infrastructure.setup_observers import ( connection_observer, invoice_observer, profile_observer, + ticket_observer, ) @@ -129,12 +130,12 @@ class WorkerThread(QThread): profile = ProfileController.get(int(profile_id)) if isinstance(profile, SessionProfile): ProfileController.disable( - profile, ignore=True, profile_observer=profile_observer) + profile, ignore=True, profile_observer=profile_observer, ticket_observer=ticket_observer, connection_observer=connection_observer) for profile_id in self.profile_data: profile = ProfileController.get(int(profile_id)) if isinstance(profile, SystemProfile): ProfileController.disable( - profile, ignore=True, profile_observer=profile_observer) + profile, ignore=True, profile_observer=profile_observer, ticket_observer=ticket_observer, connection_observer=connection_observer) self.text_output.emit("All profiles were successfully disabled") except SudoScript as e: self.text_output.emit(str(e)) @@ -153,7 +154,7 @@ class WorkerThread(QThread): if profile is not None: try: - ProfileController.destroy(profile) + ProfileController.destroy(profile, profile_observer, ticket_observer, connection_observer) except Exception as e: error_name = type(e).__name__ error_text = str(e) or 'Unknown deletion error' @@ -244,7 +245,7 @@ class WorkerThread(QThread): profile = ProfileController.get(int(self.profile_data['id'])) if profile: ProfileController.disable( - profile, profile_observer=profile_observer) + profile, profile_observer=profile_observer, ticket_observer=ticket_observer, connection_observer=connection_observer, wipe_assassin=True) else: self.text_output.emit( f"No profile found with ID: {self.profile_data['id']}")