From 0fac5a2d99f2702c2e0dfca0628ee7836c117f1e Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 26 Dec 2025 15:17:27 +0100 Subject: [PATCH] update: updated location name display --- gui/__main__.py | 3736 +++++++++++++++++++++++++++-------------------- 1 file changed, 2164 insertions(+), 1572 deletions(-) diff --git a/gui/__main__.py b/gui/__main__.py index cad9ac4..e8481f8 100755 --- a/gui/__main__.py +++ b/gui/__main__.py @@ -1,8 +1,8 @@ -from PyQt6.QtWidgets import QComboBox,QButtonGroup, QLineEdit,QMainWindow, QLabel, QWidget, QVBoxLayout, QStackedWidget, QApplication, QPushButton, QTextEdit, QFrame, QHBoxLayout, QVBoxLayout, QScrollArea, QSystemTrayIcon, QMessageBox, QGridLayout, QCheckBox, QStackedLayout, QGroupBox, QDialog -from PyQt6.QtGui import QIcon, QPixmap,QIcon, QPixmap, QTransform, QPainter, QColor, QFont, QFontDatabase, QTextOption +from PyQt6.QtWidgets import QComboBox, QButtonGroup, QLineEdit, QMainWindow, QLabel, QWidget, QVBoxLayout, QStackedWidget, QApplication, QPushButton, QTextEdit, QFrame, QHBoxLayout, QVBoxLayout, QScrollArea, QSystemTrayIcon, QMessageBox, QGridLayout, QCheckBox, QStackedLayout, QGroupBox, QDialog +from PyQt6.QtGui import QIcon, QPixmap, QIcon, QPixmap, QTransform, QPainter, QColor, QFont, QFontDatabase, QTextOption from PyQt6 import QtGui from PyQt6 import QtCore -from PyQt6.QtCore import Qt,QSize,QThread,pyqtSignal, QTimer, QPointF, QRect, QMutex, QMutexLocker, QObject +from PyQt6.QtCore import Qt, QSize, QThread, pyqtSignal, QTimer, QPointF, QRect, QMutex, QMutexLocker, QObject import os import sys import functools @@ -41,13 +41,12 @@ import json import shlex - application_version_observer = ApplicationVersionObserver() client_observer = ClientObserver() connection_observer = ConnectionObserver() invoice_observer = InvoiceObserver() profile_observer = ProfileObserver() - + class WorkerThread(QThread): text_output = pyqtSignal(str) @@ -69,7 +68,6 @@ class WorkerThread(QThread): self.is_running = True self.is_disabling = False - def run(self): if self.action == 'LIST_PROFILES': self.list_profiles() @@ -111,17 +109,18 @@ class WorkerThread(QThread): print(f"Error retrieving invoice: {str(e)}") self.invoice_finished.emit(False) - def download_update(self): self.text_output.emit("Starting update process...") ClientController.update(client_observer=client_observer) - client_observer.subscribe('update_progressing', lambda event: self.text_output.emit(f"Downloading: {event.meta.get('progress'):.1f}%")) - client_observer.subscribe('updated', lambda event: self.text_output.emit("Update process completed")) - + client_observer.subscribe('update_progressing', lambda event: self.text_output.emit( + f"Downloading: {event.meta.get('progress'):.1f}%")) + client_observer.subscribe( + 'updated', lambda event: self.text_output.emit("Update process completed")) def check_for_update(self): self.text_output.emit("Checking for updates...") - ClientController.sync(client_observer=client_observer, connection_observer=connection_observer) + ClientController.sync(client_observer=client_observer, + connection_observer=connection_observer) update_available = ClientController.can_be_updated() if update_available: self.text_output.emit("An update is available. Downloading...") @@ -129,7 +128,6 @@ class WorkerThread(QThread): else: self.text_output.emit("No updates available.") self.finished.emit(False) - def install_package(self): try: @@ -141,7 +139,8 @@ class WorkerThread(QThread): self.text_output.emit("Installation failed") self.finished.emit(False) except Exception as e: - self.text_output.emit(f"An error occurred when installing {self.package_name}: {e}") + self.text_output.emit( + f"An error occurred when installing {self.package_name}: {e}") self.finished.emit(False) def disable_all_profiles(self): @@ -149,11 +148,13 @@ class WorkerThread(QThread): for profile_id in self.profile_data: profile = ProfileController.get(int(profile_id)) if isinstance(profile, SessionProfile): - ProfileController.disable(profile, ignore=True, profile_observer=profile_observer) + ProfileController.disable( + profile, ignore=True, profile_observer=profile_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) + ProfileController.disable( + profile, ignore=True, profile_observer=profile_observer) self.text_output.emit("All profiles were successfully disabled") except Exception: self.text_output.emit("An error occurred when disabling profile") @@ -163,63 +164,73 @@ class WorkerThread(QThread): def destroy_profile(self): profile_id = int(self.profile_data['id']) profile = ProfileController.get(profile_id) - + if profile is not None: ProfileController.destroy(profile) self.text_output.emit(f'Profile {profile_id} deleted') else: self.text_output.emit(f'Profile {profile_id} does not exist') - - - def list_profiles(self): profiles = ProfileController.get_all() self.profiles_output.emit(profiles) def create_profile(self, profile_type): - location = LocationController.get(self.profile_data['country_code'], self.profile_data['code']) + location = LocationController.get( + self.profile_data['country_code'], self.profile_data['code']) if location is None: - self.text_output.emit(f"Invalid location code: {self.profile_data['location_code']}") + self.text_output.emit( + f"Invalid location code: {self.profile_data['location_code']}") return - profile_id = int(self.profile_data['id']) if self.profile_data['id'] else None + profile_id = int( + self.profile_data['id']) if self.profile_data['id'] else None name = self.profile_data['name'] connection_type = self.profile_data['connection_type'] if profile_type == "session": - application_details = self.profile_data['application'].split(':', 1) - application_version = ApplicationVersionController.get(application_details[0], application_details[1] if len(application_details) > 1 else None) + application_details = self.profile_data['application'].split( + ':', 1) + application_version = ApplicationVersionController.get( + application_details[0], application_details[1] if len(application_details) > 1 else None) if application_version is None: - self.text_output.emit(f"Invalid application: {self.profile_data['application']}") + self.text_output.emit( + f"Invalid application: {self.profile_data['application']}") return mask_connection = True if connection_type == 'tor' or connection_type == 'system' else False resolution = self.profile_data['resolution'] connection = SessionConnection(connection_type, mask_connection) - profile = SessionProfile(profile_id, name, None, location, resolution, application_version, connection) + profile = SessionProfile( + profile_id, name, None, location, resolution, application_version, connection) elif profile_type == "system": connection = SystemConnection(connection_type) - profile = SystemProfile(profile_id, name, None, location, connection) + profile = SystemProfile( + profile_id, name, None, location, connection) else: self.text_output.emit(f"Invalid profile type: {profile_type}") return try: - ProfileController.create(profile, profile_observer=profile_observer) + ProfileController.create( + profile, profile_observer=profile_observer) except Exception as e: - self.text_output.emit(f"An error occurred when creating profile {profile.id}") + self.text_output.emit( + f"An error occurred when creating profile {profile.id}") - self.text_output.emit(f"{profile_type.capitalize()} Profile created with ID: {profile.id}") + self.text_output.emit( + f"{profile_type.capitalize()} Profile created with ID: {profile.id}") def disable_profile(self): try: profile = ProfileController.get(int(self.profile_data['id'])) if profile: - ProfileController.disable(profile, profile_observer=profile_observer) + ProfileController.disable( + profile, profile_observer=profile_observer) else: - self.text_output.emit(f"No profile found with ID: {self.profile_data['id']}") + self.text_output.emit( + f"No profile found with ID: {self.profile_data['id']}") except Exception as e: self.text_output.emit("An error occurred when disabling profile") finally: @@ -234,61 +245,73 @@ class WorkerThread(QThread): self.check_for_update() locations = LocationController.get_all() browser = ApplicationVersionController.get_all() - all_browser_versions = [f"{browser.application_code}:{browser.version_number}" for browser in browser if browser.supported] - all_location_codes = [f"{location.country_code}_{location.code}" for location in locations] - self.sync_output.emit(all_location_codes, all_browser_versions, True, False, locations, browser) + all_browser_versions = [ + f"{browser.application_code}:{browser.version_number}" for browser in browser if browser.supported] + all_location_codes = [ + f"{location.country_code}_{location.code}" for location in locations] + self.sync_output.emit( + all_location_codes, all_browser_versions, True, False, locations, browser) except Exception as e: print(f'the error is: {e}') self.sync_output.emit([], [], False, False, [], []) - - def get_connection(self): connection = ConfigurationController.get_connection() self.text_output.emit(f"Current connection: {connection}") def set_connection(self): - ConfigurationController.set_connection(self.profile_data['connection_type']) - self.text_output.emit(f"Connection set to '{self.profile_data['connection_type']}'") + ConfigurationController.set_connection( + self.profile_data['connection_type']) + self.text_output.emit( + f"Connection set to '{self.profile_data['connection_type']}'") def get_subscription(self): try: - invoice_observer.subscribe('retrieved', lambda event: self.handle_event(event, self.profile_data['currency'])) - invoice_observer.subscribe('processing', lambda event: self.text_output.emit('A payment has been detected and is being verified...')) - invoice_observer.subscribe('settled', lambda event: self.text_output.emit('The payment has been successfully verified.')) + invoice_observer.subscribe('retrieved', lambda event: self.handle_event( + event, self.profile_data['currency'])) + invoice_observer.subscribe('processing', lambda event: self.text_output.emit( + 'A payment has been detected and is being verified...')) + invoice_observer.subscribe('settled', lambda event: self.text_output.emit( + 'The payment has been successfully verified.')) profile = ProfileController.get(int(self.profile_data['id'])) - subscription_plan = SubscriptionPlanController.get(profile.connection, self.profile_data['duration']) + subscription_plan = SubscriptionPlanController.get( + profile.connection, self.profile_data['duration']) if subscription_plan is None: - self.text_output.emit('No compatible subscription plan was found.') + self.text_output.emit( + 'No compatible subscription plan was found.') return - potential_subscription = SubscriptionController.create(subscription_plan, profile, connection_observer=connection_observer) + potential_subscription = SubscriptionController.create( + subscription_plan, profile, connection_observer=connection_observer) if potential_subscription is not None: - ProfileController.attach_subscription(profile, potential_subscription) + ProfileController.attach_subscription( + profile, potential_subscription) else: - self.text_output.emit('The subscription could not be created. Try again later.') + self.text_output.emit( + 'The subscription could not be created. Try again later.') return - - subscription = InvoiceController.handle_payment(potential_subscription.billing_code, invoice_observer=invoice_observer, connection_observer=connection_observer) + subscription = InvoiceController.handle_payment( + potential_subscription.billing_code, invoice_observer=invoice_observer, connection_observer=connection_observer) if subscription is not None: ProfileController.attach_subscription(profile, subscription) - self.text_output.emit('Successfully activated the subscription') + self.text_output.emit( + 'Successfully activated the subscription') self.invoice_finished.emit(True) else: - self.text_output.emit('The subscription could not be activated. Try again later.') + self.text_output.emit( + 'The subscription could not be activated. Try again later.') self.invoice_finished.emit(False) except Exception as e: self.text_output.emit('An unknown error occurred') self.invoice_finished.emit(False) - def handle_connection_events(self, event): self.text_output.emit(f'Profile disabled') def handle_event(self, event, currency=None): - invoice = event.subject + invoice = event.subject if isinstance(invoice, object): self.invoice_output.emit(invoice, '') self.text_output.emit("Invoice generated. Awaiting payment...") @@ -313,21 +336,23 @@ class CustomWindow(QMainWindow): app_font = QFont(font_family) app_font.setPointSize(10) QApplication.setFont(app_font) - + self.open_sans_family = None open_sans_path = os.path.join(font_path, 'open-sans.ttf') if os.path.exists(open_sans_path): open_sans_id = QFontDatabase.addApplicationFont(open_sans_path) if open_sans_id != -1: - self.open_sans_family = QFontDatabase.applicationFontFamilies(open_sans_id)[0] - + self.open_sans_family = QFontDatabase.applicationFontFamilies(open_sans_id)[ + 0] + self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self.setAttribute(Qt.WidgetAttribute.WA_NoSystemBackground) self.setWindowTitle('HydraVeil') self._data = {"Profile_1": {}} self.gui_config_home = os.path.join(Constants.HV_CONFIG_HOME, 'gui') - self.gui_config_file = os.path.join(self.gui_config_home, 'config.json') + self.gui_config_file = os.path.join( + self.gui_config_home, 'config.json') self.gui_cache_home = os.path.join(Constants.HV_CACHE_HOME, 'gui') self.gui_log_file = os.path.join(self.gui_cache_home, 'gui.log') @@ -336,8 +361,10 @@ class CustomWindow(QMainWindow): current_dir = os.path.dirname(os.path.abspath(__file__)) - self.btn_path = os.getenv('BTN_PATH', os.path.join(current_dir, 'resources', 'images')) - self.css_path = os.getenv('CSS_PATH', os.path.join(current_dir, 'resources', 'styles')) + self.btn_path = os.getenv('BTN_PATH', os.path.join( + current_dir, 'resources', 'images')) + self.css_path = os.getenv('CSS_PATH', os.path.join( + current_dir, 'resources', 'styles')) self.tray = None self.init_system_tray(self.btn_path) @@ -353,24 +380,34 @@ class CustomWindow(QMainWindow): self.animation_step = 0 self.page_history = [] self.log_path = None - - - profile_observer.subscribe('created', lambda event: self.update_status('Profile Created')) - profile_observer.subscribe('destroyed', lambda event: self.update_status('Profile destroyed')) - client_observer.subscribe('synchronizing', lambda event: self.update_status('Sync in progress...')) - client_observer.subscribe('synchronized', lambda event: self.update_status('Sync complete')) + profile_observer.subscribe( + 'created', lambda event: self.update_status('Profile Created')) + profile_observer.subscribe( + 'destroyed', lambda event: self.update_status('Profile destroyed')) - client_observer.subscribe('updating', lambda event: self.update_status('Updating client...')) - client_observer.subscribe('update_progressing', lambda event: self.update_status(f'Current progress: {event.meta.get('progress'):.2f}%')) - client_observer.subscribe('updated', lambda event: self.update_status('Restart client to apply update.')) + client_observer.subscribe( + 'synchronizing', lambda event: self.update_status('Sync in progress...')) + client_observer.subscribe( + 'synchronized', lambda event: self.update_status('Sync complete')) + + client_observer.subscribe( + 'updating', lambda event: self.update_status('Updating client...')) + client_observer.subscribe('update_progressing', lambda event: self.update_status( + f'Current progress: {event.meta.get('progress'):.2f}%')) + client_observer.subscribe('updated', lambda event: self.update_status( + 'Restart client to apply update.')) + + application_version_observer.subscribe('downloading', lambda event: self.update_status( + f'Downloading {ApplicationController.get(event.subject.application_code).name}')) + application_version_observer.subscribe('download_progressing', lambda event: self.update_status( + f'Downloading {ApplicationController.get(event.subject.application_code).name} {event.meta.get('progress'):.2f}%')) + application_version_observer.subscribe('downloaded', lambda event: self.update_status( + f'Downloaded {ApplicationController.get(event.subject.application_code).name}')) + + connection_observer.subscribe('connecting', lambda event: self.update_status( + f'[{event.subject.get("attempt_count")}/{event.subject.get("maximum_number_of_attempts")}] Performing connection attempt...')) - application_version_observer.subscribe('downloading', lambda event: self.update_status(f'Downloading {ApplicationController.get(event.subject.application_code).name}')) - application_version_observer.subscribe('download_progressing', lambda event: self.update_status(f'Downloading {ApplicationController.get(event.subject.application_code).name} {event.meta.get('progress'):.2f}%')) - application_version_observer.subscribe('downloaded', lambda event: self.update_status(f'Downloaded {ApplicationController.get(event.subject.application_code).name}')) - - connection_observer.subscribe('connecting', lambda event: self.update_status(f'[{event.subject.get("attempt_count")}/{event.subject.get("maximum_number_of_attempts")}] Performing connection attempt...')) - self.setFixedSize(800, 570) self.central_widget = QWidget(self) self.central_widget.setMaximumSize(800, 600) @@ -381,17 +418,21 @@ class CustomWindow(QMainWindow): self.label = QLabel(self.central_widget) self.label.setGeometry(0, 0, 800, 570) css_file = os.path.join(self.css_path, 'look.css') - self.setStyleSheet(open(css_file).read() if os.path.exists(css_file) else '') # Opcional: si deseas cargar estilos CSS desde un archivo - + # Opcional: si deseas cargar estilos CSS desde un archivo + self.setStyleSheet(open(css_file).read() + if os.path.exists(css_file) else '') self.status_label = QLabel(self) self.status_label.setGeometry(15, 518, 780, 20) - self.status_label.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) - self.status_label.setStyleSheet("color: rgb(0, 255, 255); font-size: 16px;") - self.status_label.setText(f"Status: Client version {Constants.HV_CLIENT_VERSION_NUMBER}") + self.status_label.setAlignment( + Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) + self.status_label.setStyleSheet( + "color: rgb(0, 255, 255); font-size: 16px;") + self.status_label.setText( + f"Status: Client version {Constants.HV_CLIENT_VERSION_NUMBER}") - self.text_start_x = 15 - self.text_end_x = 420 + self.text_start_x = 15 + self.text_end_x = 420 self.text_width = self.text_end_x - self.text_start_x self.marquee_text = "" @@ -399,7 +440,7 @@ class CustomWindow(QMainWindow): self.marquee_timer = QTimer(self) self.marquee_timer.timeout.connect(self.update_marquee) self.marquee_enabled = False - self.scroll_speed = 1 + self.scroll_speed = 1 self.tor_text = QLabel("Billing & Browsers", self) self.tor_text.setGeometry(532, 541, 150, 20) @@ -411,10 +452,9 @@ class CustomWindow(QMainWindow): } """) self.update_image() - self.set_scroll_speed(7) - + self.toggle_button = QPushButton(self) self.toggle_button.setGeometry(670, 541, 50, 22) self.toggle_button.setCheckable(True) @@ -434,9 +474,11 @@ class CustomWindow(QMainWindow): self.sync_button.setObjectName('sync_button') if CustomWindow.should_be_synchronized(): - sync_icon = QtGui.QIcon(os.path.join(self.btn_path, 'icon_sync_urgent.png')) + sync_icon = QtGui.QIcon(os.path.join( + self.btn_path, 'icon_sync_urgent.png')) else: - sync_icon = QtGui.QIcon(os.path.join(self.btn_path, 'icon_sync.png')) + sync_icon = QtGui.QIcon(os.path.join( + self.btn_path, 'icon_sync.png')) self.sync_button.setToolTip('Sync') self.sync_button.setIcon(sync_icon) @@ -460,7 +502,8 @@ class CustomWindow(QMainWindow): def update_values(self, available_locations, available_browsers, status, is_tor, locations, all_browsers): sync_screen = self.page_stack.findChild(SyncScreen) if status: - sync_screen.update_after_sync(available_locations, available_browsers, locations, all_browsers) + sync_screen.update_after_sync( + available_locations, available_browsers, locations, all_browsers) menu_page = self.page_stack.findChild(MenuPage) if menu_page and hasattr(menu_page, 'buttons'): for button in menu_page.buttons: @@ -473,19 +516,18 @@ class CustomWindow(QMainWindow): else: self.update_status('Sync failed. Please try again later.') - - def sync(self): if ConfigurationController.get_connection() == 'tor': self.worker_thread = WorkerThread('SYNC_TOR') else: self.worker_thread = WorkerThread('SYNC') - self.sync_button.setIcon(QtGui.QIcon(os.path.join(self.btn_path, 'icon_sync.png'))) - self.worker_thread.finished.connect(lambda: self.perform_update_check()) + self.sync_button.setIcon(QtGui.QIcon( + os.path.join(self.btn_path, 'icon_sync.png'))) + self.worker_thread.finished.connect( + lambda: self.perform_update_check()) self.worker_thread.sync_output.connect(self.update_values) self.worker_thread.start() - def _handle_exception(self, identifier, message, trace): if issubclass(identifier, UnknownConnectionTypeError): self.setup_popup() @@ -507,28 +549,30 @@ class CustomWindow(QMainWindow): sys.__excepthook__(identifier, message, trace) def get_current_connection(self): - return ConfigurationController.get_connection() + return ConfigurationController.get_connection() - def setup_popup(self): connection_dialog = QDialog(self) connection_dialog.setWindowTitle("Connection Type") - connection_dialog.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.CustomizeWindowHint | Qt.WindowType.WindowTitleHint) + connection_dialog.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowStaysOnTopHint | + Qt.WindowType.CustomizeWindowHint | Qt.WindowType.WindowTitleHint) connection_dialog.setModal(True) connection_dialog.setFixedSize(400, 200) - + layout = QVBoxLayout(connection_dialog) - - label = QLabel("Please set your preference for connecting to Simplified Privacy's billing server.") + + label = QLabel( + "Please set your preference for connecting to Simplified Privacy's billing server.") label.setWordWrap(True) label.setAlignment(Qt.AlignmentFlag.AlignCenter) - label.setStyleSheet("font-size: 12px; margin-bottom: 20px; color: black;") - + label.setStyleSheet( + "font-size: 12px; margin-bottom: 20px; color: black;") + button_layout = QHBoxLayout() - + regular_btn = QPushButton("Regular") tor_btn = QPushButton("Tor") - + button_style = """ QPushButton { background-color: #2b2b2b; @@ -547,36 +591,36 @@ class CustomWindow(QMainWindow): """ regular_btn.setStyleSheet(button_style) tor_btn.setStyleSheet(button_style) - + button_layout.addWidget(regular_btn) button_layout.addWidget(tor_btn) - + layout.addWidget(label) layout.addLayout(button_layout) - + def set_regular_connection(): ConfigurationController.set_connection('system') self.is_tor_mode = False self.set_toggle_state(False) connection_dialog.accept() - + def set_tor_connection(): ConfigurationController.set_connection('tor') self.is_tor_mode = True self.set_toggle_state(True) connection_dialog.accept() - + regular_btn.clicked.connect(set_regular_connection) tor_btn.clicked.connect(set_tor_connection) - + connection_dialog.exec() - + return ConfigurationController.get_connection() - + def _setup_gui_directory(self): os.makedirs(self.gui_cache_home, exist_ok=True) os.makedirs(self.gui_config_home, exist_ok=True) - + if not os.path.exists(self.gui_config_file): default_config = { "logging": { @@ -618,66 +662,63 @@ class CustomWindow(QMainWindow): def mark_systemwide_prompt_shown(self): config = self._load_gui_config() if config is None: - config = {"logging": {"gui_logging_enabled": False, "log_level": "INFO"}} + config = {"logging": { + "gui_logging_enabled": False, "log_level": "INFO"}} if "systemwide" not in config: config["systemwide"] = {} config["systemwide"]["prompt_shown"] = True self._save_gui_config(config) - - def stop_gui_logging(self): if os.path.exists(self.gui_log_file): os.remove(self.gui_log_file) - + config = self._load_gui_config() if config: config["logging"]["gui_logging_enabled"] = False self._save_gui_config(config) - def _setup_gui_logging(self): os.makedirs(self.gui_cache_home, exist_ok=True) - + formatter = logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) - + file_handler = logging.FileHandler(self.gui_log_file) file_handler.setLevel(logging.INFO) file_handler.setFormatter(formatter) - + logger = logging.getLogger() logger.setLevel(logging.INFO) - logger.handlers = [] + logger.handlers = [] logger.addHandler(file_handler) - - + if not os.path.exists(self.gui_log_file) or os.path.getsize(self.gui_log_file) == 0: logging.info("GUI logging system initialized") - def set_tor_icon(self): if self.is_tor_mode: icon_path = os.path.join(self.btn_path, "toricon_mini.png") - + else: icon_path = os.path.join(self.btn_path, "toricon_mini_false.png") pixmap = QPixmap(icon_path) self.tor_icon.setPixmap(pixmap) - self.tor_icon.setScaledContents(True) + self.tor_icon.setScaledContents(True) + def create_toggle(self, is_tor_mode): handle_x = 30 if is_tor_mode else 3 colors = self._get_toggle_colors(is_tor_mode) - + if not hasattr(self, 'animation_timer'): self.animation_timer = QTimer() self.animation_timer.timeout.connect(self.animate_toggle) - + self.toggle_bg = QLabel(self.toggle_button) self.toggle_bg.setGeometry(0, 0, 50, 22) - + # Create handle self.toggle_handle = QLabel(self.toggle_button) self.toggle_handle.setGeometry(handle_x, 3, 16, 16) @@ -687,13 +728,13 @@ class CustomWindow(QMainWindow): border-radius: 8px; } """) - + self.on_label = QLabel("ON", self.toggle_button) self.on_label.setGeometry(8, 4, 15, 14) - + self.off_label = QLabel("OFF", self.toggle_button) self.off_label.setGeometry(25, 4, 40, 14) - + self._update_toggle_colors(colors) if is_tor_mode: self.set_tor_icon() @@ -712,7 +753,7 @@ class CustomWindow(QMainWindow): border-radius: 11px; }} """) - + self.on_label.setStyleSheet(f""" QLabel {{ color: {colors['tor']}; @@ -720,7 +761,7 @@ class CustomWindow(QMainWindow): font-weight: bold; }} """) - + self.off_label.setStyleSheet(f""" QLabel {{ color: {colors['sys']}; @@ -742,13 +783,14 @@ class CustomWindow(QMainWindow): self.animation_step = 0 self.animation_timer.start(16) self.is_tor_mode = not self.is_tor_mode - ConfigurationController.set_connection('tor' if self.is_tor_mode else 'system') + ConfigurationController.set_connection( + 'tor' if self.is_tor_mode else 'system') def animate_toggle(self): TOTAL_STEPS = 5 if self.animation_step <= TOTAL_STEPS: progress = self.animation_step / TOTAL_STEPS - + if self.is_tor_mode: new_x = 20 + (10 * progress) start_color = "#2c3e50" @@ -757,9 +799,9 @@ class CustomWindow(QMainWindow): new_x = 31 - (28 * progress) start_color = "#00a8ff" end_color = "#2c3e50" - + self.toggle_handle.setGeometry(int(new_x), 3, 16, 16) - + bg_color = self.interpolate_color(start_color, end_color, progress) self.toggle_bg.setStyleSheet(f""" QLabel {{ @@ -767,7 +809,7 @@ class CustomWindow(QMainWindow): border-radius: 11px; }} """) - + self.off_label.setStyleSheet(f""" QLabel {{ color: rgba(255, 255, 255, {1 - progress if self.is_tor_mode else progress}); @@ -782,7 +824,7 @@ class CustomWindow(QMainWindow): font-weight: bold; }} """) - + self.animation_step += 1 else: self.animation_timer.stop() @@ -793,34 +835,33 @@ class CustomWindow(QMainWindow): def hex_to_rgb(hex_color): hex_color = hex_color.lstrip('#') return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) - + start_rgb = hex_to_rgb(start_color) end_rgb = hex_to_rgb(end_color) - + current_rgb = tuple( int(start_rgb[i] + (end_rgb[i] - start_rgb[i]) * progress) for i in range(3) ) - - return f"rgb{current_rgb}" - - + return f"rgb{current_rgb}" def init_system_tray(self, icon_base_path): if QSystemTrayIcon.isSystemTrayAvailable(): tray_icon = QIcon() window_icon = QIcon() - + tray_sizes = [22, 24] for size in tray_sizes: - icon_path = os.path.join(icon_base_path, f"hv-icon-{size}x{size}.png") + icon_path = os.path.join( + icon_base_path, f"hv-icon-{size}x{size}.png") if os.path.exists(icon_path): tray_icon.addFile(icon_path, QSize(size, size)) - + window_sizes = [32, 48, 64, 128] for size in window_sizes: - icon_path = os.path.join(icon_base_path, f"hv-icon-{size}x{size}.png") + icon_path = os.path.join( + icon_base_path, f"hv-icon-{size}x{size}.png") if os.path.exists(icon_path): window_icon.addFile(icon_path, QSize(size, size)) @@ -841,18 +882,21 @@ class CustomWindow(QMainWindow): if event is not None: event.ignore() message = self._create_disconnect_message(connected_profiles) - + self.popup = self._create_confirmation_popup(message, button_text) - self.popup.finished.connect(lambda result: self._handle_popup_result(result, connected_profiles, event)) + self.popup.finished.connect(lambda result: self._handle_popup_result( + result, connected_profiles, event)) self.popup.show() def _create_disconnect_message(self, connected_profiles): - profile_numbers = ', '.join(str(profile_id) for profile_id in connected_profiles) + profile_numbers = ', '.join(str(profile_id) + for profile_id in connected_profiles) is_are = "is" if len(connected_profiles) == 1 else "are" return f'Profile{"" if len(connected_profiles) == 1 else "s"} {profile_numbers} {is_are} still connected.\nAll connected profiles will be disconnected on exit. \nDo you want to proceed?' def _create_confirmation_popup(self, message, button_text): - popup = ConfirmationPopup(self, message=message, action_button_text=button_text, cancel_button_text="Cancel") + popup = ConfirmationPopup( + self, message=message, action_button_text=button_text, cancel_button_text="Cancel") popup.setWindowModality(Qt.WindowModality.ApplicationModal) return popup @@ -867,8 +911,10 @@ class CustomWindow(QMainWindow): def _disable_profiles(self, connected_profiles, exit=True): self.update_status('Disabling profiles...') - self.worker_thread = WorkerThread('DISABLE_ALL_PROFILES', profile_data=connected_profiles) - self.worker_thread.text_output.connect(lambda text: self._on_disable_status(text, exit)) + self.worker_thread = WorkerThread( + 'DISABLE_ALL_PROFILES', profile_data=connected_profiles) + self.worker_thread.text_output.connect( + lambda text: self._on_disable_status(text, exit)) self.worker_thread.start() def _on_disable_status(self, text, exit): @@ -883,7 +929,7 @@ class CustomWindow(QMainWindow): self.cleanup() super().closeEvent(event) - def update_image(self, appearance_value = "original"): + def update_image(self, appearance_value="original"): image_path = os.path.join(self.btn_path, f"{appearance_value}.png") # Configuramos la imagen en el QLabel @@ -891,8 +937,6 @@ class CustomWindow(QMainWindow): self.label.setPixmap(pixmap) self.label.setScaledContents(True) - - def init_ui(self): # Configuración del diseño de la ventana principal layout = QVBoxLayout(self.central_widget) @@ -901,38 +945,41 @@ class CustomWindow(QMainWindow): self.menu_page = MenuPage(self.page_stack, self) self.editor_page = EditorPage(self.page_stack, self) self.pages = [MenuPage(self.page_stack, self), - ProtocolPage(self.page_stack, self), - WireGuardPage(self.page_stack, self), - HidetorPage(self.page_stack, self), - LocationPage(self.page_stack, self), - BrowserPage(self.page_stack, self), - ScreenPage(self.page_stack, self), - ResumePage(self.page_stack, self), - ResidentialPage(self.page_stack, self), - InstallSystemPackage(self.page_stack, self), - WelcomePage(self.page_stack, self), - SystemwidePromptPage(self.page_stack, self), - PolicySuggestionPage(self.page_stack, self, None, 'capability'), - PolicySuggestionPage(self.page_stack, self, None, 'privilege'), - PaymentDetailsPage(self.page_stack, self), - DurationSelectionPage(self.page_stack, self), - CurrencySelectionPage(self.page_stack, self), - PaymentConfirmed(self.page_stack, self), - IdPage(self.page_stack, self), - TorPage(self.page_stack, self), - EditorPage(self.page_stack, self), - FastModePromptPage(self.page_stack, self), - FastRegistrationPage(self.page_stack, self), - Settings(self.page_stack, self), - ConnectionPage(self.page_stack, self), - SyncScreen(self.page_stack, self)] + ProtocolPage(self.page_stack, self), + WireGuardPage(self.page_stack, self), + HidetorPage(self.page_stack, self), + LocationPage(self.page_stack, self), + BrowserPage(self.page_stack, self), + ScreenPage(self.page_stack, self), + ResumePage(self.page_stack, self), + ResidentialPage(self.page_stack, self), + InstallSystemPackage(self.page_stack, self), + WelcomePage(self.page_stack, self), + SystemwidePromptPage(self.page_stack, self), + PolicySuggestionPage( + self.page_stack, self, None, 'capability'), + PolicySuggestionPage( + self.page_stack, self, None, 'privilege'), + PaymentDetailsPage(self.page_stack, self), + DurationSelectionPage(self.page_stack, self), + CurrencySelectionPage(self.page_stack, self), + PaymentConfirmed(self.page_stack, self), + IdPage(self.page_stack, self), + TorPage(self.page_stack, self), + EditorPage(self.page_stack, self), + FastModePromptPage(self.page_stack, self), + FastRegistrationPage(self.page_stack, self), + Settings(self.page_stack, self), + ConnectionPage(self.page_stack, self), + SyncScreen(self.page_stack, self)] for page in self.pages: self.page_stack.addWidget(page) # Conectar la señal currentChanged al método page_changed self.page_stack.currentChanged.connect(self.page_changed) - + if self.check_first_launch(): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(WelcomePage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(WelcomePage))) else: self.check_suggestible_policies() @@ -950,12 +997,11 @@ class CustomWindow(QMainWindow): self.status_label.setText('Status:') self.disable_marquee() return - + if clear: self.status_label.setText('') return - - + full_text = f'Status: {text}' self.status_label.setText(full_text) self.disable_marquee() @@ -963,10 +1009,12 @@ class CustomWindow(QMainWindow): def check_first_launch(self): config = self._load_gui_config() if config is None: - config = {"logging": {"gui_logging_enabled": False, "log_level": "INFO"}} - - is_first_launch = not config.get("first_launch", {}).get("completed", False) - + config = {"logging": { + "gui_logging_enabled": False, "log_level": "INFO"}} + + is_first_launch = not config.get( + "first_launch", {}).get("completed", False) + if is_first_launch: if "first_launch" not in config: config["first_launch"] = {} @@ -980,7 +1028,7 @@ class CustomWindow(QMainWindow): try: capability_policy = PolicyController.get('capability') - + if capability_policy is not None: if PolicyController.is_suggestible(capability_policy) and not PolicyController.is_instated(capability_policy): capability_page = None @@ -990,9 +1038,10 @@ class CustomWindow(QMainWindow): capability_page = page break if capability_page: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(capability_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(capability_page)) return - + except Exception as e: print(f"Error checking suggestible policies: {e}") @@ -1005,7 +1054,8 @@ class CustomWindow(QMainWindow): def mark_fast_mode_prompt_shown(self): config = self._load_gui_config() if config is None: - config = {"logging": {"gui_logging_enabled": False, "log_level": "INFO"}} + config = {"logging": { + "gui_logging_enabled": False, "log_level": "INFO"}} if "fast_mode" not in config: config["fast_mode"] = {} config["fast_mode"]["prompt_shown"] = True @@ -1014,7 +1064,8 @@ class CustomWindow(QMainWindow): def set_fast_mode_enabled(self, enabled): config = self._load_gui_config() if config is None: - config = {"logging": {"gui_logging_enabled": False, "log_level": "INFO"}} + config = {"logging": { + "gui_logging_enabled": False, "log_level": "INFO"}} if "registrations" not in config: config["registrations"] = {} config["registrations"]["fast_registration_enabled"] = bool(enabled) @@ -1022,15 +1073,17 @@ class CustomWindow(QMainWindow): def navigate_after_profile_created(self): if not self.has_shown_fast_mode_prompt(): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(FastModePromptPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(FastModePromptPage))) else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def enable_marquee(self, text): - self.marquee_text = text + " " + self.marquee_text = text + " " self.marquee_position = 0 self.marquee_enabled = True - self.marquee_timer.start(500) + self.marquee_timer.start(500) def disable_marquee(self): self.marquee_enabled = False @@ -1039,7 +1092,7 @@ class CustomWindow(QMainWindow): def update_marquee(self): if not self.marquee_enabled: return - + metrics = self.status_label.fontMetrics() text_width = metrics.horizontalAdvance(self.marquee_text) @@ -1048,18 +1101,21 @@ class CustomWindow(QMainWindow): self.marquee_position = 0 looped_text = self.marquee_text * 2 - - chars_that_fit = metrics.horizontalAdvance(looped_text[:self.text_width]) - - visible_text = looped_text[self.marquee_position:self.marquee_position + chars_that_fit] - + + chars_that_fit = metrics.horizontalAdvance( + looped_text[:self.text_width]) + + visible_text = looped_text[self.marquee_position: + self.marquee_position + chars_that_fit] + while metrics.horizontalAdvance(visible_text) < self.text_width: visible_text += self.marquee_text while metrics.horizontalAdvance(visible_text) > self.text_width: visible_text = visible_text[:-1] - display_text = 'Status: ' + ' ' * (self.text_start_x - metrics.horizontalAdvance('Status: ')) + display_text = 'Status: ' + ' ' * \ + (self.text_start_x - metrics.horizontalAdvance('Status: ')) display_text += visible_text self.status_label.setText(display_text) @@ -1078,9 +1134,11 @@ class CustomWindow(QMainWindow): def page_changed(self, index): if CustomWindow.should_be_synchronized(): - sync_icon = QtGui.QIcon(os.path.join(self.btn_path, 'icon_sync_urgent.png')) + sync_icon = QtGui.QIcon(os.path.join( + self.btn_path, 'icon_sync_urgent.png')) else: - sync_icon = QtGui.QIcon(os.path.join(self.btn_path, 'icon_sync.png')) + sync_icon = QtGui.QIcon(os.path.join( + self.btn_path, 'icon_sync.png')) self.sync_button.setIcon(sync_icon) @@ -1093,8 +1151,8 @@ class CustomWindow(QMainWindow): if isinstance(current_page, MenuPage): self.update_status(None) if isinstance(previous_page, (ResumePage, EditorPage, Settings, FastRegistrationPage, FastModePromptPage)): - current_page.eliminacion() - + current_page.eliminacion() + else: pass elif isinstance(current_page, ResumePage): @@ -1128,9 +1186,10 @@ class CustomWindow(QMainWindow): if isinstance(current_page, EditorPage): if not self.connection_manager.is_synced(): self.update_status('Not synchronized.') - + self.show() + class Page(QWidget): def __init__(self, name, page_stack, custom_window, parent=None): @@ -1141,14 +1200,14 @@ class Page(QWidget): self.page_stack = page_stack self.init_ui() self.selected_profiles = [] - self.selected_wireguard= [] # Lista para almacenar perfiles seleccionados - self.selected_residential= [] - self.buttons = [] + self.selected_wireguard = [] # Lista para almacenar perfiles seleccionados + self.selected_residential = [] + self.buttons = [] def add_selected_profile(self, profile): self.selected_profiles.clear() self.selected_wireguard.clear() - self.selected_residential.clear() + self.selected_residential.clear() self.selected_profiles.append(profile) # self.selected_wireguard.append(wireguard) # self.selected_residential.append(residential) @@ -1160,8 +1219,8 @@ class Page(QWidget): self.display = QLabel(self) self.display.setObjectName("display") - self.display.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - #self.display.setStyleSheet("background-color: yellow;") + self.display.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + # self.display.setStyleSheet("background-color: yellow;") buttons_info = [ (QPushButton, "button_back", "back", (660, 525, 48, 35)), (QPushButton, "button_next", "next", (720, 525, 48, 35)), @@ -1173,7 +1232,8 @@ class Page(QWidget): button = button_type(self) button.setObjectName(object_name) button.setGeometry(*geometry) - button.setIcon(QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) + button.setIcon( + QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) button.setIconSize(QtCore.QSize(48, 35)) button.setVisible(False) # Ocultar el botón inicialmente if object_name == "button_back": @@ -1192,8 +1252,6 @@ class Page(QWidget): if object_name == "button_apply": self.button_apply = button - - def gestionar_back(self): current_index = self.page_stack.currentIndex() @@ -1201,9 +1259,9 @@ class Page(QWidget): return if current_index > 0: self.page_stack.setCurrentIndex(current_index - 1) - + def gestionar_next(self): - + current_index = self.page_stack.currentIndex() next_index = (current_index + 1) % self.page_stack.count() self.page_stack.setCurrentIndex(next_index) @@ -1213,29 +1271,32 @@ class Page(QWidget): self.display.clear() for boton in self.buttons: boton.setChecked(False) - self.button_next.setVisible(False) class Worker(QObject): - update_signal = pyqtSignal(str, bool, int, int, str) + update_signal = pyqtSignal(str, bool, int, int, str) change_page = pyqtSignal(str, bool) def __init__(self, profile_data): self.profile_data = profile_data super().__init__() - profile_observer.subscribe('disabled', lambda event: self.handle_profile_status(event.subject, False)) - profile_observer.subscribe('enabled', lambda event: self.handle_profile_status(event.subject, True)) + profile_observer.subscribe( + 'disabled', lambda event: self.handle_profile_status(event.subject, False)) + profile_observer.subscribe( + 'enabled', lambda event: self.handle_profile_status(event.subject, True)) self.profile_type = None def run(self): self.profile = ProfileController.get(int(self.profile_data['id'])) if 'billing_code' in self.profile_data: - subscription = SubscriptionController.get(self.profile_data['billing_code'], connection_observer=connection_observer) + subscription = SubscriptionController.get( + self.profile_data['billing_code'], connection_observer=connection_observer) if subscription is not None: - ProfileController.attach_subscription(self.profile, subscription) + ProfileController.attach_subscription( + self.profile, subscription) else: self.change_page.emit('The billing code is invalid.', True) return @@ -1247,32 +1308,40 @@ class Worker(QObject): if self.profile_data.get('ignore_profile_state_conflict', False): ignore_exceptions.append(ProfileStateConflictError) ignore_tuple = tuple(ignore_exceptions) - ProfileController.enable(self.profile, ignore=ignore_tuple, profile_observer=profile_observer, - application_version_observer=application_version_observer, - connection_observer=connection_observer) + ProfileController.enable(self.profile, ignore=ignore_tuple, profile_observer=profile_observer, + application_version_observer=application_version_observer, + connection_observer=connection_observer) except EndpointVerificationError: - self.update_signal.emit("ENDPOINT_VERIFICATION_ERROR", False, self.profile_data['id'], None, None) + self.update_signal.emit( + "ENDPOINT_VERIFICATION_ERROR", False, self.profile_data['id'], None, None) except (InvalidSubscriptionError, MissingSubscriptionError) as e: - self.change_page.emit(f"Subscription missing or invalid for profile {self.profile_data['id']}", True) + self.change_page.emit( + f"Subscription missing or invalid for profile {self.profile_data['id']}", True) except ProfileActivationError: - self.update_signal.emit("The profile could not be enabled", False, None, None, None) + self.update_signal.emit( + "The profile could not be enabled", False, None, None, None) except UnsupportedApplicationVersionError: - self.update_signal.emit("The application version in question is not supported", False, None, None, None) + self.update_signal.emit( + "The application version in question is not supported", False, None, None, None) except FileIntegrityError: - self.update_signal.emit("Application version file integrity could not be verified.", False, None, None, None) + self.update_signal.emit( + "Application version file integrity could not be verified.", False, None, None, None) except ProfileModificationError: - self.update_signal.emit("WireGuard configuration could not be attached.", False, None, None, None) + self.update_signal.emit( + "WireGuard configuration could not be attached.", False, None, None, None) except ProfileStateConflictError: - self.update_signal.emit("PROFILE_STATE_CONFLICT_ERROR", False, self.profile_data['id'], None, None) - except CommandNotFoundError as e : + self.update_signal.emit( + "PROFILE_STATE_CONFLICT_ERROR", False, self.profile_data['id'], None, None) + except CommandNotFoundError as e: self.update_signal.emit(str(e.subject), False, -1, None, None) except Exception as e: print(e) - self.update_signal.emit("An unknown error occurred", False, None, None, None) + self.update_signal.emit( + "An unknown error occurred", False, None, None, None) else: - self.update_signal.emit(f"No profile found with ID: {self.profile_data['id']}", False, None, None, None) - + self.update_signal.emit( + f"No profile found with ID: {self.profile_data['id']}", False, None, None, None) def handle_profile_status(self, profile, is_enabled): profile_id = profile.id @@ -1286,7 +1355,8 @@ class Worker(QObject): else: self.profile_type = None - self.update_signal.emit(message, is_enabled, profile_id, self.profile_type, profile_connection) + self.update_signal.emit( + message, is_enabled, profile_id, self.profile_type, profile_connection) @staticmethod def generate_profile_message(profile, is_enabled, idle=False): @@ -1294,12 +1364,12 @@ class Worker(QObject): profile_id = profile.id if not profile.subscription or not profile.subscription.expires_at: return f"Offline. No subscription found." - + profile_date = profile.subscription.expires_at status = 'enabled' if is_enabled else 'disabled' expiration_date = profile_date.replace(tzinfo=timezone.utc) - + time_left = expiration_date - datetime.now(timezone.utc) days_left = time_left.days hours_left, remainder = divmod(time_left.seconds, 3600) @@ -1310,11 +1380,13 @@ class Worker(QObject): return "Offline. Subscription has expired." if idle: return f"Offline. Expires in {days_left} days." - + if is_enabled: return f"Profile {int(profile_id)} {status}. Expires on {formatted_expiration}. Time left: {days_left} days, {hours_left} hours." else: return f"Profile {int(profile_id)} {status}" + + class MenuPage(Page): def __init__(self, page_stack=None, main_window=None, parent=None): super().__init__("Menu", page_stack, main_window, parent) @@ -1328,13 +1400,16 @@ class MenuPage(Page): self.profile_info = {} self.additional_labels = [] self.update_status = main_window - self.title.setGeometry(400, 40, 380, 30); self.title.setText("Load Profile") + self.title.setGeometry(400, 40, 380, 30) + self.title.setText("Load Profile") self.scroll_area = QScrollArea(self) self.scroll_area.setGeometry(420, 80, 370, 350) self.scroll_area.setWidgetResizable(True) - self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) - self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.scroll_area.setHorizontalScrollBarPolicy( + Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.scroll_area.setVerticalScrollBarPolicy( + Qt.ScrollBarPolicy.ScrollBarAsNeeded) self.scroll_area.setStyleSheet(""" QScrollArea { background-color: transparent; @@ -1358,25 +1433,29 @@ class MenuPage(Page): height: 0px; } """) - + self.scroll_widget = QWidget() self.scroll_widget.setStyleSheet("background-color: transparent;") self.scroll_area.setWidget(self.scroll_widget) - - self.not_connected_profile = os.path.join(self.btn_path, "button_profile.png") - self.connected_profile = os.path.join(self.btn_path, "button_session_profile.png") - self.system_wide_connected_profile = os.path.join(self.btn_path, "button_system_profile.png") - self.connected_tor_profile = os.path.join(self.btn_path, "button_session_tor.png") + self.not_connected_profile = os.path.join( + self.btn_path, "button_profile.png") + self.connected_profile = os.path.join( + self.btn_path, "button_session_profile.png") + self.system_wide_connected_profile = os.path.join( + self.btn_path, "button_system_profile.png") + self.connected_tor_profile = os.path.join( + self.btn_path, "button_session_tor.png") self.worker = None self.IsSystem: int = 0 self.button_states = {} self.is_system_connected = False - self.profile_button_map = {} + self.profile_button_map = {} self.font_style = f"font-family: '{main_window.open_sans_family}';" if main_window.open_sans_family else "" - #self.label.setStyleSheet("background-color: rgba(0, 255, 0, 51);") - self.create_interface_elements() # Establecer el color de fondo y el color del texto utilizando hojas de estilo + # self.label.setStyleSheet("background-color: rgba(0, 255, 0, 51);") + # Establecer el color de fondo y el color del texto utilizando hojas de estilo + self.create_interface_elements() def showEvent(self, event): super().showEvent(event) @@ -1387,30 +1466,29 @@ class MenuPage(Page): verification_icons = parent.findChildren(QPushButton) for icon in verification_icons: if icon.geometry().width() == 20 and icon.geometry().height() == 20: - icon.setEnabled(self.connection_manager.is_synced()) + icon.setEnabled( + self.connection_manager.is_synced()) def on_update_check_finished(self): - reply = QMessageBox.question(self, 'Update Available', - 'An update is available. Would you like to download it?', - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) - if reply == QMessageBox.StandardButton.Yes: - self.worker = WorkerThread('DOWNLOAD_UPDATE') - self.worker.start() - else: - self.update_status.update_status('Update canceled') - - + reply = QMessageBox.question(self, 'Update Available', + 'An update is available. Would you like to download it?', + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + if reply == QMessageBox.StandardButton.Yes: + self.worker = WorkerThread('DOWNLOAD_UPDATE') + self.worker.start() + else: + self.update_status.update_status('Update canceled') def create_interface_elements(self): for icon_name, function, position in [ ("create_profile", self.create_prof, (410, 440, 110, 60)), ("edit_profile", self.edit_prof, (540, 440, 110, 60)), - #("delete_profile", self.delete_profile, (670, 440, 110, 60)), - ("launch", self.launch, (0, 440,185,63)), - ("disconnect", self.disconnect, (200, 433,185,73)), - ("disconnect_system_wide", self.disconnect, (200, 433,185,73)), - ("just", self.connect, (200, 433,185,73)), - ("just_session", self.connect, (200, 433,185,73)), + # ("delete_profile", self.delete_profile, (670, 440, 110, 60)), + ("launch", self.launch, (0, 440, 185, 63)), + ("disconnect", self.disconnect, (200, 433, 185, 73)), + ("disconnect_system_wide", self.disconnect, (200, 433, 185, 73)), + ("just", self.connect, (200, 433, 185, 73)), + ("just_session", self.connect, (200, 433, 185, 73)), ("settings", self.settings_gui, (670, 440, 110, 60)), ]: boton = QPushButton(self) @@ -1428,41 +1506,44 @@ class MenuPage(Page): if icon_name == "launch": self.boton_launch = boton self.boton_launch.setVisible(False) - if icon_name =="create_profile": - self.boton_create=boton + if icon_name == "create_profile": + self.boton_create = boton self.boton_create.setEnabled(True) - if icon_name =="edit_profile": - self.boton_edit=boton - #if icon_name =="delete_profile": + if icon_name == "edit_profile": + self.boton_edit = boton + # if icon_name =="delete_profile": # self.boton_settings=boton - if icon_name =="just": + if icon_name == "just": boton.setVisible(False) - self.boton_just=boton + self.boton_just = boton self.connect_button = boton - if icon_name =="just_session": - self.boton_just_session=boton + if icon_name == "just_session": + self.boton_just_session = boton self.connect_button = boton - if icon_name =="disconnect_system_wide": + if icon_name == "disconnect_system_wide": boton.setEnabled(True) boton.setVisible(False) self.disconnect_system_wide_button = boton - if icon_name =="settings": + if icon_name == "settings": self.settings_button = boton self.settings_button.setEnabled(True) - + self.create() def delete_profile(self): - self.popup = ConfirmationPopup(self, message="Are you sure you want to\ndelete this profile?", action_button_text="Delete", cancel_button_text="Cancel") + self.popup = ConfirmationPopup(self, message="Are you sure you want to\ndelete this profile?", + action_button_text="Delete", cancel_button_text="Cancel") self.popup.setWindowModality(Qt.WindowModality.ApplicationModal) - self.popup.finished.connect(lambda result: self.on_popup_finished(result)) + self.popup.finished.connect( + lambda result: self.on_popup_finished(result)) self.popup.show() - + def on_popup_finished(self, result): if result: profile_id = self.reverse_id self.update_status.update_status(f'Deleting profile...') - self.worker_thread = WorkerThread('DESTROY_PROFILE', profile_data={'id': profile_id}) + self.worker_thread = WorkerThread( + 'DESTROY_PROFILE', profile_data={'id': profile_id}) self.worker_thread.text_output.connect(self.delete_status_update) self.worker_thread.start() else: @@ -1483,7 +1564,7 @@ class MenuPage(Page): self.boton_just.setVisible(not toggle) except RuntimeError: pass - + def match_core_profiles(self, profiles_dict): new_dict = {} @@ -1495,13 +1576,14 @@ class MenuPage(Page): location = f'{profile.location.country_code}_{profile.location.code}' new_profile['location'] = location - + if protocol == 'wireguard': new_profile['protocol'] = 'wireguard' else: new_profile['protocol'] = 'hidetor' - connection_type = 'browser-only' if isinstance(profile, SessionProfile) else 'system-wide' + connection_type = 'browser-only' if isinstance( + profile, SessionProfile) else 'system-wide' if protocol == 'wireguard': new_profile['connection'] = connection_type @@ -1522,7 +1604,8 @@ class MenuPage(Page): new_profile['browser'] = 'unknown browser' new_profile['browser_supported'] = False - resolution = profile.resolution if hasattr(profile, 'resolution') else 'None' + resolution = profile.resolution if hasattr( + profile, 'resolution') else 'None' new_profile['dimentions'] = resolution new_profile['name'] = profile.name @@ -1530,34 +1613,36 @@ class MenuPage(Page): new_dict[f'Profile_{idx}'] = new_profile return new_dict - + def create(self): self.boton_just.setEnabled(False) self.boton_just_session.setEnabled(False) self.boton_edit.setEnabled(False) if hasattr(self, 'verification_button'): self.verification_button.setEnabled(False) - self.profiles_data = self.match_core_profiles(ProfileController.get_all()) + self.profiles_data = self.match_core_profiles( + ProfileController.get_all()) self.number_of_profiles = len(self.profiles_data) self.profile_info.update(self.profiles_data) self.button_group = QButtonGroup(self) self.buttons = [] - + for profile_name, profile_value in self.profiles_data.items(): self.create_profile_widget(profile_name, profile_value) - + self.update_scroll_widget_size() def refresh_profiles_data(self): - self.profiles_data = self.match_core_profiles(ProfileController.get_all()) + self.profiles_data = self.match_core_profiles( + ProfileController.get_all()) self.number_of_profiles = len(self.profiles_data) self.profile_info.update(self.profiles_data) for profile_name, profile_value in self.profiles_data.items(): self.create_profile_widget(profile_name, profile_value) self.update_scroll_widget_size() - + def refresh_menu_buttons(self): profiles = ProfileController.get_all() self.button_states.clear() @@ -1574,40 +1659,41 @@ class MenuPage(Page): elif isinstance(profile, SystemProfile): self.button_states[profile_id] = self.system_wide_connected_profile self.IsSystem += 1 - + if self.IsSystem > 0: - self.update_status.update_image(appearance_value='background_connected') + self.update_status.update_image( + appearance_value='background_connected') else: self.update_status.update_image() - + for widget in self.scroll_widget.findChildren(QLabel): widget.setParent(None) - + for widget in self.scroll_widget.findChildren(QPushButton): widget.setParent(None) - + self.profile_button_map.clear() self.button_group = QButtonGroup(self) self.buttons = [] - + self.create() def update_scroll_widget_size(self): if self.number_of_profiles == 0: return - + rows = (self.number_of_profiles + 1) // 2 height = rows * 120 self.scroll_widget.setFixedSize(370, height) def create_profile_widget(self, key, value): - profile_id = int(key.split('_')[1]) + profile_id = int(key.split('_')[1]) parent_label = self.create_parent_label(profile_id) button = self.create_profile_button(parent_label, profile_id, key) - + self.profile_button_map[profile_id] = button - + self.create_profile_name_label(parent_label, value["name"]) self.create_profile_icons(parent_label, value) @@ -1615,8 +1701,8 @@ class MenuPage(Page): parent_label = QLabel(self.scroll_widget) profile_list = list(self.profiles_data.keys()) index = profile_list.index(f'Profile_{profile_id}') - row, column = divmod(index, 2) - + row, column = divmod(index, 2) + parent_label.setGeometry(column * 179, row * 120, 175, 100) parent_label.setVisible(True) return parent_label @@ -1636,18 +1722,20 @@ class MenuPage(Page): background-color: rgba(200, 200, 200, 80); } """) - - icon = QIcon(self.button_states.get(profile_id, self.not_connected_profile)) + + icon = QIcon(self.button_states.get( + profile_id, self.not_connected_profile)) button.setIcon(icon) button.setIconSize(QtCore.QSize(175, 60)) - + button.show() button.setCheckable(True) self.button_group.addButton(button) self.buttons.append(button) - - button.clicked.connect(lambda checked, pid=profile_id: self.print_profile_details(f"Profile_{pid}")) - + + button.clicked.connect( + lambda checked, pid=profile_id: self.print_profile_details(f"Profile_{pid}")) + return button def create_profile_name_label(self, parent_label, name): @@ -1655,7 +1743,8 @@ class MenuPage(Page): child_label.setGeometry(0, 65, 175, 30) child_label.setText(name) child_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - child_label.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents) + child_label.setAttribute( + Qt.WidgetAttribute.WA_TransparentForMouseEvents) child_label.show() def create_profile_icons(self, parent_label, value): @@ -1671,22 +1760,26 @@ class MenuPage(Page): child_label.setObjectName(f"label_{j}") child_label.setGeometry(3 + j * 60, 5, 50, 50) child_label.setObjectName("label_profiles") - child_label.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents) - child_label.setStyleSheet("background-color: rgba(128, 128, 128, 0.5); border-radius: 25px;") + child_label.setAttribute( + Qt.WidgetAttribute.WA_TransparentForMouseEvents) + child_label.setStyleSheet( + "background-color: rgba(128, 128, 128, 0.5); border-radius: 25px;") image_path = self.get_icon_path(label_name, value, connection_type) pixmap = QPixmap(image_path) if pixmap.isNull() and label_name == 'location': - fallback_path = os.path.join(self.btn_path, "default_location_mini.png") + fallback_path = os.path.join( + self.btn_path, "default_location_mini.png") pixmap = QPixmap(fallback_path) if pixmap.isNull(): pixmap = QPixmap(50, 50) - pixmap.fill(QtGui.QColor(200, 200, 200)) + pixmap.fill(QtGui.QColor(200, 200, 200)) if pixmap.isNull() and label_name == 'browser': - fallback_path = os.path.join(self.btn_path, "default_browser_mini.png") + fallback_path = os.path.join( + self.btn_path, "default_browser_mini.png") pixmap = QPixmap(fallback_path) if pixmap.isNull(): pixmap = QPixmap(50, 50) - pixmap.fill(QtGui.QColor(200, 200, 200)) + pixmap.fill(QtGui.QColor(200, 200, 200)) child_label.setPixmap(pixmap) child_label.show() @@ -1696,28 +1789,34 @@ class MenuPage(Page): child_label.setObjectName(f"label_{j}") child_label.setGeometry(3 + j * 60, 5, 50, 50) child_label.setObjectName("label_profiles") - child_label.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents) - child_label.setStyleSheet("background-color: rgba(128, 128, 128, 0.5); border-radius: 25px;") + child_label.setAttribute( + Qt.WidgetAttribute.WA_TransparentForMouseEvents) + child_label.setStyleSheet( + "background-color: rgba(128, 128, 128, 0.5); border-radius: 25px;") image_path = self.get_icon_path(label_name, value, connection_type) pixmap = QPixmap(image_path) if pixmap.isNull() and label_name == 'location': - fallback_path = os.path.join(self.btn_path, "default_location_mini.png") + fallback_path = os.path.join( + self.btn_path, "default_location_mini.png") pixmap = QPixmap(fallback_path) if pixmap.isNull(): pixmap = QPixmap(50, 50) - pixmap.fill(QtGui.QColor(200, 200, 200)) + pixmap.fill(QtGui.QColor(200, 200, 200)) if pixmap.isNull() and label_name == 'browser': - fallback_path = os.path.join(self.btn_path, "default_browser_mini.png") + fallback_path = os.path.join( + self.btn_path, "default_browser_mini.png") pixmap = QPixmap(fallback_path) if pixmap.isNull(): pixmap = QPixmap(50, 50) - pixmap.fill(QtGui.QColor(200, 200, 200)) + pixmap.fill(QtGui.QColor(200, 200, 200)) if label_name == 'browser' and not value.get('browser_supported', True) and value.get('browser') != 'unknown browser': - warning_pixmap = QPixmap(os.path.join(self.btn_path, 'warning.png')) + warning_pixmap = QPixmap( + os.path.join(self.btn_path, 'warning.png')) painter = QPainter(pixmap) - painter.drawPixmap(pixmap.width() - 22, pixmap.height() - 21, warning_pixmap) + painter.drawPixmap(pixmap.width() - 22, + pixmap.height() - 21, warning_pixmap) painter.end() child_label.setPixmap(pixmap) @@ -1736,7 +1835,7 @@ class MenuPage(Page): return os.path.join(self.btn_path, "wireguard_system_wide.png") else: return os.path.join(self.btn_path, f"{value[label_name]} latest_mini.png") - + return os.path.join(self.btn_path, f"icon_mini_{value[label_name]}.png") def truncate_key(self, text, max_length=50): @@ -1750,50 +1849,53 @@ class MenuPage(Page): verification_widget = QWidget(self) verification_widget.setGeometry(0, 90, 400, 300) verification_widget.setStyleSheet("background: transparent;") - + verification_layout = QVBoxLayout(verification_widget) verification_layout.setContentsMargins(20, 20, 20, 20) verification_layout.setSpacing(15) - + operator = None if profile_obj.location and profile_obj.location.operator: operator = profile_obj.location.operator - + info_items = [ ("Operator Name", "operator_name"), ("Nostr Key", "nostr_public_key"), ("HydraVeil Key", "hydraveil_public_key"), ] - + for label, key in info_items: container = QWidget() container.setStyleSheet("background: transparent;") container_layout = QHBoxLayout(container) container_layout.setContentsMargins(0, 0, 0, 0) container_layout.setSpacing(10) - + label_widget = QLabel(label + ":") - label_widget.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}") + label_widget.setStyleSheet( + f"color: white; font-size: 12px; {self.font_style}") label_widget.setMinimumWidth(120) container_layout.addWidget(label_widget) - + value_widget = QLineEdit() value_widget.setReadOnly(True) - + if operator: if key == "operator_name": value = operator.name or "N/A" elif key == "nostr_public_key": value = operator.nostr_public_key or "N/A" - value = self.truncate_key(value) if value != "N/A" else value + value = self.truncate_key( + value) if value != "N/A" else value elif key == "hydraveil_public_key": value = operator.public_key or "N/A" - value = self.truncate_key(value) if value != "N/A" else value + value = self.truncate_key( + value) if value != "N/A" else value else: value = "N/A" else: value = "N/A" - + value_widget.setText(value) value_widget.setCursorPosition(0) value_widget.setStyleSheet(f""" @@ -1808,9 +1910,10 @@ class MenuPage(Page): }} """) container_layout.addWidget(value_widget, 1) - + checkmark_widget = QLabel("✓") - checkmark_widget.setStyleSheet(f"color: #4CAF50; font-size: 20px; font-weight: bold; {self.font_style}") + checkmark_widget.setStyleSheet( + f"color: #4CAF50; font-size: 20px; font-weight: bold; {self.font_style}") checkmark_widget.setFixedSize(20, 20) checkmark_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) if value and value != "N/A": @@ -1818,9 +1921,10 @@ class MenuPage(Page): else: checkmark_widget.hide() container_layout.addWidget(checkmark_widget) - + copy_button = QPushButton() - copy_button.setIcon(QIcon(os.path.join(self.btn_path, "paste_button.png"))) + copy_button.setIcon( + QIcon(os.path.join(self.btn_path, "paste_button.png"))) copy_button.setIconSize(QSize(24, 24)) copy_button.setFixedSize(30, 30) copy_button.setStyleSheet(f""" @@ -1833,7 +1937,7 @@ class MenuPage(Page): border-radius: 4px; }} """) - + if operator: if key == "operator_name": full_value = operator.name or "N/A" @@ -1845,30 +1949,34 @@ class MenuPage(Page): full_value = "N/A" else: full_value = "N/A" - - copy_button.clicked.connect(lambda checked=False, val=full_value: self.copy_verification_value(val)) + + copy_button.clicked.connect( + lambda checked=False, val=full_value: self.copy_verification_value(val)) container_layout.addWidget(copy_button) - + verification_layout.addWidget(container) - + verification_widget.show() return verification_widget - + def copy_verification_value(self, value): if value and value != "N/A": clipboard = QApplication.clipboard() clipboard.setText(value) - self.update_status.update_status("Verification value copied to clipboard") + self.update_status.update_status( + "Verification value copied to clipboard") def print_profile_details(self, profile_name): - self.reverse_id = int(profile_name.split('_')[1]) - + self.reverse_id = int(profile_name.split('_')[1]) + target_button = self.profile_button_map.get(self.reverse_id) if target_button: - self.connection_manager.set_profile_button_objects(self.reverse_id, target_button) + self.connection_manager.set_profile_button_objects( + self.reverse_id, target_button) else: print(f"No button found for profile {self.reverse_id}") - is_connected = self.connection_manager.is_profile_connected(int(self.reverse_id)) + is_connected = self.connection_manager.is_profile_connected( + int(self.reverse_id)) if is_connected: self.boton_edit.setEnabled(False) else: @@ -1886,19 +1994,17 @@ class MenuPage(Page): verification_icons = parent.findChildren(QPushButton) for icon in verification_icons: if icon.geometry().width() == 20 and icon.geometry().height() == 20: - icon.setEnabled(self.connection_manager.is_synced()) - #self.boton_settings.setEnabled(True) + icon.setEnabled( + self.connection_manager.is_synced()) + # self.boton_settings.setEnabled(True) - # Eliminar labels adicionales anteriores for label in self.additional_labels: label.deleteLater() - + # Limpiar la lista de labels adicionales self.additional_labels.clear() - - self.change_connect_button() if profile: @@ -1907,35 +2013,39 @@ class MenuPage(Page): name = profile.get("name", "") protocol = profile.get("protocol", "") location = profile.get("location", "") - connection = profile.get("connection", "") + connection = profile.get("connection", "") country_garaje = profile.get("country_garaje", "") - + profile_obj = ProfileController.get(self.reverse_id) - is_profile_enabled = self.connection_manager.is_profile_connected(self.reverse_id) + is_profile_enabled = self.connection_manager.is_profile_connected( + self.reverse_id) show_verification_widget = False - - if protocol.lower() in ["wireguard", "open", "lokinet","residential", "hidetor"]: + + if protocol.lower() in ["wireguard", "open", "lokinet", "residential", "hidetor"]: label_principal = None - if protocol.lower() == "wireguard" and is_profile_enabled and profile_obj and profile_obj.connection and profile_obj.connection.code == 'wireguard': - verification_widget = self.create_verification_widget(profile_obj) + if protocol.lower() == "wireguard" and is_profile_enabled and profile_obj and profile_obj.connection and profile_obj.connection.code == 'wireguard': + verification_widget = self.create_verification_widget( + profile_obj) self.additional_labels.append(verification_widget) show_verification_widget = True label_principal = None else: label_principal = QLabel(self) label_principal.setGeometry(0, 90, 400, 300) - pixmap=QPixmap(os.path.join(self.btn_path, f"{protocol}_{location}.png")) + pixmap = QPixmap(os.path.join( + self.btn_path, f"{protocol}_{location}.png")) label_principal.setPixmap(pixmap) label_principal.setScaledContents(True) label_principal.show() self.additional_labels.append(label_principal) - + if protocol.lower() == "wireguard" and ConfigurationController.get_endpoint_verification_enabled(): if is_profile_enabled and profile_obj and profile_obj.connection and profile_obj.connection.code == 'wireguard': verified_icon = QLabel(self) verified_icon.setGeometry(20, 50, 100, 80) - verified_pixmap = QPixmap(os.path.join(self.btn_path, "verified_profile.png")) + verified_pixmap = QPixmap(os.path.join( + self.btn_path, "verified_profile.png")) verified_icon.setPixmap(verified_pixmap) verified_icon.setScaledContents(True) verified_icon.show() @@ -1946,11 +2056,13 @@ class MenuPage(Page): if label_principal: label_principal.setGeometry(0, 80, 400, 300) label_background = QLabel(self) - label_background.setGeometry(0, 60, 410, 354) + label_background.setGeometry(0, 60, 410, 354) if connection == 'just proxy': - image_path = os.path.join(self.btn_path, f"icon_{location}.png") + image_path = os.path.join( + self.btn_path, f"icon_{location}.png") else: - image_path = os.path.join(self.btn_path, f"hdtor_{location}.png") + image_path = os.path.join( + self.btn_path, f"hdtor_{location}.png") pixmap = QPixmap(image_path) label_background.setPixmap(pixmap) label_background.show() @@ -1958,12 +2070,11 @@ class MenuPage(Page): label_background.lower() self.additional_labels.append(label_background) - if protocol.lower() == "wireguard" and connection.lower() == "browser-only" and not show_verification_widget: if label_principal: label_principal.setGeometry(0, 80, 400, 300) - + label_background = QLabel(self) label_background.setGeometry(0, 60, 410, 354) is_supported = profile.get('browser_supported', False) @@ -1974,25 +2085,27 @@ class MenuPage(Page): label_background.setScaledContents(True) label_background.lower() self.additional_labels.append(label_background) - + if protocol.lower() == "residential" and connection.lower() == "tor": label_background = QLabel(self) label_background.setGeometry(0, 60, 410, 354) - pixmap = QPixmap(os.path.join(self.btn_path, "browser_tor.png")) + pixmap = QPixmap(os.path.join( + self.btn_path, "browser_tor.png")) label_background.setPixmap(pixmap) label_background.show() label_background.setScaledContents(True) - #label_background.setStyleSheet("background-color: blue;") + # label_background.setStyleSheet("background-color: blue;") self.additional_labels.append(label_background) label_garaje = QLabel(self) label_garaje.setGeometry(5, 110, 400, 300) - pixmap = QPixmap(os.path.join(self.btn_path, f"{country_garaje} garaje.png")) + pixmap = QPixmap(os.path.join( + self.btn_path, f"{country_garaje} garaje.png")) label_garaje.setPixmap(pixmap) label_garaje.show() label_garaje.setScaledContents(True) - #label_garaje.setStyleSheet("background-color: red;") + # label_garaje.setStyleSheet("background-color: red;") self.additional_labels.append(label_garaje) label_tor = QLabel(self) @@ -2003,62 +2116,67 @@ class MenuPage(Page): label_tor.setScaledContents(True) self.additional_labels.append(label_tor) if protocol.lower() == "residential" and connection.lower() == "just proxy": - + label_background = QLabel(self) label_background.setGeometry(0, 60, 410, 354) - pixmap = QPixmap(os.path.join(self.btn_path, "browser_just_proxy.png")) + pixmap = QPixmap(os.path.join( + self.btn_path, "browser_just_proxy.png")) label_background.setPixmap(pixmap) label_background.show() label_background.setScaledContents(True) - #label_background.setStyleSheet("background-color: blue;") + # label_background.setStyleSheet("background-color: blue;") self.additional_labels.append(label_background) label_garaje = QLabel(self) label_garaje.setGeometry(5, 110, 400, 300) - pixmap = QPixmap(os.path.join(self.btn_path, f"{country_garaje} garaje.png")) + pixmap = QPixmap(os.path.join( + self.btn_path, f"{country_garaje} garaje.png")) label_garaje.setPixmap(pixmap) label_garaje.show() label_garaje.setScaledContents(True) - #label_garaje.setStyleSheet("background-color: red;") + # label_garaje.setStyleSheet("background-color: red;") self.additional_labels.append(label_garaje) # Actualizar perfil para editar - editar_profile = {"profile_number": profile_number, "name": name, "protocol": protocol} + editar_profile = {"profile_number": profile_number, + "name": name, "protocol": protocol} self.page_stack.currentWidget().add_selected_profile(editar_profile) - + self.current_profile_location = location def show_profile_verification(self, profile_id): profile = ProfileController.get(profile_id) if not profile or not profile.location: return - + location_key = f'{profile.location.country_code}_{profile.location.code}' location_info = self.connection_manager.get_location_info(location_key) if not location_info: return - + location_icon_name = None btn_path = self.btn_path - + for icon_file in os.listdir(btn_path): if icon_file.startswith('button_') and icon_file.endswith('.png'): - icon_name = icon_file.replace('button_', '').replace('.png', '') + icon_name = icon_file.replace( + 'button_', '').replace('.png', '') test_loc = self.connection_manager.get_location_info(icon_name) if test_loc and test_loc.country_code == location_info.country_code and test_loc.code == location_info.code: location_icon_name = icon_name break - - if location_icon_name: - verification_page = LocationVerificationPage(self.page_stack, self.update_status, location_icon_name, self) - self.page_stack.addWidget(verification_page) - self.page_stack.setCurrentIndex(self.page_stack.indexOf(verification_page)) - def launch(self): + if location_icon_name: + verification_page = LocationVerificationPage( + self.page_stack, self.update_status, location_icon_name, self) + self.page_stack.addWidget(verification_page) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(verification_page)) + + def launch(self): pass - - - def connect(self): + + def connect(self): self.boton_just.setEnabled(False) self.boton_just_session.setEnabled(False) @@ -2070,22 +2188,24 @@ class MenuPage(Page): else: self.get_billing_code_by_id() return - - self.popup = self.update_status._create_confirmation_popup(message, button_text='Proceed') - self.popup.finished.connect(lambda result: self._handle_popup_result(result)) + + self.popup = self.update_status._create_confirmation_popup( + message, button_text='Proceed') + self.popup.finished.connect( + lambda result: self._handle_popup_result(result)) self.popup.show() - - + def _handle_popup_result(self, result, change_screen=False): if result: if change_screen: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(IdPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(IdPage))) else: self.get_billing_code_by_id() else: self.popup.close() - def disconnect(self): + def disconnect(self): self.disconnect_button.setEnabled(False) self.disconnect_system_wide_button.setEnabled(False) self.update_status.update_status('Disconnecting...') @@ -2098,11 +2218,13 @@ class MenuPage(Page): connected_profiles = self.connection_manager.get_connected_profiles() if len(connected_profiles) > 1: message = f'Profile{"" if len(connected_profiles) == 1 else "s"} {", ".join(str(profile_id) for profile_id in connected_profiles)} are still connected.\nAll connected session profiles will be disconnected. \nDo you want to proceed?' - self.update_status._show_disconnect_confirmation(connected_profiles, button_text='Disable', message=message) + self.update_status._show_disconnect_confirmation( + connected_profiles, button_text='Disable', message=message) self.disconnect_button.setEnabled(True) self.disconnect_system_wide_button.setEnabled(True) return - self.worker_thread = WorkerThread('DISABLE_PROFILE', profile_data=profile_data) + self.worker_thread = WorkerThread( + 'DISABLE_PROFILE', profile_data=profile_data) self.worker_thread.finished.connect(self.on_disconnect_done) self.worker_thread.start() @@ -2111,100 +2233,108 @@ class MenuPage(Page): self.disconnect_system_wide_button.setEnabled(True) pass - def create_prof(self): + def create_prof(self): settings_page = self.page_stack.findChild(Settings) if settings_page and settings_page.is_fast_registration_enabled(): if not self.connection_manager.is_synced(): self.update_status.update_status('Syncing in progress..') self.update_status.sync() - self.update_status.worker_thread.sync_output.connect(self.on_sync_complete_for_fast_registration) + self.update_status.worker_thread.sync_output.connect( + self.on_sync_complete_for_fast_registration) else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(FastRegistrationPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(FastRegistrationPage))) return - if not self.connection_manager.is_synced(): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(SyncScreen))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(SyncScreen))) else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ProtocolPage))) - - + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ProtocolPage))) def on_sync_complete_for_fast_registration(self, available_locations, available_browsers, status, is_tor, locations, all_browsers): if status: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(FastRegistrationPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(FastRegistrationPage))) else: - self.update_status.update_status('Sync failed. Please try again later.') - + self.update_status.update_status( + 'Sync failed. Please try again later.') def change_connect_button(self): profile = ProfileController.get(int(self.reverse_id)) - is_connected = self.connection_manager.is_profile_connected(int(self.reverse_id)) + is_connected = self.connection_manager.is_profile_connected( + int(self.reverse_id)) is_session_profile = isinstance(profile, SessionProfile) self.update_button_visibility(is_connected, is_session_profile) self.update_status_message(profile, is_connected) def update_button_visibility(self, is_connected, is_session_profile): - self.boton_just_session.setVisible(not is_connected and is_session_profile) + self.boton_just_session.setVisible( + not is_connected and is_session_profile) self.boton_just.setVisible(not is_connected and not is_session_profile) self.disconnect_button.setVisible(is_connected and is_session_profile) - self.disconnect_system_wide_button.setVisible(is_connected and not is_session_profile) + self.disconnect_system_wide_button.setVisible( + is_connected and not is_session_profile) def update_status_message(self, profile, is_connected): if is_connected: message = Worker.generate_profile_message(profile, is_enabled=True) self.update_status.enable_marquee(message) else: - message = Worker.generate_profile_message(profile, is_enabled=True, idle=True) + message = Worker.generate_profile_message( + profile, is_enabled=True, idle=True) self.update_status.update_status(message) - - def edit_prof(self): + def edit_prof(self): settings_page = self.page_stack.findChild(Settings) if settings_page and settings_page.is_auto_sync_enabled() and not self.connection_manager.is_synced(): self.update_status.update_status('Syncing in progress..') self.update_status.sync() - self.update_status.worker_thread.sync_output.connect(self.on_sync_complete_for_edit_profile) + self.update_status.worker_thread.sync_output.connect( + self.on_sync_complete_for_edit_profile) else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(EditorPage))) - + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(EditorPage))) def on_sync_complete_for_edit_profile(self, available_locations, available_browsers, status, is_tor, locations, all_browsers): if status: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(EditorPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(EditorPage))) else: - self.update_status.update_status('Sync failed. Please try again later.') + self.update_status.update_status( + 'Sync failed. Please try again later.') + def settings_gui(self): + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(Settings))) - - - def settings_gui(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(Settings))) def eliminacion(self): current_state = { 'is_tor_mode': self.is_tor_mode, 'is_animating': self.is_animating, 'animation_step': self.animation_step } - + self.main_window.toggle_bg.setParent(None) self.main_window.toggle_handle.setParent(None) self.main_window.on_label.setParent(None) self.main_window.off_label.setParent(None) - + self.refresh_menu_buttons() self.main_window.toggle_bg.setParent(self.main_window.toggle_button) - self.main_window.toggle_handle.setParent(self.main_window.toggle_button) + self.main_window.toggle_handle.setParent( + self.main_window.toggle_button) self.main_window.on_label.setParent(self.main_window.toggle_button) self.main_window.off_label.setParent(self.main_window.toggle_button) - + self.main_window.toggle_bg.show() self.main_window.toggle_handle.show() self.main_window.on_label.show() self.main_window.off_label.show() - + self.is_tor_mode = current_state['is_tor_mode'] self.is_animating = current_state['is_animating'] self.animation_step = current_state['animation_step'] @@ -2218,7 +2348,7 @@ class MenuPage(Page): 'force': force } self.update_status.update_status('Attempting to connect...') - + self.enabling_profile(profile_data) def enabling_profile(self, profile_data): @@ -2241,7 +2371,8 @@ class MenuPage(Page): def handle_enable_force_result(self, result): if result: - profile_data = {'id': self.reverse_id, 'ignore_profile_state_conflict': True} + profile_data = {'id': self.reverse_id, + 'ignore_profile_state_conflict': True} if hasattr(self, '_pending_endpoint_verification_ignore') and self._pending_endpoint_verification_ignore: profile_data['ignore_endpoint_verification'] = True self.enabling_profile(profile_data) @@ -2252,24 +2383,27 @@ class MenuPage(Page): if hasattr(self, '_pending_endpoint_verification_ignore'): delattr(self, '_pending_endpoint_verification_ignore') self.popup.close() - + def handle_endpoint_verification_result(self, result, action, profile_id): if action == "continue": - profile_data = {'id': profile_id, 'ignore_endpoint_verification': True} + profile_data = {'id': profile_id, + 'ignore_endpoint_verification': True} if hasattr(self, '_pending_profile_state_conflict_ignore') and self._pending_profile_state_conflict_ignore: profile_data['ignore_profile_state_conflict'] = True self.enabling_profile(profile_data) elif action == "sync": self.update_status.update_status("Syncing...") self.worker_thread = WorkerThread('SYNC') - self.worker_thread.finished.connect(lambda: self.handle_sync_after_verification(profile_id)) - self.worker_thread.sync_output.connect(self.update_status.update_values) + self.worker_thread.finished.connect( + lambda: self.handle_sync_after_verification(profile_id)) + self.worker_thread.sync_output.connect( + self.update_status.update_values) self.worker_thread.start() else: self.update_status.update_status("Profile enable aborted") if hasattr(self, 'popup'): self.popup.close() - + def handle_sync_after_verification(self, profile_id): profile_data = {'id': profile_id} if hasattr(self, '_pending_profile_state_conflict_ignore') and self._pending_profile_state_conflict_ignore: @@ -2280,19 +2414,21 @@ class MenuPage(Page): if text == "ENDPOINT_VERIFICATION_ERROR": message = "Operator verification failed. Do you want to continue anyway?" self.popup = EndpointVerificationPopup(self, message=message) - self.popup.finished.connect(lambda result, action: self.handle_endpoint_verification_result(result, action, profile_id)) + self.popup.finished.connect( + lambda result, action: self.handle_endpoint_verification_result(result, action, profile_id)) self.popup.show() return - + if text == "PROFILE_STATE_CONFLICT_ERROR": message = f'The profile is already enabled. Do you want to force enable it anyway?' self._pending_profile_state_conflict_ignore = True - self.popup = self.update_status._create_confirmation_popup(message, button_text='Proceed') - self.popup.finished.connect(lambda result: self.handle_enable_force_result(result)) + self.popup = self.update_status._create_confirmation_popup( + message, button_text='Proceed') + self.popup.finished.connect( + lambda result: self.handle_enable_force_result(result)) self.popup.show() return - - + if profile_id < 0: self.DisplayInstallScreen(text) return @@ -2301,7 +2437,8 @@ class MenuPage(Page): else: self.update_status.update_status(str(text)) if profile_id is not None: - self.on_finished_update_gui(is_enabled, profile_id, profile_type, profile_connection) + self.on_finished_update_gui( + is_enabled, profile_id, profile_type, profile_connection) self.boton_just.setEnabled(True) self.boton_just_session.setEnabled(True) @@ -2312,21 +2449,25 @@ class MenuPage(Page): profile = ProfileController.get(int(self.reverse_id)) if current_connection != 'tor' and profile.connection.code == 'tor': message = f'You are using a Tor profile, but the profile subscription is missing or expired. If you want the billing to be done thourgh Tor, you must switch to a Tor connection. Otherwise, proceed with a clearweb connection.' - self.popup = self.update_status._create_confirmation_popup(message, button_text='Proceed') - self.popup.finished.connect(lambda result: self._handle_popup_result(result, True)) + self.popup = self.update_status._create_confirmation_popup( + message, button_text='Proceed') + self.popup.finished.connect( + lambda result: self._handle_popup_result(result, True)) self.popup.show() else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(IdPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(IdPage))) self.boton_just.setEnabled(True) self.boton_just_session.setEnabled(True) def on_finished_update_gui(self, is_enabled, profile_id, profile_type, profile_connection): - try: + try: if is_enabled: self.connection_manager.add_connected_profile(profile_id) - target_button: QPushButton = self.connection_manager.get_profile_button_objects(profile_id) - + target_button: QPushButton = self.connection_manager.get_profile_button_objects( + profile_id) + if profile_type == 1: if target_button: icon_path = self.connected_tor_profile if profile_connection == 'tor' else self.connected_profile @@ -2338,17 +2479,20 @@ class MenuPage(Page): else: if target_button: try: - target_button.setIcon(QIcon(self.system_wide_connected_profile)) + target_button.setIcon( + QIcon(self.system_wide_connected_profile)) except RuntimeError: pass - self.update_status.update_image(appearance_value='background_connected') + self.update_status.update_image( + appearance_value='background_connected') self.button_states[profile_id] = self.system_wide_connected_profile self.IsSystem += 1 if target_button: - self.show_disconnect_button(True, profile_type, target_button) + self.show_disconnect_button( + True, profile_type, target_button) self.boton_edit.setEnabled(False) - + if profile_id == self.reverse_id: profile_obj = ProfileController.get(profile_id) if profile_obj and profile_obj.connection and profile_obj.connection.code == 'wireguard' and ConfigurationController.get_endpoint_verification_enabled(): @@ -2366,13 +2510,14 @@ class MenuPage(Page): self.update_status.update_image() self.boton_edit.setEnabled(True) - + if profile_id == self.reverse_id: self.print_profile_details(f"Profile_{profile_id}") self.refresh_menu_buttons() except IndexError: - self.update_status.update_status('An error occurred while updating profile state.') + self.update_status.update_status( + 'An error occurred while updating profile state.') class ConnectionManager: @@ -2381,25 +2526,26 @@ class ConnectionManager: self._is_synced = False self._is_profile_being_enabled = {} self.profile_button_objects = {} - self.available_resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] + self.available_resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', + '1920x1080', '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] self._location_list = [] self._browser_list = [] def get_profile_button_objects(self, profile_id): return self.profile_button_objects.get(profile_id, None) - + def set_profile_button_objects(self, profile_id, profile_button_objects): self.profile_button_objects[profile_id] = profile_button_objects - + def get_available_resolutions(self, profile_id): profile = ProfileController.get(profile_id) if profile and hasattr(profile, 'resolution') and profile.resolution: self.available_resolutions.append(profile.resolution) return self.available_resolutions - + def add_custom_resolution(self, resolution): self.available_resolutions.append(resolution) - + def add_connected_profile(self, profile_id): self._connected_profiles.add(profile_id) @@ -2417,7 +2563,6 @@ class ConnectionManager: def is_synced(self): return self._is_synced - def get_location_info(self, location_key): if not location_key: @@ -2427,13 +2572,13 @@ class ConnectionManager: for location in self._location_list: if location.country_code == country_code and location.code == location_code: return location - + return None except (ValueError, AttributeError): return None def store_locations(self, locations): - self._location_list = locations + self._location_list = locations def store_browsers(self, browsers): self._browser_list = browsers @@ -2441,16 +2586,13 @@ class ConnectionManager: def get_browser_list(self): return self._browser_list - - def get_location_list(self): if self.is_synced(): - location_names = [f'{location.country_code}_{location.code}' for location in self._location_list] + location_names = [ + f'{location.country_code}_{location.code}' for location in self._location_list] return location_names else: return [] - - class InstallSystemPackage(Page): @@ -2466,7 +2608,7 @@ class InstallSystemPackage(Page): self.permanent_elements = [] self.current_distro = "debian" self.distro_buttons = {} - + self._setup_permanent_ui() self._setup_distro_buttons() @@ -2571,20 +2713,21 @@ class InstallSystemPackage(Page): self.title.setText("Package Installation") self.title.setStyleSheet("font-size: 22px; font-weight: bold;") self.permanent_elements.append(self.title) - + self.display.setGeometry(QtCore.QRect(100, 160, 580, 435)) self.permanent_elements.append(self.display) def _setup_distro_buttons(self): distros = ["debian", "arch", "fedora"] - + for i, distro in enumerate(distros): btn = QPushButton(self) btn.setGeometry(360 + i*140, 40, 120, 49) btn.setIcon(QIcon(os.path.join(self.btn_path, f"{distro}.png"))) btn.setIconSize(QSize(120, 49)) btn.setCheckable(True) - btn.clicked.connect(lambda checked, d=distro: self.switch_distro(d)) + btn.clicked.connect( + lambda checked, d=distro: self.switch_distro(d)) self.distro_buttons[distro] = btn self.permanent_elements.append(btn) @@ -2592,23 +2735,27 @@ class InstallSystemPackage(Page): def switch_distro(self, distro): self.current_distro = distro - + for d, btn in self.distro_buttons.items(): btn.setChecked(d == distro) - + if self.package_name: self.update_command() - self.setup_ui() + self.setup_ui() def update_command(self): - + if self.package_name in self.auto_install_package_commands: if self.is_sync: - self.install_command = self.auto_install_package_commands['tor_sync'][self.current_distro] - self.manual_install_command = self.manual_install_package_commands['tor_sync'][self.current_distro] + self.install_command = self.auto_install_package_commands[ + 'tor_sync'][self.current_distro] + self.manual_install_command = self.manual_install_package_commands[ + 'tor_sync'][self.current_distro] else: - self.install_command = self.auto_install_package_commands[self.package_name][self.current_distro] - self.manual_install_command = self.manual_install_package_commands[self.package_name][self.current_distro] + self.install_command = self.auto_install_package_commands[ + self.package_name][self.current_distro] + self.manual_install_command = self.manual_install_package_commands[ + self.package_name][self.current_distro] else: self.install_command = "" self.manual_install_command = "" @@ -2624,42 +2771,42 @@ class InstallSystemPackage(Page): def setup_ui(self): self.button_back.setVisible(False) self.button_go.setVisible(True) - if not self.package_name: + if not self.package_name: return - + self.clear_ui() - - - + self._setup_auto_install() self._setup_manual_install() - + self._setup_status_and_nav() - + for element in self.ui_elements: element.setParent(self) element.setVisible(True) - element.raise_() + element.raise_() def clear_ui(self): for element in self.ui_elements: - element.setParent(None) + element.setParent(None) element.deleteLater() self.ui_elements.clear() - + self.command_box = None self.status_label = None self.install_button = None self.check_button = None def _setup_auto_install(self): - auto_install_label = QLabel(f"Automatic Installation for {self.current_distro}", self) + auto_install_label = QLabel( + f"Automatic Installation for {self.current_distro}", self) auto_install_label.setGeometry(80, 130, 580, 30) auto_install_label.setStyleSheet("font-size: 18px; font-weight: bold;") auto_install_label.setVisible(True) self.ui_elements.append(auto_install_label) - - auto_install_desc = QLabel("Click the button below to automatically install the missing packages:", self) + + auto_install_desc = QLabel( + "Click the button below to automatically install the missing packages:", self) auto_install_desc.setStyleSheet("font-size: 14px; font-weight: bold;") auto_install_desc.setGeometry(80, 170, 650, 30) auto_install_desc.setVisible(True) @@ -2667,7 +2814,8 @@ class InstallSystemPackage(Page): self.install_button = QPushButton(self) self.install_button.setGeometry(135, 210, 100, 40) - self.install_button.setIcon(QIcon(os.path.join(self.btn_path, "install.png"))) + self.install_button.setIcon( + QIcon(os.path.join(self.btn_path, "install.png"))) self.install_button.setIconSize(self.install_button.size()) self.install_button.clicked.connect(self.install_package) self.install_button.setVisible(True) @@ -2676,12 +2824,13 @@ class InstallSystemPackage(Page): if self.current_distro == 'arch': auto_install_label.setGeometry(50, 110, 580, 30) auto_install_desc.setGeometry(50, 140, 650, 30) - + self.install_button.setGeometry(150, 185, 100, 40) self.check_button = QPushButton(self) self.check_button.setGeometry(270, 185, 100, 40) - self.check_button.setIcon(QIcon(os.path.join(self.btn_path, "check.png"))) + self.check_button.setIcon( + QIcon(os.path.join(self.btn_path, "check.png"))) self.check_button.setIconSize(self.check_button.size()) self.check_button.clicked.connect(self.check_package) self.check_button.setVisible(True) @@ -2689,22 +2838,23 @@ class InstallSystemPackage(Page): def _setup_manual_install(self): if self.current_distro != 'arch': - manual_install_label = QLabel(f"Manual Installation for {self.current_distro}", self) + manual_install_label = QLabel( + f"Manual Installation for {self.current_distro}", self) manual_install_label.setGeometry(80, 290, 650, 30) - manual_install_label.setStyleSheet("font-size: 18px; font-weight: bold;") + manual_install_label.setStyleSheet( + "font-size: 18px; font-weight: bold;") manual_install_label.setVisible(True) self.ui_elements.append(manual_install_label) - manual_install_desc = QLabel("Run this command in your terminal:", self) - manual_install_desc.setStyleSheet("font-size: 14px; font-weight: bold;") + manual_install_desc = QLabel( + "Run this command in your terminal:", self) + manual_install_desc.setStyleSheet( + "font-size: 14px; font-weight: bold;") manual_install_desc.setGeometry(80, 330, 380, 30) manual_install_desc.setVisible(True) - self.ui_elements.append(manual_install_desc) - - self.command_box = QLabel(self.manual_install_command, self) self.command_box.setGeometry(80, 370, 380, 40) @@ -2713,7 +2863,8 @@ class InstallSystemPackage(Page): self.command_box.setGeometry(50, 280, 380, 40) metrics = self.command_box.fontMetrics() - text_width = metrics.horizontalAdvance(self.manual_install_command) + 100 + text_width = metrics.horizontalAdvance( + self.manual_install_command) + 100 available_width = self.command_box.width() - 20 font_size = 18 MIN_FONT_SIZE = 10 @@ -2722,7 +2873,7 @@ class InstallSystemPackage(Page): break font_size -= 1 text_width -= 10 - + self.command_box.setStyleSheet(f""" background-color: #2b2b2b; color: #ffffff; @@ -2731,7 +2882,7 @@ class InstallSystemPackage(Page): font-family: monospace; font-size: {font_size}px; """) - + self.command_box.mousePressEvent = lambda _: self.copy_command() self.command_box.setVisible(True) self.ui_elements.append(self.command_box) @@ -2740,21 +2891,24 @@ class InstallSystemPackage(Page): # Pacman commands section pacman_label = QLabel("Pacman Installation:", self) pacman_label.setGeometry(50, 240, 650, 30) - pacman_label.setStyleSheet("font-size: 18px; font-weight: bold; color: #00ffff;") + pacman_label.setStyleSheet( + "font-size: 18px; font-weight: bold; color: #00ffff;") pacman_label.setVisible(True) self.ui_elements.append(pacman_label) # AUR commands section aur_label = QLabel("AUR / Yay Installation:", self) aur_label.setGeometry(50, 350, 300, 30) - aur_label.setStyleSheet("font-size: 18px; font-weight: bold; color: #00ffff;") + aur_label.setStyleSheet( + "font-size: 18px; font-weight: bold; color: #00ffff;") self.ui_elements.append(aur_label) # Yay command self.yay_command_box = QLabel("sudo yay -S ratpoison", self) self.yay_command_box.setGeometry(50, 390, 300, 40) self._setup_command_box_style(self.yay_command_box) - self.yay_command_box.mousePressEvent = lambda _: self.copy_command("sudo yay -S ratpoison", self.yay_command_box) + self.yay_command_box.mousePressEvent = lambda _: self.copy_command( + "sudo yay -S ratpoison", self.yay_command_box) self.ui_elements.append(self.yay_command_box) # Manual AUR command @@ -2763,15 +2917,16 @@ class InstallSystemPackage(Page): self.aur_command_box.setGeometry(370, 390, 380, 60) self._setup_command_box_style(self.aur_command_box) self.aur_command_box.setWordWrap(True) - self.aur_command_box.mousePressEvent = lambda _: self.copy_command(aur_command, self.aur_command_box) + self.aur_command_box.mousePressEvent = lambda _: self.copy_command( + aur_command, self.aur_command_box) self.ui_elements.append(self.aur_command_box) - else: self.command_box = QLabel(self.manual_install_command, self) self.command_box.setGeometry(80, 370, 380, 40) metrics = self.command_box.fontMetrics() - text_width = metrics.horizontalAdvance(self.manual_install_command) + 100 + text_width = metrics.horizontalAdvance( + self.manual_install_command) + 100 available_width = self.command_box.width() - 20 font_size = 18 MIN_FONT_SIZE = 10 @@ -2780,7 +2935,7 @@ class InstallSystemPackage(Page): break font_size -= 1 text_width -= 10 - + self.command_box.setStyleSheet(f""" background-color: #2b2b2b; color: #ffffff; @@ -2789,12 +2944,11 @@ class InstallSystemPackage(Page): font-family: monospace; font-size: {font_size}px; """) - + self.command_box.mousePressEvent = lambda _: self.copy_command() self.command_box.setVisible(True) self.ui_elements.append(self.command_box) - def _setup_command_box_style(self, command_box): metrics = command_box.fontMetrics() text_width = metrics.horizontalAdvance(command_box.text()) + 100 @@ -2806,7 +2960,7 @@ class InstallSystemPackage(Page): break font_size -= 1 text_width -= 10 - + command_box.setStyleSheet(f""" background-color: #2b2b2b; color: #ffffff; @@ -2820,24 +2974,27 @@ class InstallSystemPackage(Page): def copy_yay_command(self): clipboard = QApplication.clipboard() clipboard.setText("sudo yay -S ratpoison") - + original_style = self.yay_command_box.styleSheet() - self.yay_command_box.setStyleSheet(original_style + "background-color: #27ae60;") - QTimer.singleShot(200, lambda: self.yay_command_box.setStyleSheet(original_style)) + self.yay_command_box.setStyleSheet( + original_style + "background-color: #27ae60;") + QTimer.singleShot( + 200, lambda: self.yay_command_box.setStyleSheet(original_style)) self.update_status.update_status("Yay command copied to clipboard") def _setup_status_and_nav(self): if self.current_distro != 'arch': self.check_button = QPushButton(self) self.check_button.setGeometry(130, 430, 100, 40) - self.check_button.setIcon(QIcon(os.path.join(self.btn_path, "check.png"))) + self.check_button.setIcon( + QIcon(os.path.join(self.btn_path, "check.png"))) self.check_button.setIconSize(self.check_button.size()) self.check_button.clicked.connect(self.check_package) self.ui_elements.append(self.check_button) - + self.button_go.clicked.connect(self.go_next) self.button_back.clicked.connect(self.go_next) - + self.status_label = QLabel("", self) self.status_label.setGeometry(300, 430, 250, 40) if self.current_distro == 'arch': @@ -2853,25 +3010,30 @@ class InstallSystemPackage(Page): clipboard.setText(command) else: clipboard.setText(self.manual_install_command) - + original_style = command_box.styleSheet() - command_box.setStyleSheet(original_style + "background-color: #27ae60;") - QTimer.singleShot(200, lambda: command_box.setStyleSheet(original_style)) + command_box.setStyleSheet( + original_style + "background-color: #27ae60;") + QTimer.singleShot( + 200, lambda: command_box.setStyleSheet(original_style)) self.update_status.update_status("Command copied to clipboard") + def install_package(self): if not self.install_command: - self.update_status.update_status(f"Installation not supported for {self.current_distro}") + self.update_status.update_status( + f"Installation not supported for {self.current_distro}") return - + if subprocess.getstatusoutput('pkexec --help')[0] == 127: self.update_status.update_status("polkit toolkit is not installed") self.install_button.setDisabled(True) return - - self.worker_thread = WorkerThread('INSTALL_PACKAGE', - package_command=self.install_command, - package_name=self.package_name) - self.worker_thread.text_output.connect(self.update_status.update_status) + + self.worker_thread = WorkerThread('INSTALL_PACKAGE', + package_command=self.install_command, + package_name=self.package_name) + self.worker_thread.text_output.connect( + self.update_status.update_status) self.worker_thread.finished.connect(self.installation_complete) self.worker_thread.start() @@ -2882,10 +3044,12 @@ class InstallSystemPackage(Page): def check_package(self): try: if self.package_name.lower() == 'all': - packages = ['bwrap', 'ip', 'microsocks', 'proxychains4', 'ratpoison', 'tor', 'Xephyr', 'wg'] + packages = ['bwrap', 'ip', 'microsocks', + 'proxychains4', 'ratpoison', 'tor', 'Xephyr', 'wg'] for package in packages: if subprocess.getstatusoutput(f'{package} --help')[0] == 127: - self.status_label.setText(f"{package} is not installed") + self.status_label.setText( + f"{package} is not installed") self.status_label.setStyleSheet("color: red;") return self.status_label.setText("All packages installed!") @@ -2899,10 +3063,12 @@ class InstallSystemPackage(Page): else: self.install_name = self.package_name if subprocess.getstatusoutput(f'{self.install_name.lower()} --help')[0] == 127: - self.status_label.setText(f"{self.package_name} is not installed") + self.status_label.setText( + f"{self.package_name} is not installed") self.status_label.setStyleSheet("color: red;") else: - self.status_label.setText(f"{self.package_name} is installed!") + self.status_label.setText( + f"{self.package_name} is installed!") self.status_label.setStyleSheet("color: green;") except Exception: self.status_label.setText("Check failed") @@ -2912,19 +3078,23 @@ class InstallSystemPackage(Page): if not self.update_status.has_shown_systemwide_prompt(): system_page = self.page_stack.findChild(SystemwidePromptPage) if system_page is None: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) return - self.page_stack.setCurrentIndex(self.page_stack.indexOf(system_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(system_page)) else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + class ProtocolPage(Page): def __init__(self, page_stack, main_window=None, parent=None): - super().__init__("Protocol", page_stack,main_window, parent) + super().__init__("Protocol", page_stack, main_window, parent) self.main_window = main_window self.selected_protocol = None self.btn_path = main_window.btn_path - self.selected_protocol_icon = None + self.selected_protocol_icon = None self.connection_manager = main_window.connection_manager self.button_back.setVisible(True) self.update_status = main_window @@ -2934,39 +3104,43 @@ class ProtocolPage(Page): self.coming_soon_label.setStyleSheet("font-size: 22px;") self.coming_soon_label.setVisible(False) - self.title.setGeometry(585, 40, 185, 40); self.title.setText("Pick a Protocol") - self.display.setGeometry(QtCore.QRect(0, 50, 580, 435))#relacion 4:3 + self.title.setGeometry(585, 40, 185, 40) + self.title.setText("Pick a Protocol") + self.display.setGeometry(QtCore.QRect(0, 50, 580, 435)) # relacion 4:3 self.create_interface_elements() - def create_interface_elements(self): self.buttonGroup = QButtonGroup(self) self.buttons = [] - for j, (object_type,icon_name, page_class, geometry) in enumerate([ - (QPushButton,"wireguard", WireGuardPage, (585, 90,185,75)), - (QPushButton,"residential", ResidentialPage, (585, 90+30+75,185,75)), - (QPushButton,"hidetor", HidetorPage, (585, 90+30+75+30+75,185,75)) + for j, (object_type, icon_name, page_class, geometry) in enumerate([ + (QPushButton, "wireguard", WireGuardPage, (585, 90, 185, 75)), + (QPushButton, "residential", ResidentialPage, (585, 90+30+75, 185, 75)), + (QPushButton, "hidetor", HidetorPage, (585, 90+30+75+30+75, 185, 75)) ]): boton = object_type(self) boton.setGeometry(*geometry) boton.setIconSize(boton.size()) boton.setCheckable(True) boton.setDisabled(True) - boton.setIcon(QIcon(os.path.join(self.btn_path, f"{icon_name}_button.png"))) + boton.setIcon( + QIcon(os.path.join(self.btn_path, f"{icon_name}_button.png"))) self.buttons.append(boton) self.buttonGroup.addButton(boton, j) - boton.clicked.connect(lambda _, page=page_class, protocol=icon_name: self.show_protocol(page, protocol)) - + boton.clicked.connect( + lambda _, page=page_class, protocol=icon_name: self.show_protocol(page, protocol)) + def enable_protocol_buttons(self): for button in self.buttons: button.setDisabled(False) def update_swarp_json(self): - self.update_status.write_data({"protocol": self.selected_protocol_icon}) + self.update_status.write_data( + {"protocol": self.selected_protocol_icon}) def show_protocol(self, page_class, protocol): self.update_status.clear_data() - self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"{protocol}.png")).scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) + self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"{protocol}.png")).scaled( + self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) self.selected_protocol_icon = protocol self.selected_page_class = page_class @@ -2983,14 +3157,16 @@ class ProtocolPage(Page): if self.selected_page_class: selected_page = self.selected_page_class if selected_page == HidetorPage: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(HidetorPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(HidetorPage))) else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(selected_page))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(selected_page))) self.display.clear() for boton in self.buttons: boton.setChecked(False) - + self.button_go.setVisible(False) def find_menu_page(self): @@ -3000,22 +3176,26 @@ class ProtocolPage(Page): return page return None + class WireGuardPage(Page): - browser_label_created = False # Variable de clase para verificar si el QLabel ya se ha creado + # Variable de clase para verificar si el QLabel ya se ha creado + browser_label_created = False + def __init__(self, page_stack, main_window, parent=None): super().__init__("Wireguard", page_stack, main_window, parent) self.buttonGroup = QButtonGroup(self) - self.btn_path = main_window.btn_path + self.btn_path = main_window.btn_path self.update_status = main_window self.buttons = [] self.selected_protocol = None - self.selected_protocol_icon = None + self.selected_protocol_icon = None self.button_back.setVisible(True) self.button_go.clicked.connect(self.go_selected) - self.additional_labels=[ ] - self.title.setGeometry(585, 40, 185, 40); self.title.setText("Pick a Protocol") - #self.display.setGeometry(QtCore.QRect(15, 50, 550, 411))#relacion 4:3 - #self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"{wireguard}.png")).scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) + self.additional_labels = [] + self.title.setGeometry(585, 40, 185, 40) + self.title.setText("Pick a Protocol") + # self.display.setGeometry(QtCore.QRect(15, 50, 550, 411))#relacion 4:3 + # self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"{wireguard}.png")).scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) self.sudo_warning = QLabel("Requires Sudo", self) self.sudo_warning.setGeometry(165, 90, 300, 40) self.sudo_warning.setStyleSheet(""" @@ -3029,10 +3209,10 @@ class WireGuardPage(Page): def create_interface_elements(self): - for j, (object_type, icon_name, page_class, geometry) in enumerate([ (QPushButton, "system-wide", LocationPage, (585, 90, 185, 75)), - (QPushButton, "browser-only", LocationPage, (585, 90+30+75+30+75, 185, 75)), + (QPushButton, "browser-only", LocationPage, + (585, 90+30+75+30+75, 185, 75)), (QLabel, None, None, (570, 170, 210, 105)), (QLabel, None, None, (570, 385, 210, 115)) ]): @@ -3041,11 +3221,13 @@ class WireGuardPage(Page): boton.setGeometry(*geometry) boton.setIconSize(boton.size()) boton.setCheckable(True) - boton.setIcon(QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) + boton.setIcon( + QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) self.buttons.append(boton) self.buttonGroup.addButton(boton, j) # Usamos argumentos por defecto para capturar los valores - boton.clicked.connect(lambda _, page=page_class, protocol=icon_name: self.show_protocol(page, protocol)) + boton.clicked.connect( + lambda _, page=page_class, protocol=icon_name: self.show_protocol(page, protocol)) elif object_type == QLabel: label = object_type(self) label.setGeometry(*geometry) @@ -3066,8 +3248,7 @@ class WireGuardPage(Page): "connection": self.selected_protocol_icon } self.update_status.write_data(inserted_data) - - + def show_protocol(self, page_class, protocol): if protocol == "browser-only": self.sudo_warning.setVisible(False) @@ -3085,65 +3266,75 @@ class WireGuardPage(Page): self.additional_labels.clear() if protocol == "system-wide": - - # Crear QLabel con la imagen os.path.join(self.btn_path, "browser only.png") detrás del label_principal - label_principal = QLabel(self) - label_principal.setGeometry(0, 60, 540, 460) # Geometría según necesidades - pixmap = QPixmap(os.path.join(self.btn_path, "wireguard.png")) - label_principal.setPixmap(pixmap) - label_principal.show() - label_principal.setScaledContents(True) - label_principal.lower() # Colocar label_background debajo del label_principal - self.additional_labels.append(label_principal) + # Crear QLabel con la imagen os.path.join(self.btn_path, "browser only.png") detrás del label_principal + label_principal = QLabel(self) + # Geometría según necesidades + label_principal.setGeometry(0, 60, 540, 460) + pixmap = QPixmap(os.path.join(self.btn_path, "wireguard.png")) + label_principal.setPixmap(pixmap) + label_principal.show() + label_principal.setScaledContents(True) + label_principal.lower() # Colocar label_background debajo del label_principal + self.additional_labels.append(label_principal) if protocol == "browser-only": - # Crear QLabel principal - label_principal = QLabel(self) - label_principal.setGeometry(0, 80, 530, 380) - pixmap = QPixmap(os.path.join(self.btn_path, "wireguard.png")) - label_principal.setPixmap(pixmap) - label_principal.show() - label_principal.setScaledContents(True) + # Crear QLabel principal + label_principal = QLabel(self) + label_principal.setGeometry(0, 80, 530, 380) + pixmap = QPixmap(os.path.join(self.btn_path, "wireguard.png")) + label_principal.setPixmap(pixmap) + label_principal.show() + label_principal.setScaledContents(True) - label_principal.show() - self.additional_labels.append(label_principal) + label_principal.show() + self.additional_labels.append(label_principal) - # Crear QLabel con la imagen os.path.join(self.btn_path, "browser only.png") detrás del label_principal - label_background = QLabel(self) - label_background.setGeometry(0, 60, 540, 460) # Geometría según necesidades - pixmap = QPixmap(os.path.join(self.btn_path, "browser only.png")) - label_background.setPixmap(pixmap) - label_background.show() - label_background.setScaledContents(True) - label_background.lower() # Colocar label_background debajo del label_principal - self.additional_labels.append(label_background) + # Crear QLabel con la imagen os.path.join(self.btn_path, "browser only.png") detrás del label_principal + label_background = QLabel(self) + # Geometría según necesidades + label_background.setGeometry(0, 60, 540, 460) + pixmap = QPixmap(os.path.join(self.btn_path, "browser only.png")) + label_background.setPixmap(pixmap) + label_background.show() + label_background.setScaledContents(True) + label_background.lower() # Colocar label_background debajo del label_principal + self.additional_labels.append(label_background) def go_selected(self): if self.selected_page_class: if self.protocol_chosen == 'system-wide': - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(LocationPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(LocationPage))) else: selected_page = self.selected_page_class - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(selected_page))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(selected_page))) self.display.clear() for boton in self.buttons: boton.setChecked(False) - + self.button_go.setVisible(False) + def reverse(self): self.display.clear() for boton in self.buttons: boton.setChecked(False) - + self.button_go.setVisible(False) - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ProtocolPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ProtocolPage))) + + class lokinetPage(Page): def __init__(self, page_stack, parent=None): super().__init__("Lokinet", page_stack, parent) self.create_interface_elements() + def create_interface_elements(self): pass + + class OpenPage(Page): def __init__(self, page_stack, parent=None): super().__init__("Opne", page_stack, parent) @@ -3160,8 +3351,8 @@ class HidetorPage(Page): self.button_reverse.setVisible(True) self.button_reverse.clicked.connect(self.reverse) self.display.setGeometry(QtCore.QRect(5, 10, 390, 520)) - self.title.setGeometry(395, 40, 380, 40); self.title.setText("Pick a location") - + self.title.setGeometry(395, 40, 380, 40) + self.title.setText("Pick a location") def create_interface_elements(self, available_locations): self.buttonGroup = QButtonGroup(self) @@ -3174,32 +3365,40 @@ class HidetorPage(Page): boton.setCheckable(True) locations = self.connection_manager.get_location_info(icon_name) if icon_name == 'my_14': - boton.setVisible(False) - if locations and not(hasattr(locations, 'is_proxy_capable') and locations.is_proxy_capable): + boton.setVisible(False) + if locations and not (hasattr(locations, 'is_proxy_capable') and locations.is_proxy_capable): boton.setVisible(False) icon_path = os.path.join(self.btn_path, f"button_{icon_name}.png") boton.setIcon(QIcon(icon_path)) - fallback_path = os.path.join(self.btn_path, "default_location_button.png") - provider = locations.operator.name if locations and hasattr(locations, 'operator') else None + fallback_path = os.path.join( + self.btn_path, "default_location_button.png") + provider = locations.operator.name if locations and hasattr( + locations, 'operator') else None if boton.icon().isNull(): if locations and hasattr(locations, 'country_name'): - base_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider) + location_name = locations.country_name + base_image = LocationPage.create_location_button_image( + location_name, fallback_path, provider) boton.setIcon(QIcon(base_image)) else: - base_image = LocationPage.create_location_button_image('', fallback_path, provider) + base_image = LocationPage.create_location_button_image( + '', fallback_path, provider) boton.setIcon(QIcon(base_image)) else: if locations and hasattr(locations, 'country_name'): - base_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider, icon_path) + base_image = LocationPage.create_location_button_image( + f'{locations.country_code}_{locations.code}', fallback_path, provider, icon_path) boton.setIcon(QIcon(base_image)) else: - base_image = LocationPage.create_location_button_image('', fallback_path, provider, icon_path) + base_image = LocationPage.create_location_button_image( + '', fallback_path, provider, icon_path) boton.setIcon(QIcon(base_image)) self.buttons.append(boton) self.buttonGroup.addButton(boton, j) boton.location_icon_name = icon_name boton.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) - boton.clicked.connect(lambda checked, loc=icon_name: self.show_location(loc)) + boton.clicked.connect( + lambda checked, loc=icon_name: self.show_location(loc)) def update_swarp_json(self): inserted_data = { @@ -3210,27 +3409,33 @@ class HidetorPage(Page): def show_location(self, location): tor_hide_img = f'hdtor_{location}' - self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"{tor_hide_img}.png")).scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) - self.selected_location_icon = location + self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"{tor_hide_img}.png")).scaled( + self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) + self.selected_location_icon = location self.button_next.setVisible(True) self.update_swarp_json() - def reverse(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ProtocolPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ProtocolPage))) def go_selected(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(BrowserPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(BrowserPage))) def show_location_verification(self, location_icon_name): - verification_page = LocationVerificationPage(self.page_stack, self.update_status, location_icon_name, self) + verification_page = LocationVerificationPage( + self.page_stack, self.update_status, location_icon_name, self) self.page_stack.addWidget(verification_page) - self.page_stack.setCurrentIndex(self.page_stack.indexOf(verification_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(verification_page)) + class ResidentialPage(Page): def __init__(self, page_stack, main_window, parent=None): super().__init__("Wireguard", page_stack, main_window, parent) - self.title.setGeometry(585, 40, 185, 40); self.title.setText("Pick a Protocol") + self.title.setGeometry(585, 40, 185, 40) + self.title.setText("Pick a Protocol") self.update_status = main_window self.connection_choice = None self.button_reverse.setVisible(True) @@ -3238,27 +3443,29 @@ class ResidentialPage(Page): self.button_go.clicked.connect(self.go_selected) self.display_1 = QLabel(self) - self.display_1.setGeometry(QtCore.QRect(15, 50, 550, 465))#relacion 4:3 - self.display_1.setPixmap(QPixmap(os.path.join(self.btn_path, "browser only.png"))) + self.display_1.setGeometry(QtCore.QRect( + 15, 50, 550, 465)) # relacion 4:3 + self.display_1.setPixmap( + QPixmap(os.path.join(self.btn_path, "browser only.png"))) self.label = QLabel(self) - self.label.setGeometry(440, 370, 86,130) - self.label.setPixmap(QPixmap(os.path.join(self.btn_path, "tor 86x130.png"))) - self.label.hide() - - + self.label.setGeometry(440, 370, 86, 130) + self.label.setPixmap( + QPixmap(os.path.join(self.btn_path, "tor 86x130.png"))) + self.label.hide() def showEvent(self, event): super().showEvent(event) self.create_interface_elements() - def create_interface_elements(self): self.buttonGroup = QButtonGroup(self) self.buttons = [] for j, (object_type, icon_name, page_class, geometry) in enumerate([ - (QPushButton, "tor", self.set_connection_choice('tor'), (585, 90, 185, 75)), - (QPushButton, "just proxy", self.set_connection_choice('just proxy'), (585, 90+30+75+30+75, 185, 75)), + (QPushButton, "tor", self.set_connection_choice( + 'tor'), (585, 90, 185, 75)), + (QPushButton, "just proxy", self.set_connection_choice( + 'just proxy'), (585, 90+30+75+30+75, 185, 75)), (QLabel, None, None, (570, 170, 210, 105)), (QLabel, None, None, (570, 385, 210, 115)) ]): @@ -3267,14 +3474,16 @@ class ResidentialPage(Page): boton.setGeometry(*geometry) boton.setIconSize(boton.size()) boton.setCheckable(True) - boton.setIcon(QIcon(os.path.join(self.btn_path, f"{icon_name}_button.png"))) + boton.setIcon( + QIcon(os.path.join(self.btn_path, f"{icon_name}_button.png"))) self.buttons.append(boton) self.buttonGroup.addButton(boton, j) - + boton.show() # Conectar el botón a la función show_residential - boton.clicked.connect(lambda checked,page=page_class, name=icon_name: self.show_residential(name,page)) + boton.clicked.connect( + lambda checked, page=page_class, name=icon_name: self.show_residential(name, page)) elif object_type == QLabel: label = object_type(self) label.setGeometry(*geometry) @@ -3288,12 +3497,10 @@ class ResidentialPage(Page): text2 = "Connect directly\nTo the Proxy\nin a browser\nThis has no encryption" label.setText(text2) - def set_connection_choice(self, connection_choice): pass - - def show_residential(self, icon_name,page_class): + def show_residential(self, icon_name, page_class): self.connection_choice = icon_name self.selected_page_class = page_class @@ -3304,10 +3511,10 @@ class ResidentialPage(Page): self.button_go.setVisible(True) - def go_selected(self): self.update_swarp_json(self.connection_choice) - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(HidetorPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(HidetorPage))) self.button_go.setVisible(False) def update_swarp_json(self, icon_name): @@ -3316,20 +3523,25 @@ class ResidentialPage(Page): } self.update_status.write_data(inserted_data) - def reverse(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ProtocolPage))) - + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ProtocolPage))) + + class TorPage(Page): def __init__(self, page_stack, main_window, parent=None): super().__init__("TorPage", page_stack, main_window, parent) self.update_status = main_window self.button_back.setVisible(True) - self.title.setGeometry(585, 40, 185, 40); self.title.setText("Pick a Country") - self.display.setGeometry(QtCore.QRect(0, 100, 540, 405))#relacion 4:3 - self.display0=QLabel(self) - self.display0.setGeometry(QtCore.QRect(0, 50, 600, 465))#relacion 4:3 - self.display0.setPixmap(QPixmap(os.path.join(self.btn_path, "browser only.png"))) + self.title.setGeometry(585, 40, 185, 40) + self.title.setText("Pick a Country") + self.display.setGeometry(QtCore.QRect( + 0, 100, 540, 405)) # relacion 4:3 + self.display0 = QLabel(self) + self.display0.setGeometry(QtCore.QRect( + 0, 50, 600, 465)) # relacion 4:3 + self.display0.setPixmap( + QPixmap(os.path.join(self.btn_path, "browser only.png"))) self.display0.lower() # Colocar display2 debajo de otros widgets self.button_go.clicked.connect(self.go_selected) @@ -3337,15 +3549,14 @@ class TorPage(Page): self.button_reverse.setVisible(True) self.button_reverse.clicked.connect(self.reverse_selected) - - self.label = QLabel(self) - self.label.setGeometry(440, 370, 86,130) - pixmap = QPixmap(os.path.join(self.btn_path, "tor 86x130.png")) # Reemplaza "ruta/a/la/imagen.png" por la ruta de tu imagen + self.label.setGeometry(440, 370, 86, 130) + # Reemplaza "ruta/a/la/imagen.png" por la ruta de tu imagen + pixmap = QPixmap(os.path.join(self.btn_path, "tor 86x130.png")) self.label.setPixmap(pixmap) - + self.label.hide() - + def showEvent(self, event): super().showEvent(event) self.extraccion() @@ -3356,11 +3567,11 @@ class TorPage(Page): profile_1 = profile.get('Profile_1') self.verificate() - def verificate(self, value= 'tor'): + def verificate(self, value='tor'): # Verificar el valor de key if value == "just proxy": - self.display0.show() - self.label.hide() + self.display0.show() + self.label.hide() elif value == "tor": self.display0.show() self.label.show() # Colocar display2 debajo de otros widgets @@ -3388,11 +3599,13 @@ class TorPage(Page): boton.show() ''' + def show_dimentions(self, dimentions): - self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"{dimentions} garaje.png")).scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) + self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"{dimentions} garaje.png")).scaled( + self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) self.selected_dimentions_icon = dimentions self.button_go.setVisible(True) - self.update_swarp_json() + self.update_swarp_json() def update_swarp_json(self): inserted_data = { @@ -3400,18 +3613,18 @@ class TorPage(Page): } self.update_status.write_data(inserted_data) - def reverse_selected(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ResidentialPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ResidentialPage))) def go_selected(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(BrowserPage))) - + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(BrowserPage))) self.display.clear() for boton in self.buttons: boton.setChecked(False) - + self.button_go.setVisible(False) @@ -3419,44 +3632,52 @@ class TorLocationPage(Page): def __init__(self, page_stack, parent=None): super().__init__("TorPage", page_stack, parent) pass + + class ConnectionPage(Page): def __init__(self, page_stack, parent=None): super().__init__("Connection", page_stack, parent) self.create_interface_elements() - def create_interface_elements(self): self.display.setGeometry(QtCore.QRect(5, 50, 390, 430)) self.title.setGeometry(QtCore.QRect(465, 40, 300, 20)) - self.title.setText("Pick a TOR") - + self.title.setText("Pick a TOR") + labels_info = [ ("server", None, (410, 115)), ("", "rr2", (560, 115)), ("port", None, (410, 205)), ("", "rr2", (560, 205)), - ("username",None, (410, 295)), + ("username", None, (410, 295)), ("", "rr2", (560, 295)), - ("password",None, (410, 385)), + ("password", None, (410, 385)), ("", "rr2", (560, 385)) ] for j, (text, image_name, position) in enumerate(labels_info): label = QLabel(self) label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - if image_name: # Si hay un nombre de imagen, usar el tamaño predeterminado (220x50) + # Si hay un nombre de imagen, usar el tamaño predeterminado (220x50) + if image_name: label.setGeometry(position[0], position[1], 220, 50) - else: # Si no hay una imagen, usar el tamaño personalizado (130x30) + # Si no hay una imagen, usar el tamaño personalizado (130x30) + else: label.setGeometry(position[0], position[1], 140, 50) - label.setStyleSheet("background-color: rgba(255, 255, 255, 51); padding: 3px;") + label.setStyleSheet( + "background-color: rgba(255, 255, 255, 51); padding: 3px;") if image_name: # Si hay un nombre de imagen, crear una QLabel con la imagen - pixmap = QPixmap(os.path.join(self.btn_path, f"{image_name}.png")) + pixmap = QPixmap(os.path.join( + self.btn_path, f"{image_name}.png")) label.setPixmap(pixmap) - label.setScaledContents(True) # Escalar contenido para ajustarlo al tamaño del QLabel + # Escalar contenido para ajustarlo al tamaño del QLabel + label.setScaledContents(True) else: # Si no hay una imagen, crear una QLabel con el texto label.setText(text) + + class LocationPage(Page): def __init__(self, page_stack, main_window, parent=None): super().__init__("Location", page_stack, main_window, parent) @@ -3466,13 +3687,14 @@ class LocationPage(Page): self.connection_manager = main_window.connection_manager self.button_reverse.clicked.connect(self.reverse) self.display.setGeometry(QtCore.QRect(5, 10, 390, 520)) - self.title.setGeometry(395, 40, 380, 40); self.title.setText("Pick a location") - + self.title.setGeometry(395, 40, 380, 40) + self.title.setText("Pick a location") + self.initial_display = QLabel(self) - self.initial_display.setGeometry(5, 22, 355, 485) + self.initial_display.setGeometry(5, 22, 355, 485) self.initial_display.setAlignment(Qt.AlignmentFlag.AlignCenter) self.initial_display.setWordWrap(True) - + self.verification_button = QPushButton("More Info", self) self.verification_button.setGeometry(0, 50, 160, 40) self.verification_button.setStyleSheet(f""" @@ -3495,7 +3717,8 @@ class LocationPage(Page): opacity: 0.5; }} """) - self.verification_button.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) + self.verification_button.setCursor( + QtCore.Qt.CursorShape.PointingHandCursor) self.verification_button.setEnabled(False) self.verification_button.show() @@ -3510,40 +3733,48 @@ class LocationPage(Page): def create_interface_elements(self, available_locations): self.buttonGroup = QButtonGroup(self) self.buttons = [] - + for j, (object_type, icon_name, geometry) in enumerate(available_locations): boton = object_type(self) - boton.setGeometry(*geometry) + boton.setGeometry(*geometry) boton.setIconSize(boton.size()) boton.setCheckable(True) locations = self.connection_manager.get_location_info(icon_name) - if locations and not(hasattr(locations, 'is_wireguard_capable') and locations.is_wireguard_capable): + if locations and not (hasattr(locations, 'is_wireguard_capable') and locations.is_wireguard_capable): boton.setVisible(False) icon_path = os.path.join(self.btn_path, f"button_{icon_name}.png") boton.setIcon(QIcon(icon_path)) - fallback_path = os.path.join(self.btn_path, "default_location_button.png") - provider = locations.operator.name if locations and hasattr(locations, 'operator') else None + fallback_path = os.path.join( + self.btn_path, "default_location_button.png") + provider = locations.operator.name if locations and hasattr( + locations, 'operator') else None if boton.icon().isNull(): if locations and hasattr(locations, 'country_name'): - base_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider) + location_name = locations.country_name + base_image = LocationPage.create_location_button_image( + location_name, fallback_path, provider) boton.setIcon(QIcon(base_image)) else: - base_image = LocationPage.create_location_button_image('', fallback_path, provider) + base_image = LocationPage.create_location_button_image( + '', fallback_path, provider) boton.setIcon(QIcon(base_image)) else: if locations and hasattr(locations, 'country_name'): - base_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider, icon_path) + base_image = LocationPage.create_location_button_image( + f'{locations.country_code}_{locations.code}', fallback_path, provider, icon_path) boton.setIcon(QIcon(base_image)) else: - base_image = LocationPage.create_location_button_image('', fallback_path, provider, icon_path) + base_image = LocationPage.create_location_button_image( + '', fallback_path, provider, icon_path) boton.setIcon(QIcon(base_image)) self.buttons.append(boton) self.buttonGroup.addButton(boton, j) boton.location_icon_name = icon_name boton.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) - boton.clicked.connect(lambda checked, loc=icon_name: self.show_location(loc)) + boton.clicked.connect( + lambda checked, loc=icon_name: self.show_location(loc)) def update_swarp_json(self, get_connection=False): profile_data = self.update_status.read_data() @@ -3555,37 +3786,42 @@ class LocationPage(Page): } self.update_status.write_data(inserted_data) - def show_location(self, location): self.initial_display.hide() - self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"icon_{location}.png")).scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) - self.selected_location_icon = location + self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"icon_{location}.png")).scaled( + self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) + self.selected_location_icon = location self.button_next.setVisible(True) - self.button_next.clicked.connect(self.go_selected) + self.button_next.clicked.connect(self.go_selected) self.update_swarp_json() - + try: self.verification_button.clicked.disconnect() except TypeError: pass - - self.verification_button.clicked.connect(lambda: self.show_location_verification(location)) + + self.verification_button.clicked.connect( + lambda: self.show_location_verification(location)) self.verification_button.setEnabled(True) - def reverse(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ProtocolPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ProtocolPage))) def go_selected(self): if self.connection_type == "system-wide": - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ResumePage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ResumePage))) else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(BrowserPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(BrowserPage))) def show_location_verification(self, location_icon_name): - verification_page = LocationVerificationPage(self.page_stack, self.update_status, location_icon_name, self) + verification_page = LocationVerificationPage( + self.page_stack, self.update_status, location_icon_name, self) self.page_stack.addWidget(verification_page) - self.page_stack.setCurrentIndex(self.page_stack.indexOf(verification_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(verification_page)) @staticmethod def create_location_button_image(location_name, fallback_image_path, provider=None, existing_icon_path=None): @@ -3597,10 +3833,10 @@ class LocationPage(Page): else: base_image = QPixmap(fallback_image_path) draw_location_text = True - + if base_image.isNull(): return base_image - + painter = QPainter(base_image) try: if draw_location_text: @@ -3625,7 +3861,7 @@ class LocationPage(Page): app_font.setStretch(font_stretch) painter.setFont(app_font) painter.setPen(QColor(0, 255, 255)) - + text_rect = painter.fontMetrics().boundingRect(location_name) max_width = 110 @@ -3649,7 +3885,8 @@ class LocationPage(Page): shadow_offset = 1 painter.setPen(QColor(0, 0, 0)) - painter.drawText(x_scaled + shadow_offset, y_scaled + shadow_offset, location_name) + painter.drawText(x_scaled + shadow_offset, + y_scaled + shadow_offset, location_name) painter.setPen(QColor(0, 255, 255)) painter.drawText(x_scaled, y_scaled, location_name) @@ -3660,24 +3897,25 @@ class LocationPage(Page): painter.setPen(QColor(128, 128, 128)) - provider_text_font = QApplication.font() provider_text_font.setPointSize(7) provider_text_font.setWeight(QFont.Weight.Normal) painter.setFont(provider_text_font) provider_text_rect = painter.fontMetrics().boundingRect(provider) - provider_x = ((base_image.width() - provider_text_rect.width()) // 2) - 30 + provider_x = ( + (base_image.width() - provider_text_rect.width()) // 2) - 30 provider_y = 50 px = int(provider_x) py = int(provider_y) - + painter.setFont(provider_text_font) painter.drawText(px + 5, py + 2, provider) finally: painter.end() return base_image + class BrowserPage(Page): def __init__(self, page_stack, main_window, parent=None): super().__init__("Browser", page_stack, main_window, parent) @@ -3686,7 +3924,7 @@ class BrowserPage(Page): self.selected_browser_icon = None self.display.setGeometry(QtCore.QRect(5, 10, 390, 520)) self.title.setGeometry(395, 40, 380, 40) - self.title.setText("Pick a Browser") + self.title.setText("Pick a Browser") self.button_back.setVisible(True) def create_interface_elements(self, available_browsers): @@ -3699,7 +3937,8 @@ class BrowserPage(Page): self.scroll_area = QScrollArea(self) self.scroll_area.setGeometry(400, 90, 385, 400) self.scroll_area.setWidgetResizable(True) - self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.scroll_area.setHorizontalScrollBarPolicy( + Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self._apply_scroll_area_style() def _apply_scroll_area_style(self): @@ -3740,7 +3979,8 @@ class BrowserPage(Page): def _populate_button_widget(self, button_widget, available_browsers): dimensions = self._get_button_dimensions() - total_height = self._create_browser_buttons(button_widget, available_browsers, dimensions) + total_height = self._create_browser_buttons( + button_widget, available_browsers, dimensions) self._set_final_widget_size(button_widget, dimensions, total_height) def _get_button_dimensions(self): @@ -3755,9 +3995,10 @@ class BrowserPage(Page): total_height = 0 for browser_tuple in browser_icons: _, browser_string, geometry = browser_tuple - x_coord = geometry[0] - 395 - y_coord = geometry[1] - 90 - self._create_single_button(button_widget, browser_string, x_coord, y_coord, dims) + x_coord = geometry[0] - 395 + y_coord = geometry[1] - 90 + self._create_single_button( + button_widget, browser_string, x_coord, y_coord, dims) total_height = max(total_height, y_coord + dims['height']) return total_height @@ -3769,15 +4010,19 @@ class BrowserPage(Page): button.setCheckable(True) browser_name, version = icon_name.split(':') - button.setIcon(QIcon(BrowserPage.create_browser_button_image(f"{browser_name} {version}", self.btn_path))) + button.setIcon(QIcon(BrowserPage.create_browser_button_image( + f"{browser_name} {version}", self.btn_path))) if button.icon().isNull(): - fallback_path = os.path.join(self.btn_path, "default_browser_button.png") - button.setIcon(QIcon(BrowserPage.create_browser_button_image(f"{browser_name} {version}", fallback_path, True))) + fallback_path = os.path.join( + self.btn_path, "default_browser_button.png") + button.setIcon(QIcon(BrowserPage.create_browser_button_image( + f"{browser_name} {version}", fallback_path, True))) self._apply_button_style(button) - + self.buttons.append(button) self.buttonGroup.addButton(button) - button.clicked.connect(lambda _, b=icon_name: self.show_browser(b.replace(':', ' '))) + button.clicked.connect( + lambda _, b=icon_name: self.show_browser(b.replace(':', ' '))) @staticmethod def create_browser_button_image(browser_text, btn_path, is_fallback=False): @@ -3785,21 +4030,24 @@ class BrowserPage(Page): if ':' in browser_text: browser_name, version = browser_text.split(':', 1) else: - browser_name, version = browser_text.split()[0], ' '.join(browser_text.split()[1:]) + browser_name, version = browser_text.split( + )[0], ' '.join(browser_text.split()[1:]) if is_fallback: base_image = QPixmap(btn_path) else: - base_image = QPixmap(os.path.join(btn_path, f"{browser_name}_button.png")) - + base_image = QPixmap(os.path.join( + btn_path, f"{browser_name}_button.png")) + if base_image.isNull(): base_image = QPixmap(185, 75) base_image.fill(QColor(44, 62, 80)) - + painter = QPainter(base_image) if painter.isActive(): BrowserPage._setup_version_font(painter, version, base_image) if is_fallback: - BrowserPage._setup_browser_name(painter, browser_name, base_image) + BrowserPage._setup_browser_name( + painter, browser_name, base_image) painter.end() return base_image @@ -3818,7 +4066,6 @@ class BrowserPage(Page): x = (base_image.width() - text_rect.width()) // 2 - 30 y = (base_image.height() + text_rect.height()) // 2 - 10 painter.drawText(x, y, browser_name) - @staticmethod def _setup_version_font(painter, version, base_image): @@ -3850,13 +4097,17 @@ class BrowserPage(Page): """) def _set_final_widget_size(self, widget, dims, total_height): - widget.setFixedSize(dims['width'] * 2 + 5, total_height + dims['spacing']) + widget.setFixedSize(dims['width'] * 2 + 5, + total_height + dims['spacing']) def show_browser(self, browser): - browser_name, version = browser.split()[0], ' '.join(browser.split()[1:]) + browser_name, version = browser.split( + )[0], ' '.join(browser.split()[1:]) try: - base_image = self._create_browser_display_image(browser_name, version) - self.display.setPixmap(base_image.scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) + base_image = self._create_browser_display_image( + browser_name, version) + self.display.setPixmap(base_image.scaled( + self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) except Exception: pass self.selected_browser_icon = browser @@ -3864,15 +4115,16 @@ class BrowserPage(Page): self.update_swarp_json() def _create_browser_display_image(self, browser_name, version): - base_image = QPixmap(os.path.join(self.btn_path, f"{browser_name}_icon.png")) + base_image = QPixmap(os.path.join( + self.btn_path, f"{browser_name}_icon.png")) painter = QPainter(base_image) painter.setFont(QFont('Arial', 25)) painter.setPen(QColor(0, 255, 255)) - + text_rect = painter.fontMetrics().boundingRect(version) x = (base_image.width() - text_rect.width()) // 2 y = base_image.height() - 45 - + painter.drawText(x, y, version) painter.end() return base_image @@ -3883,14 +4135,17 @@ class BrowserPage(Page): } self.update_status.write_data(inserted_data) + + class ScreenPage(Page): def __init__(self, page_stack, main_window, parent=None): super().__init__("Screen", page_stack, main_window, parent) self.selected_dimentions = None self.update_status = main_window - self.selected_dimentions_icon = None + self.selected_dimentions_icon = None self.button_back.setVisible(True) - self.title.setGeometry(585, 40, 200, 40); self.title.setText("Pick a Resolution") + self.title.setGeometry(585, 40, 200, 40) + self.title.setText("Pick a Resolution") self.display.setGeometry(QtCore.QRect(5, 50, 580, 435)) self.showing_larger_resolutions = False self.larger_resolution_buttons = [] @@ -3910,26 +4165,35 @@ class ScreenPage(Page): boton.setGeometry(*geometry) boton.setIconSize(boton.size()) boton.setCheckable(True) - boton.setIcon(QIcon(self.create_resolution_button_image(icon_name))) + boton.setIcon( + QIcon(self.create_resolution_button_image(icon_name))) self.buttons.append(boton) self.buttonGroup.addButton(boton, j) - boton.clicked.connect(lambda _, dimentions=icon_name: self.show_dimentions(dimentions)) + boton.clicked.connect( + lambda _, dimentions=icon_name: self.show_dimentions(dimentions)) self.larger_resolutions_button = QPushButton(self) self.larger_resolutions_button.setGeometry(100, 450, 185, 50) - self.larger_resolutions_button.setIconSize(self.larger_resolutions_button.size()) - self.larger_resolutions_button.setIcon(QIcon(self.create_resolution_button_image("Larger Resolutions"))) - self.larger_resolutions_button.clicked.connect(self.show_larger_resolutions) + self.larger_resolutions_button.setIconSize( + self.larger_resolutions_button.size()) + self.larger_resolutions_button.setIcon( + QIcon(self.create_resolution_button_image("Larger Resolutions"))) + self.larger_resolutions_button.clicked.connect( + self.show_larger_resolutions) self.custom_resolution_button = QPushButton(self) self.custom_resolution_button.setGeometry(300, 450, 195, 50) - self.custom_resolution_button.setIconSize(self.custom_resolution_button.size()) - self.custom_resolution_button.setIcon(QIcon(self.create_resolution_button_image("Custom Resolution"))) - self.custom_resolution_button.clicked.connect(self.show_custom_resolution_dialog) + self.custom_resolution_button.setIconSize( + self.custom_resolution_button.size()) + self.custom_resolution_button.setIcon( + QIcon(self.create_resolution_button_image("Custom Resolution"))) + self.custom_resolution_button.clicked.connect( + self.show_custom_resolution_dialog) def create_resolution_button_image(self, resolution_text): - template_path = os.path.join(self.btn_path, "resolution_template_button.png") - + template_path = os.path.join( + self.btn_path, "resolution_template_button.png") + if os.path.exists(template_path): base_image = QPixmap(template_path) if 'Resolution' in resolution_text: @@ -3942,20 +4206,21 @@ class ScreenPage(Page): base_image = QPixmap(185, 75) base_image.fill(QColor(44, 62, 80)) font_size = 13 - + painter = QPainter(base_image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) - + font = QFont() font.setPointSize(font_size) font.setBold(True) painter.setFont(font) - + painter.setPen(QColor(0, 255, 255)) - + text_rect = base_image.rect() - painter.drawText(text_rect, Qt.AlignmentFlag.AlignCenter | Qt.AlignmentFlag.AlignVCenter, resolution_text) - + painter.drawText(text_rect, Qt.AlignmentFlag.AlignCenter | + Qt.AlignmentFlag.AlignVCenter, resolution_text) + painter.end() return base_image @@ -3965,8 +4230,9 @@ class ScreenPage(Page): else: self.hide_standard_resolutions() self.showing_larger_resolutions = True - self.larger_resolutions_button.setIcon(QIcon(self.create_resolution_button_image("Standard Resolutions"))) - + self.larger_resolutions_button.setIcon( + QIcon(self.create_resolution_button_image("Standard Resolutions"))) + larger_resolutions = [ ("2560x1600", (595, 90, 180, 70)), ("2560x1440", (595, 170, 180, 70)), @@ -3974,15 +4240,17 @@ class ScreenPage(Page): ("1792x1344", (595, 330, 180, 70)), ("2048x1152", (595, 410, 180, 70)) ] - + for i, (resolution, geometry) in enumerate(larger_resolutions): button = QPushButton(self) button.setGeometry(*geometry) button.setIconSize(button.size()) button.setCheckable(True) button.setVisible(True) - button.setIcon(QIcon(self.create_resolution_button_image(resolution))) - button.clicked.connect(lambda _, res=resolution: self.show_dimentions(res)) + button.setIcon( + QIcon(self.create_resolution_button_image(resolution))) + button.clicked.connect( + lambda _, res=resolution: self.show_dimentions(res)) self.larger_resolution_buttons.append(button) self.buttonGroup.addButton(button, len(self.buttons) + i) @@ -3992,7 +4260,8 @@ class ScreenPage(Page): button.deleteLater() self.larger_resolution_buttons.clear() self.showing_larger_resolutions = False - self.larger_resolutions_button.setIcon(QIcon(self.create_resolution_button_image("Larger Resolutions"))) + self.larger_resolutions_button.setIcon( + QIcon(self.create_resolution_button_image("Larger Resolutions"))) self.show_standard_resolutions() def hide_standard_resolutions(self): @@ -4069,21 +4338,24 @@ class ScreenPage(Page): try: width = int(width_input.text()) height = int(height_input.text()) - + if width <= 0 or height <= 0: - QMessageBox.warning(dialog, "Invalid Resolution", "Width and height must be positive numbers.") + QMessageBox.warning( + dialog, "Invalid Resolution", "Width and height must be positive numbers.") return - + if width > 10000 or height > 10000: - QMessageBox.warning(dialog, "Invalid Resolution", "Resolution too large. Maximum 10000x10000.") + QMessageBox.warning( + dialog, "Invalid Resolution", "Resolution too large. Maximum 10000x10000.") return - + custom_resolution = f"{width}x{height}" self.show_dimentions(custom_resolution) dialog.accept() - + except ValueError: - QMessageBox.warning(dialog, "Invalid Input", "Please enter valid numbers for width and height.") + QMessageBox.warning( + dialog, "Invalid Input", "Please enter valid numbers for width and height.") ok_button.clicked.connect(validate_and_accept) cancel_button.clicked.connect(dialog.reject) @@ -4101,62 +4373,68 @@ class ScreenPage(Page): try: image_path = os.path.join(self.btn_path, f"{dimentions}.png") if os.path.exists(image_path): - self.display.setPixmap(QPixmap(image_path).scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) + self.display.setPixmap(QPixmap(image_path).scaled( + self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) else: self.create_resolution_preview_image(dimentions) except: self.display.clear() - + self.selected_dimentions_icon = dimentions self.button_next.setVisible(True) self.update_swarp_json() def create_resolution_preview_image(self, resolution_text): template_path = os.path.join(self.btn_path, "resolution_template.png") - + if os.path.exists(template_path): base_image = QPixmap(template_path) - base_image = base_image.scaled(580, 435, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) + base_image = base_image.scaled( + 580, 435, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) else: base_image = QPixmap(580, 435) base_image.fill(QColor(44, 62, 80)) - + painter = QPainter(base_image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) - + try: width, height = map(int, resolution_text.split('x')) gcd = self._gcd(width, height) aspect_ratio = f"{width//gcd}:{height//gcd}" except: aspect_ratio = "" - + font = QFont() font.setPointSize(24) font.setBold(True) painter.setFont(font) painter.setPen(QColor(0, 255, 255)) - + text_rect = base_image.rect() - painter.drawText(text_rect, Qt.AlignmentFlag.AlignCenter, resolution_text) - + painter.drawText( + text_rect, Qt.AlignmentFlag.AlignCenter, resolution_text) + if aspect_ratio: font.setPointSize(16) painter.setFont(font) - painter.setPen(QColor(200, 200, 200)) - - aspect_rect = QRect(text_rect.x(), text_rect.y() + 80, text_rect.width(), 40) - painter.drawText(aspect_rect, Qt.AlignmentFlag.AlignCenter, f"({aspect_ratio})") - + painter.setPen(QColor(200, 200, 200)) + + aspect_rect = QRect( + text_rect.x(), text_rect.y() + 80, text_rect.width(), 40) + painter.drawText( + aspect_rect, Qt.AlignmentFlag.AlignCenter, f"({aspect_ratio})") + painter.end() - + self.display.setPixmap(base_image) - + def _gcd(self, a, b): while b: a, b = b, a % b return a + class ResumePage(Page): def __init__(self, page_stack, main_window=None, parent=None): super().__init__("Resume", page_stack, main_window, parent) @@ -4167,70 +4445,85 @@ class ResumePage(Page): self.additional_labels = [] self.button_go.clicked.connect(self.copy_profile) self.button_back.setVisible(True) - self.title.setGeometry(585, 40, 185, 40); self.title.setText("Profile Summary") - self.display.setGeometry(QtCore.QRect(5, 50, 580, 435))#relacion 4:3 - self.buttonGroup = QButtonGroup(self) + self.title.setGeometry(585, 40, 185, 40) + self.title.setText("Profile Summary") + self.display.setGeometry(QtCore.QRect(5, 50, 580, 435)) # relacion 4:3 + self.buttonGroup = QButtonGroup(self) self.button_back.clicked.connect(self.reverse) self.create_arrow() self.create_interface_elements() def reverse(self): if self.connection_type == "system-wide": - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(LocationPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(LocationPage))) else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ScreenPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ScreenPage))) def show_location_verification(self, location_icon_name): - verification_page = LocationVerificationPage(self.page_stack, self.update_status, location_icon_name, self) + verification_page = LocationVerificationPage( + self.page_stack, self.update_status, location_icon_name, self) self.page_stack.addWidget(verification_page) - self.page_stack.setCurrentIndex(self.page_stack.indexOf(verification_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(verification_page)) def create_arrow(self): self.arrow_label = QLabel(self) - self.arrow_label.setGeometry(400, 115, 200, 200) - arrow_pixmap = QPixmap(os.path.join(self.btn_path, "arrow.png")) + self.arrow_label.setGeometry(400, 115, 200, 200) + arrow_pixmap = QPixmap(os.path.join(self.btn_path, "arrow.png")) self.arrow_label.setPixmap(arrow_pixmap) self.arrow_label.setScaledContents(True) - - self.arrow_label.raise_() + self.arrow_label.raise_() def showEvent(self, event): super().showEvent(event) self.arrow_label.show() - self.arrow_label.raise_() + self.arrow_label.raise_() def create_interface_elements(self): for j, (object_type, icon_name, geometry) in enumerate([ (QLineEdit, None, (130, 73, 300, 24)), - (QLabel, None, (0,0,0,0)) + (QLabel, None, (0, 0, 0, 0)) ]): if object_type == QLabel: label = object_type(self) label.setGeometry(*geometry) - icon_path = os.path.join(self.btn_path, f"{icon_name}_button.png") + icon_path = os.path.join( + self.btn_path, f"{icon_name}_button.png") if os.path.exists(icon_path): label.setPixmap(QPixmap(icon_path)) - locations = self.connection_manager.get_location_info(icon_name) - provider = locations.operator.name if locations and hasattr(locations, 'operator') else None + locations = self.connection_manager.get_location_info( + icon_name) + provider = locations.operator.name if locations and hasattr( + locations, 'operator') else None if label.pixmap().isNull(): if locations and hasattr(locations, 'country_name'): - label.setPixmap(LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', os.path.join(self.btn_path, "default_location_button.png"), provider)) + location_name = locations.country_name + label.setPixmap(LocationPage.create_location_button_image( + location_name, os.path.join(self.btn_path, "default_location_button.png"), provider)) else: - label.setPixmap(LocationPage.create_location_button_image('', os.path.join(self.btn_path, "default_location_button.png"), provider)) + label.setPixmap(LocationPage.create_location_button_image( + '', os.path.join(self.btn_path, "default_location_button.png"), provider)) else: if locations and hasattr(locations, 'country_name'): - label.setPixmap(LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', os.path.join(self.btn_path, "default_location_button.png"), provider, icon_path)) + label.setPixmap(LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', os.path.join( + self.btn_path, "default_location_button.png"), provider, icon_path)) else: - label.setPixmap(LocationPage.create_location_button_image('', os.path.join(self.btn_path, "default_location_button.png"), provider, icon_path)) + label.setPixmap(LocationPage.create_location_button_image('', os.path.join( + self.btn_path, "default_location_button.png"), provider, icon_path)) elif object_type == QLineEdit: - self.line_edit = object_type(self) # Define line_edit como un atributo de la clase ResumePage + # Define line_edit como un atributo de la clase ResumePage + self.line_edit = object_type(self) self.line_edit.setGeometry(*geometry) self.line_edit.setMaxLength(13) - self.line_edit.textChanged.connect(self.toggle_button_visibility) - self.line_edit.setStyleSheet("background-color: transparent; border: none; color: cyan;") + self.line_edit.textChanged.connect( + self.toggle_button_visibility) + self.line_edit.setStyleSheet( + "background-color: transparent; border: none; color: cyan;") self.line_edit.setPlaceholderText("Enter profile name") self.line_edit.setAlignment(Qt.AlignmentFlag.AlignCenter) self.create() @@ -4245,11 +4538,13 @@ class ResumePage(Page): connection_exists = 'connection' in profile_1 if connection_exists and profile_1['connection'] not in ["tor", "just proxy"]: - items = ["protocol", "connection", "location", "browser", "dimentions"] + items = ["protocol", "connection", + "location", "browser", "dimentions"] initial_y = 90 label_height = 80 elif connection_exists: # si la conexión existe pero su texto es 'tor' o 'just proxy' - items = ["protocol", "connection", "location", "browser", "dimentions"] + items = ["protocol", "connection", + "location", "browser", "dimentions"] initial_y = 90 label_height = 80 else: @@ -4260,50 +4555,64 @@ class ResumePage(Page): text = profile_1.get(item, "") if text: if item == 'browser': - base_image = BrowserPage.create_browser_button_image(text, self.btn_path) + base_image = BrowserPage.create_browser_button_image( + text, self.btn_path) geometry = (585, initial_y + i * label_height, 185, 75) parent_label = QLabel(self) parent_label.setGeometry(*geometry) parent_label.setPixmap(base_image) if parent_label.pixmap().isNull(): - fallback_path = os.path.join(self.btn_path, "default_browser_button.png") - base_image = BrowserPage.create_browser_button_image(text, fallback_path, True) + fallback_path = os.path.join( + self.btn_path, "default_browser_button.png") + base_image = BrowserPage.create_browser_button_image( + text, fallback_path, True) parent_label.setPixmap(base_image) parent_label.show() self.labels_creados.append(parent_label) elif item == 'location': - icon_path = os.path.join(self.btn_path, f"button_{text}.png") + icon_path = os.path.join( + self.btn_path, f"button_{text}.png") geometry = (585, initial_y + i * label_height, 185, 75) parent_label = QPushButton(self) parent_label.setGeometry(*geometry) parent_label.setFlat(True) - parent_label.setStyleSheet("background: transparent; border: none;") + parent_label.setStyleSheet( + "background: transparent; border: none;") location_pixmap = QPixmap(icon_path) locations = self.connection_manager.get_location_info(text) - provider = locations.operator.name if locations and hasattr(locations, 'operator') else None - fallback_path = os.path.join(self.btn_path, "default_location_button.png") + provider = locations.operator.name if locations and hasattr( + locations, 'operator') else None + fallback_path = os.path.join( + self.btn_path, "default_location_button.png") if location_pixmap.isNull(): if locations and hasattr(locations, 'country_name'): - base_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider) + base_image = LocationPage.create_location_button_image( + f'{locations.country_code}_{locations.code}', fallback_path, provider) parent_label.setIcon(QIcon(base_image)) else: - base_image = LocationPage.create_location_button_image('', fallback_path, provider) + base_image = LocationPage.create_location_button_image( + '', fallback_path, provider) parent_label.setIcon(QIcon(base_image)) else: if locations and hasattr(locations, 'country_name'): - base_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider, icon_path) + base_image = LocationPage.create_location_button_image( + f'{locations.country_code}_{locations.code}', fallback_path, provider, icon_path) parent_label.setIcon(QIcon(base_image)) else: - base_image = LocationPage.create_location_button_image('', fallback_path, provider, icon_path) + base_image = LocationPage.create_location_button_image( + '', fallback_path, provider, icon_path) parent_label.setIcon(QIcon(base_image)) parent_label.setIconSize(QSize(185, 75)) parent_label.location_icon_name = text - parent_label.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) - parent_label.clicked.connect(lambda checked, loc=text: self.show_location_verification(loc)) + parent_label.setCursor( + QtCore.Qt.CursorShape.PointingHandCursor) + parent_label.clicked.connect( + lambda checked, loc=text: self.show_location_verification(loc)) parent_label.show() self.labels_creados.append(parent_label) elif item == 'dimentions': - base_image = ScreenPage.create_resolution_button_image(self, text) + base_image = ScreenPage.create_resolution_button_image( + self, text) geometry = (585, initial_y + i * label_height, 185, 75) parent_label = QLabel(self) parent_label.setGeometry(*geometry) @@ -4311,7 +4620,8 @@ class ResumePage(Page): parent_label.show() self.labels_creados.append(parent_label) else: - icon_path = os.path.join(self.btn_path, f"{text}_button.png") + icon_path = os.path.join( + self.btn_path, f"{text}_button.png") geometry = (585, initial_y + i * label_height, 185, 75) parent_label = QLabel(self) parent_label.setGeometry(*geometry) @@ -4322,31 +4632,33 @@ class ResumePage(Page): if connection_exists: if profile_1.get("connection", "") == "system-wide": - image_path = os.path.join(self.btn_path, f"wireguard_{profile_1.get('location', '')}.png") + image_path = os.path.join( + self.btn_path, f"wireguard_{profile_1.get('location', '')}.png") main_label = QLabel(self) main_label.setGeometry(10, 130, 500, 375) main_label.setPixmap(QPixmap(image_path)) main_label.setScaledContents(True) - main_label.show() - self.labels_creados.append(main_label) + main_label.show() + self.labels_creados.append(main_label) - if profile_1.get("connection", "") == "just proxy": - image_path = os.path.join(self.btn_path, f"icon_{profile_1.get('location', '')}.png") + image_path = os.path.join( + self.btn_path, f"icon_{profile_1.get('location', '')}.png") main_label = QLabel(self) main_label.setGeometry(10, 105, 530, 398) main_label.setPixmap(QPixmap(image_path)) main_label.setScaledContents(True) - main_label.show() - self.labels_creados.append(main_label) + main_label.show() + self.labels_creados.append(main_label) if profile_1.get("connection", "") == "tor": - image_path = os.path.join(self.btn_path, f"hdtor_{profile_1.get('location', '')}.png") + image_path = os.path.join( + self.btn_path, f"hdtor_{profile_1.get('location', '')}.png") main_label = QLabel(self) main_label.setGeometry(10, 105, 530, 398) main_label.setPixmap(QPixmap(image_path)) main_label.setScaledContents(True) - main_label.show() - self.labels_creados.append(main_label) + main_label.show() + self.labels_creados.append(main_label) if profile_1.get("connection", "") == "browser-only": image_name = "browser only.png" image_path = os.path.join(self.btn_path, image_name) @@ -4357,21 +4669,23 @@ class ResumePage(Page): label_background.show() label_background.lower() self.labels_creados.append(label_background) - image_path = os.path.join(self.btn_path, f"wireguard_{profile_1.get('location', '')}.png") + image_path = os.path.join( + self.btn_path, f"wireguard_{profile_1.get('location', '')}.png") main_label = QLabel(self) main_label.setGeometry(10, 130, 500, 375) main_label.setPixmap(QPixmap(image_path)) main_label.setScaledContents(True) main_label.show() - self.labels_creados.append(main_label) - else: - image_path = os.path.join(self.btn_path, f"icon_{profile_1.get('location', '')}.png") - main_label = QLabel(self) - main_label.setGeometry(10, 130, 500, 375) - main_label.setPixmap(QPixmap(image_path)) - main_label.setScaledContents(True) - main_label.show() - self.labels_creados.append(main_label) + self.labels_creados.append(main_label) + else: + image_path = os.path.join( + self.btn_path, f"icon_{profile_1.get('location', '')}.png") + main_label = QLabel(self) + main_label.setGeometry(10, 130, 500, 375) + main_label.setPixmap(QPixmap(image_path)) + main_label.setScaledContents(True) + main_label.show() + self.labels_creados.append(main_label) if hasattr(self, 'arrow_label'): self.arrow_label.raise_() @@ -4385,7 +4699,7 @@ class ResumePage(Page): if isinstance(page, MenuPage): return page return None - + def copy_profile(self): # Obtener el nombre del perfil ingresado en el QLineEdit profile_name = self.line_edit.text() @@ -4396,33 +4710,30 @@ class ResumePage(Page): # Abrir y cargar los datos de swarp.json profile_data = self.update_status.read_data() - # Verificar si los campos necesarios están llenos required_fields = [profile_data.get("protocol"), profile_name] if not all(required_fields): print("Error: Some required fields are empty!") return - + # Actualizar el nombre del perfil con el texto ingresado profile_data["name"] = profile_name profile_data["visible"] = "yes" - - - #profile_id = int(number_of_profiles) + 1 + # profile_id = int(number_of_profiles) + 1 profiles = ProfileController.get_all() profile_id = self.get_next_available_id(profiles) new_profile = profile_data self.create_core_profiles(new_profile, profile_id) - - + main = self.update_status if hasattr(main, 'navigate_after_profile_created'): main.navigate_after_profile_created() else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) - + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.update_status.clear_data() # Limpiar el QLineEdit @@ -4433,28 +4744,29 @@ class ResumePage(Page): def get_next_available_id(self, profiles: dict) -> int: if not profiles: return 1 - + existing_ids = sorted(profiles.keys()) - + for i in range(1, max(existing_ids) + 2): if i not in existing_ids: return i - + return None def create_core_profiles(self, profile, id): if profile.get('connection') != 'system-wide': browser_info = profile.get('browser', '').split() if len(browser_info) < 2: - self.update_status.update_status('Application version not supported') + self.update_status.update_status( + 'Application version not supported') return application = f"{browser_info[0].lower()}:{browser_info[1]}" else: application = '' - + parts = profile.get('location').split('_') - country_code = parts[0] + country_code = parts[0] location_code = parts[1] if profile.get('protocol') == 'wireguard': connection_type = 'wireguard' @@ -4476,19 +4788,18 @@ class ResumePage(Page): 'connection_type': connection_type, 'resolution': profile.get('dimentions', ''), } - profile_type = 'system' if profile.get('connection') == 'system-wide' else 'session' + profile_type = 'system' if profile.get( + 'connection') == 'system-wide' else 'session' action = f'CREATE_{profile_type.upper()}_PROFILE' - - self.handle_core_action_create_profile(action, profile_data, profile_type) - + self.handle_core_action_create_profile( + action, profile_data, profile_type) def eliminacion(self): for label in self.labels_creados: label.deleteLater() # Limpia la lista de referencia - self.labels_creados = [] self.create() @@ -4506,13 +4817,14 @@ class ResumePage(Page): def update_output(self, text): self.update_status.update_status(text) - def on_profile_creation(self, result): - + if self.worker_thread: self.worker_thread.quit() self.worker_thread.wait() self.worker_thread = None + + class EditorPage(Page): def __init__(self, page_stack, main_window): super().__init__("Editor", page_stack, main_window) @@ -4521,12 +4833,12 @@ class EditorPage(Page): self.connection_manager = main_window.connection_manager self.labels = [] # Lista para almacenar los labels dinámicamente self.buttons = [] # Lista para almacenar los labels dinámicamente - self.title.setGeometry(570, 40, 185, 40); self.title.setText("Edit Profile") + self.title.setGeometry(570, 40, 185, 40) + self.title.setText("Edit Profile") - self.button_apply.setVisible(True) self.button_apply.clicked.connect(self.go_selected) - + self.button_back.setVisible(True) try: self.button_back.clicked.disconnect() @@ -4541,35 +4853,39 @@ class EditorPage(Page): self.name_hint = QLabel(self) self.name_hint.setGeometry(265, 100, 190, 20) - self.name_hint.setStyleSheet('color: #888888; font-size: 10px; font-style: italic;') + self.name_hint.setStyleSheet( + 'color: #888888; font-size: 10px; font-style: italic;') self.name_hint.setText("Click here to edit profile name") self.name_hint.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.name = QLineEdit(self) self.name.setPlaceholderText("Enter name") self.name.setGeometry(265, 70, 190, 30) - self.name.setStyleSheet("color: cyan; border: 1px solid #666666; border-radius: 3px; background-color: rgba(0, 0, 0, 0.3);") - self.name.setCursor(QtCore.Qt.CursorShape.IBeamCursor) + self.name.setStyleSheet( + "color: cyan; border: 1px solid #666666; border-radius: 3px; background-color: rgba(0, 0, 0, 0.3);") + self.name.setCursor(QtCore.Qt.CursorShape.IBeamCursor) self.name.focusInEvent = lambda event: self.name_hint.hide() - self.name.focusOutEvent = lambda event: self.name_hint.show() if not self.name.text() else self.name_hint.hide() - - self.name.textChanged.connect(lambda text: self.name_hint.hide() if text else self.name_hint.show()) + self.name.focusOutEvent = lambda event: self.name_hint.show( + ) if not self.name.text() else self.name_hint.hide() + + self.name.textChanged.connect( + lambda text: self.name_hint.hide() if text else self.name_hint.show()) self.temp_changes = {} self.original_values = {} - self.display.setGeometry(QtCore.QRect(0, 60, 540, 405)) + self.display.setGeometry(QtCore.QRect(0, 60, 540, 405)) self.display.hide() - self.garaje=QLabel(self) + self.garaje = QLabel(self) self.garaje.setGeometry(QtCore.QRect(0, 70, 540, 460)) - - self.brow_disp=QLabel(self) - self.brow_disp.setGeometry(QtCore.QRect(0, 50, 540, 460)) - self.brow_disp.setPixmap(QPixmap(os.path.join(self.btn_path, "browser only.png"))) + self.brow_disp = QLabel(self) + self.brow_disp.setGeometry(QtCore.QRect(0, 50, 540, 460)) + self.brow_disp.setPixmap( + QPixmap(os.path.join(self.btn_path, "browser only.png"))) self.brow_disp.hide() self.brow_disp.lower() - + def update_name_value(self): original_name = self.data_profile.get('name', '') new_name = self.name.text() @@ -4577,13 +4893,15 @@ class EditorPage(Page): self.update_temp_value('name', new_name) else: pass - + def go_back(self): - selected_profiles_str = ', '.join([f"Profile_{profile['profile_number']}" for profile in self.page_stack.widget(0).selected_profiles]) + selected_profiles_str = ', '.join( + [f"Profile_{profile['profile_number']}" for profile in self.page_stack.widget(0).selected_profiles]) if self.has_unsaved_changes(selected_profiles_str): self.show_unsaved_changes_popup() else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def find_menu_page(self): for i in range(self.page_stack.count()): @@ -4591,21 +4909,21 @@ class EditorPage(Page): if isinstance(page, MenuPage): return page return None - + def find_resume_page(self): for i in range(self.page_stack.count()): page = self.page_stack.widget(i) if isinstance(page, ResumePage): return page return None - + def find_protocol_page(self): for i in range(self.page_stack.count()): page = self.page_stack.widget(i) if isinstance(page, ProtocolPage): return page return None - + def showEvent(self, event): super().showEvent(event) self.extraccion() @@ -4617,18 +4935,21 @@ class EditorPage(Page): self.labels = [] for button in self.buttons: button.deleteLater() - self.buttons = [] + self.buttons = [] - selected_profiles_str = ', '.join([f"Profile_{profile['profile_number']}" for profile in self.page_stack.widget(0).selected_profiles]) + selected_profiles_str = ', '.join( + [f"Profile_{profile['profile_number']}" for profile in self.page_stack.widget(0).selected_profiles]) menu_page = self.find_menu_page() if menu_page: new_profiles = ProfileController.get_all() - self.profiles_data = menu_page.match_core_profiles(profiles_dict=new_profiles) - self.data_profile = self.profiles_data[selected_profiles_str].copy() - + self.profiles_data = menu_page.match_core_profiles( + profiles_dict=new_profiles) + self.data_profile = self.profiles_data[selected_profiles_str].copy( + ) + profile_id = int(selected_profiles_str.split('_')[1]) self.data_profile['id'] = profile_id - + if selected_profiles_str in self.temp_changes: for key, value in self.temp_changes[selected_profiles_str].items(): self.data_profile[key] = value @@ -4648,7 +4969,7 @@ class EditorPage(Page): "browser": self.connection_manager.get_browser_list(), "dimentions": self.connection_manager.get_available_resolutions(data_profile.get('id', '')) }, selected_profile_str) - + elif protocol == "residential" or protocol == "hidetor": self.process_and_show_labels(data_profile, { "protocol": ['residential', 'wireguard', 'hidetor'], @@ -4657,7 +4978,7 @@ class EditorPage(Page): "browser": self.connection_manager.get_browser_list(), "dimentions": self.connection_manager.get_available_resolutions(data_profile.get('id', '')) }, selected_profile_str) - + elif protocol == "lokinet": self.process_and_show_labels(data_profile, { "protocol": ['lokinet'] @@ -4672,92 +4993,109 @@ class EditorPage(Page): def process_and_show_labels(self, data_profile, parameters, selected_profile_str): protocol = data_profile.get('protocol', "") - connection= data_profile.get('connection', "") + connection = data_profile.get('connection', "") location = data_profile.get('location', "") country_garaje = location name = data_profile.get('name', "") self.name.setText(name) - if protocol=="hidetor": + if protocol == "hidetor": if connection == "just proxy": - self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"icon_{location}.png"))) + self.display.setPixmap(QPixmap(os.path.join( + self.btn_path, f"icon_{location}.png"))) else: - self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"hdtor_{location}.png"))) + self.display.setPixmap(QPixmap(os.path.join( + self.btn_path, f"hdtor_{location}.png"))) self.display.show() self.display.setGeometry(0, 100, 400, 394) - + self.display.setScaledContents(True) - + self.garaje.hide() self.brow_disp.hide() - - if protocol=="wireguard": + if protocol == "wireguard": self.display.setGeometry(0, 60, 540, 405) self.display.show() - self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"wireguard_{location}.png"))) + self.display.setPixmap(QPixmap(os.path.join( + self.btn_path, f"wireguard_{location}.png"))) self.garaje.hide() if connection == "browser-only": is_supported = data_profile.get('browser_supported', False) image_name = "browser only.png" if is_supported else "unsupported_browser_only.png" - self.brow_disp.setPixmap(QPixmap(os.path.join(self.btn_path, image_name))) + self.brow_disp.setPixmap( + QPixmap(os.path.join(self.btn_path, image_name))) self.brow_disp.show() else: self.brow_disp.hide() - if protocol=="residential": + if protocol == "residential": self.display.setGeometry(0, 60, 540, 405) self.brow_disp.show() self.garaje.show() self.display.hide() - if country_garaje: + if country_garaje: country_garaje = 'brazil' - self.garaje.setPixmap(QPixmap(os.path.join(self.btn_path, f"{country_garaje} garaje.png"))) + self.garaje.setPixmap(QPixmap(os.path.join( + self.btn_path, f"{country_garaje} garaje.png"))) for i, key in enumerate(parameters.keys()): if key == 'browser': browser_value = f"{data_profile.get(key, '')}" split_value = browser_value.split(':', 1) browser_type = split_value[0] - browser_version = split_value[1] if len(split_value) > 1 else '' + browser_version = split_value[1] if len( + split_value) > 1 else '' browser_value = f"{browser_type} {browser_version}" if browser_version == '': - browser_version = data_profile.get('browser_version', '') + browser_version = data_profile.get('browser_version', '') browser_value = f"{browser_type} {browser_version}" if connection == 'system-wide' or not browser_value.strip(): - base_image = QPixmap() + base_image = QPixmap() else: - base_image = BrowserPage.create_browser_button_image(browser_value, self.btn_path) + base_image = BrowserPage.create_browser_button_image( + browser_value, self.btn_path) if base_image.isNull(): - fallback_path = os.path.join(self.btn_path, "default_browser_button.png") - base_image = BrowserPage.create_browser_button_image(browser_value, fallback_path, True) + fallback_path = os.path.join( + self.btn_path, "default_browser_button.png") + base_image = BrowserPage.create_browser_button_image( + browser_value, fallback_path, True) elif key == 'location': current_value = f"{data_profile.get(key, '')}" - image_path = os.path.join(self.btn_path, f"button_{current_value}.png") + image_path = os.path.join( + self.btn_path, f"button_{current_value}.png") base_image = QPixmap(image_path) - locations = self.connection_manager.get_location_info(current_value) - provider = locations.operator.name if locations and hasattr(locations, 'operator') else None - fallback_path = os.path.join(self.btn_path, "default_location_button.png") + locations = self.connection_manager.get_location_info( + current_value) + provider = locations.operator.name if locations and hasattr( + locations, 'operator') else None + fallback_path = os.path.join( + self.btn_path, "default_location_button.png") if base_image.isNull(): if locations and hasattr(locations, 'country_name'): - base_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider) + base_image = LocationPage.create_location_button_image( + f'{locations.country_code}_{locations.code}', fallback_path, provider) else: - base_image = LocationPage.create_location_button_image(current_value, fallback_path, provider) + base_image = LocationPage.create_location_button_image( + current_value, fallback_path, provider) else: if locations and hasattr(locations, 'country_name'): - base_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider, image_path) + base_image = LocationPage.create_location_button_image( + f'{locations.country_code}_{locations.code}', fallback_path, provider, image_path) else: - base_image = LocationPage.create_location_button_image(current_value, fallback_path, provider, image_path) + base_image = LocationPage.create_location_button_image( + current_value, fallback_path, provider, image_path) elif key == 'dimentions': current_value = f"{data_profile.get(key, '')}" if current_value != 'None': - base_image = ScreenPage.create_resolution_button_image(self, current_value) - else: - image_path = os.path.join(self.btn_path, f"{data_profile.get(key, '')}_button.png") + base_image = ScreenPage.create_resolution_button_image( + self, current_value) + else: + image_path = os.path.join( + self.btn_path, f"{data_profile.get(key, '')}_button.png") current_value = data_profile.get(key, '') base_image = QPixmap(image_path) - label = QLabel(key, self) label.setGeometry(565, 90 + i * 80, 185, 75) @@ -4765,11 +5103,12 @@ class EditorPage(Page): label.setScaledContents(True) label.show() self.labels.append(label) - + try: if key == 'browser': - value_index = [item.replace(':', ' ') for item in parameters[key]].index(browser_value) - else: + value_index = [item.replace( + ':', ' ') for item in parameters[key]].index(browser_value) + else: value_index = parameters[key].index(current_value) except ValueError: value_index = 0 @@ -4777,7 +5116,8 @@ class EditorPage(Page): # Botón para mostrar el valor anterior prev_button = QPushButton(self) prev_button.setGeometry(535, 90 + i * 80, 30, 75) - prev_button.clicked.connect(lambda _, k=key, idx=value_index: self.show_previous_value(k, idx, parameters)) + prev_button.clicked.connect( + lambda _, k=key, idx=value_index: self.show_previous_value(k, idx, parameters)) prev_button.show() icon_path = os.path.join(self.btn_path, f"UP_button.png") icon = QPixmap(icon_path) @@ -4799,12 +5139,13 @@ class EditorPage(Page): pen.setWidth(3) painter.setPen(pen) painter.setBrush(Qt.BrushStyle.NoBrush) - left_points = [QPointF(w*0.65, h*0.15), QPointF(w*0.25, h*0.50), QPointF(w*0.65, h*0.85)] + left_points = [ + QPointF(w*0.65, h*0.15), QPointF(w*0.25, h*0.50), QPointF(w*0.65, h*0.85)] painter.drawPolygon(QtGui.QPolygonF(left_points)) painter.end() prev_button.setIcon(QIcon(outline_pix)) prev_button.setIconSize(prev_button.size()) - + # Apply green styling for location and browser buttons to indicate sync requirement if (key == 'location' or key == 'browser') and not self.connection_manager.is_synced(): prev_button.setStyleSheet(""" @@ -4821,16 +5162,18 @@ class EditorPage(Page): border-radius: 3px; } """) - + self.buttons.append(prev_button) # Botón para mostrar el valor siguiente - next_button = QPushButton( self) + next_button = QPushButton(self) next_button.setGeometry(750, 90 + i * 80, 30, 75) - next_button.clicked.connect(lambda _, k=key, idx=value_index: self.show_next_value(k, idx, parameters)) + next_button.clicked.connect( + lambda _, k=key, idx=value_index: self.show_next_value(k, idx, parameters)) next_button.show() self.buttons.append(next_button) - next_button.setIcon(QIcon( os.path.join(self.btn_path, f"UP_button.png"))) + next_button.setIcon( + QIcon(os.path.join(self.btn_path, f"UP_button.png"))) next_button.setIconSize(next_button.size()) if (key == 'location' or key == 'browser') and not self.connection_manager.is_synced(): w = next_button.width() @@ -4843,12 +5186,13 @@ class EditorPage(Page): pen_r.setWidth(3) painter_r.setPen(pen_r) painter_r.setBrush(Qt.BrushStyle.NoBrush) - right_points = [QPointF(w*0.35, h*0.15), QPointF(w*0.75, h*0.50), QPointF(w*0.35, h*0.85)] + right_points = [ + QPointF(w*0.35, h*0.15), QPointF(w*0.75, h*0.50), QPointF(w*0.35, h*0.85)] painter_r.drawPolygon(QtGui.QPolygonF(right_points)) painter_r.end() next_button.setIcon(QIcon(outline_pix_r)) next_button.setIconSize(next_button.size()) - + # Apply green styling for location and browser buttons to indicate sync requirement if (key == 'location' or key == 'browser') and not self.connection_manager.is_synced(): next_button.setStyleSheet(""" @@ -4865,7 +5209,7 @@ class EditorPage(Page): border-radius: 3px; } """) - + prev_button.setVisible(True) next_button.setVisible(True) if key == 'protocol' or (protocol == 'wireguard' and key == 'connection'): @@ -4885,40 +5229,44 @@ class EditorPage(Page): self.update_status.update_status('Sync complete.') self.extraccion() else: - self.update_status.update_status('Sync failed. Please try again later.') + self.update_status.update_status( + 'Sync failed. Please try again later.') def show_previous_value(self, key: str, index: int, parameters: dict) -> None: if key == 'browser' or key == 'location': if not self.connection_manager.is_synced(): self.update_status.update_status('Syncing in progress..') self.update_status.sync() - self.update_status.worker_thread.sync_output.connect(self.on_sync_complete_for_edit_profile) + self.update_status.worker_thread.sync_output.connect( + self.on_sync_complete_for_edit_profile) return previous_index = (index - 1) % len(parameters[key]) previous_value = parameters[key][previous_index] self.update_temp_value(key, previous_value) - def show_next_value(self, key: str, index: int, parameters: dict) -> None: if key == 'browser' or key == 'location': if not self.connection_manager.is_synced(): self.update_status.update_status('Syncing in progress..') self.update_status.sync() - self.update_status.worker_thread.sync_output.connect(self.on_sync_complete_for_edit_profile) + self.update_status.worker_thread.sync_output.connect( + self.on_sync_complete_for_edit_profile) return - + next_index = (index + 1) % len(parameters[key]) next_value = parameters[key][next_index] self.update_temp_value(key, next_value) def update_temp_value(self, key: str, new_value: str) -> None: - selected_profiles_str = ', '.join([f"Profile_{profile['profile_number']}" for profile in self.page_stack.widget(0).selected_profiles]) + selected_profiles_str = ', '.join( + [f"Profile_{profile['profile_number']}" for profile in self.page_stack.widget(0).selected_profiles]) if selected_profiles_str not in self.temp_changes: self.temp_changes[selected_profiles_str] = {} - self.original_values[selected_profiles_str] = self.data_profile.copy() - + self.original_values[selected_profiles_str] = self.data_profile.copy( + ) + self.temp_changes[selected_profiles_str][key] = new_value self.extraccion() @@ -4933,14 +5281,13 @@ class EditorPage(Page): current_browser = f"{current_data.get('browser', '')} {current_data.get('browser_version', '')}" - if 'location' in temp_changes and temp_changes['location'] != current_data.get('location'): message = "A new location would require a new subscription code.\nDo you want to proceed with erasing the old one?" elif 'browser' in temp_changes and temp_changes['browser'] != current_browser: message = "Changing the browser would delete all data associated with it. Proceed?" else: return False - + self.popup = ConfirmationPopup( self, message=message, @@ -4948,10 +5295,11 @@ class EditorPage(Page): cancel_button_text="Cancel" ) self.popup.setWindowModality(Qt.WindowModality.ApplicationModal) - self.popup.finished.connect(lambda result: self.handle_apply_changes_response(result)) + self.popup.finished.connect( + lambda result: self.handle_apply_changes_response(result)) self.popup.show() return True - + def show_unsaved_changes_popup(self) -> None: self.popup = ConfirmationPopup( self, @@ -4960,51 +5308,57 @@ class EditorPage(Page): cancel_button_text="Cancel" ) self.popup.setWindowModality(Qt.WindowModality.ApplicationModal) - self.popup.finished.connect(lambda result: self.handle_unsaved_changes_response(result)) + self.popup.finished.connect( + lambda result: self.handle_unsaved_changes_response(result)) self.popup.show() def handle_apply_changes_response(self, result: bool) -> None: if result: self.commit_changes() - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def handle_unsaved_changes_response(self, result: bool) -> None: if result: self.temp_changes.clear() - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def go_selected(self) -> None: - selected_profiles_str = ', '.join([f"Profile_{profile['profile_number']}" - for profile in self.page_stack.widget(0).selected_profiles]) - + selected_profiles_str = ', '.join([f"Profile_{profile['profile_number']}" + for profile in self.page_stack.widget(0).selected_profiles]) + if selected_profiles_str in self.temp_changes and self.temp_changes[selected_profiles_str]: - needs_confirmation = self.show_apply_changes_popup(selected_profiles_str) + needs_confirmation = self.show_apply_changes_popup( + selected_profiles_str) if not needs_confirmation: self.commit_changes() - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) - + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + else: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) - - + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def commit_changes(self) -> None: - selected_profiles_str = ', '.join([f"Profile_{profile['profile_number']}" for profile in self.page_stack.widget(0).selected_profiles]) + selected_profiles_str = ', '.join( + [f"Profile_{profile['profile_number']}" for profile in self.page_stack.widget(0).selected_profiles]) if selected_profiles_str in self.temp_changes: for key, new_value in self.temp_changes[selected_profiles_str].items(): self.update_core_profiles(key, new_value) - + self.temp_changes.pop(selected_profiles_str, None) self.original_values.pop(selected_profiles_str, None) def update_core_profiles(self, key, new_value): - profile = ProfileController.get(int(self.update_status.current_profile_id)) + profile = ProfileController.get( + int(self.update_status.current_profile_id)) self.update_res = False if key == 'dimentions': profile.resolution = new_value self.update_res = True - elif key == 'name': + elif key == 'name': profile.name = new_value elif key == 'connection': @@ -5015,14 +5369,14 @@ class EditorPage(Page): profile.connection.code = 'system' profile.connection.masked = True else: - self.update_status.update_status('System wide profiles not supported atm') + self.update_status.update_status( + 'System wide profiles not supported atm') elif key == 'browser': browser_type, browser_version = new_value.split(':', 1) profile.application_version.application_code = browser_type profile.application_version.version_number = browser_version - elif key == 'protocol': if self.data_profile.get('connection') == 'system-wide': self.edit_to_session() @@ -5033,22 +5387,14 @@ class EditorPage(Page): else: location = self.connection_manager.get_location_info(new_value) - if location: profile.location.code = location.code - profile.location.country_code = location.country_code + profile.location.country_code = location.country_code profile.location.time_zone = location.time_zone profile.subscription = None - ProfileController.update(profile) - - - - - - ''' def edit_to_system(self): id = int(self.update_status.current_profile_id) @@ -5085,8 +5431,9 @@ class EditorPage(Page): profile = self.data_profile default_app = 'firefox:123.0' default_resolution = '1024x760' - location_code = self.connection_manager.get_location_info(profile.get('location')) - + location_code = self.connection_manager.get_location_info( + profile.get('location')) + connection_type = 'tor' profile_data = { @@ -5094,13 +5441,15 @@ class EditorPage(Page): 'name': profile.get('name'), 'country_code': location_code.country_code, 'code': location_code.code, - 'application': default_app , + 'application': default_app, 'connection_type': connection_type, 'resolution': default_resolution, } resume_page = self.find_resume_page() if resume_page: - resume_page.handle_core_action_create_profile('CREATE_SESSION_PROFILE', profile_data, 'session') + resume_page.handle_core_action_create_profile( + 'CREATE_SESSION_PROFILE', profile_data, 'session') + class LocationVerificationPage(Page): def __init__(self, page_stack, main_window, location_icon_name, previous_page, parent=None): @@ -5127,20 +5476,24 @@ class LocationVerificationPage(Page): location_display = QLabel(self) location_display.setGeometry(10, 0, 390, 520) location_display.setAlignment(Qt.AlignmentFlag.AlignCenter) - - icon_path = os.path.join(self.btn_path, f"icon_{self.location_icon_name}.png") + + icon_path = os.path.join( + self.btn_path, f"icon_{self.location_icon_name}.png") location_pixmap = QPixmap(icon_path) - fallback_path = os.path.join(self.btn_path, "default_location_button.png") - + fallback_path = os.path.join( + self.btn_path, "default_location_button.png") + if location_pixmap.isNull(): location_pixmap = QPixmap(fallback_path) - - location_display.setPixmap(location_pixmap.scaled(390, 520, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) + + location_display.setPixmap(location_pixmap.scaled( + 390, 520, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) location_display.show() title = QLabel("Operator Information", self) title.setGeometry(350, 50, 350, 30) - title.setStyleSheet(f"color: #808080; font-size: 20px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 20px; font-weight: bold; {self.font_style}") title.show() info_items = [ @@ -5167,20 +5520,26 @@ class LocationVerificationPage(Page): for label_text, key, y_pos in info_items: label_widget = QLabel(label_text + ":", self) label_widget.setGeometry(label_x, y_pos, label_width, label_height) - label_widget.setStyleSheet(f"color: white; font-size: 18px; {self.font_style}") - label_widget.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) + label_widget.setStyleSheet( + f"color: white; font-size: 18px; {self.font_style}") + label_widget.setAlignment( + Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) label_widget.show() self.verification_labels[key] = label_widget value_widget = QLabel("N/A", self) value_widget.setGeometry(value_x, y_pos, value_width, value_height) - value_widget.setStyleSheet(f"color: white; font-size: 16px; {self.font_style}") - value_widget.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) + value_widget.setStyleSheet( + f"color: white; font-size: 16px; {self.font_style}") + value_widget.setAlignment( + Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) value_widget.show() checkmark_widget = QLabel("✓", self) - checkmark_widget.setGeometry(checkmark_x, y_pos, checkmark_width, checkmark_height) - checkmark_widget.setStyleSheet(f"color: #4CAF50; font-size: 28px; font-weight: bold; {self.font_style}") + checkmark_widget.setGeometry( + checkmark_x, y_pos, checkmark_width, checkmark_height) + checkmark_widget.setStyleSheet( + f"color: #4CAF50; font-size: 28px; font-weight: bold; {self.font_style}") checkmark_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) checkmark_widget.hide() @@ -5188,8 +5547,10 @@ class LocationVerificationPage(Page): self.verification_checkmarks[key] = checkmark_widget copy_button = QPushButton(self) - copy_button.setGeometry(copy_button_x, y_pos, copy_button_width, copy_button_height) - copy_button.setIcon(QIcon(os.path.join(self.btn_path, "paste_button.png"))) + copy_button.setGeometry( + copy_button_x, y_pos, copy_button_width, copy_button_height) + copy_button.setIcon( + QIcon(os.path.join(self.btn_path, "paste_button.png"))) copy_button.setIconSize(QSize(24, 24)) copy_button.setStyleSheet(f""" QPushButton {{ @@ -5201,13 +5562,15 @@ class LocationVerificationPage(Page): border-radius: 4px; }} """) - copy_button.clicked.connect(lambda checked=False, k=key: self.copy_verification_value(k)) + copy_button.clicked.connect( + lambda checked=False, k=key: self.copy_verification_value(k)) copy_button.show() self.verification_copy_buttons[key] = copy_button self.back_button = QPushButton(self) self.back_button.setGeometry(720, 525, 48, 35) - self.back_button.setIcon(QIcon(os.path.join(self.btn_path, "back.png"))) + self.back_button.setIcon( + QIcon(os.path.join(self.btn_path, "back.png"))) self.back_button.setIconSize(QSize(48, 35)) self.back_button.setStyleSheet(f""" QPushButton {{ @@ -5227,28 +5590,29 @@ class LocationVerificationPage(Page): def truncate_text_by_width(self, text, widget, max_width): if not text or text == "N/A": return text - + metrics = widget.fontMetrics() text_width = metrics.horizontalAdvance(text) - + if text_width <= max_width: return text - + ellipsis = "..." ellipsis_width = metrics.horizontalAdvance(ellipsis) available_width = max_width - ellipsis_width - + if available_width <= 0: return ellipsis - + start_chars = 1 end_chars = 1 - + while True: start_text = text[:start_chars] end_text = text[-end_chars:] - combined_width = metrics.horizontalAdvance(start_text + ellipsis + end_text) - + combined_width = metrics.horizontalAdvance( + start_text + ellipsis + end_text) + if combined_width <= max_width: if start_chars + end_chars >= len(text): return text @@ -5262,16 +5626,17 @@ class LocationVerificationPage(Page): if end_chars > 1: end_chars -= 1 break - + if start_chars + end_chars >= len(text): return text - + return text[:start_chars] + ellipsis + text[-end_chars:] def update_verification_info(self): - locations = self.connection_manager.get_location_info(self.location_icon_name) + locations = self.connection_manager.get_location_info( + self.location_icon_name) value_width = 210 - + if not locations: for key, widget in self.verification_info.items(): widget.setText("N/A") @@ -5287,28 +5652,36 @@ class LocationVerificationPage(Page): if operator: operator_name = operator.name or "N/A" self.verification_full_values["operator_name"] = operator_name - display_operator = self.truncate_text_by_width(operator_name, self.verification_info["operator_name"], value_width) + display_operator = self.truncate_text_by_width( + operator_name, self.verification_info["operator_name"], value_width) self.verification_info["operator_name"].setText(display_operator) - - provider_name = locations.provider_name if locations and hasattr(locations, 'provider_name') and locations.provider_name else "N/A" + + provider_name = locations.provider_name if locations and hasattr( + locations, 'provider_name') and locations.provider_name else "N/A" self.verification_full_values["provider_name"] = provider_name - display_provider = self.truncate_text_by_width(provider_name, self.verification_info["provider_name"], value_width) + display_provider = self.truncate_text_by_width( + provider_name, self.verification_info["provider_name"], value_width) self.verification_info["provider_name"].setText(display_provider) - + nostr_key = operator.nostr_public_key or "N/A" self.verification_full_values["nostr_public_key"] = nostr_key - display_nostr = self.truncate_text_by_width(nostr_key, self.verification_info["nostr_public_key"], value_width) + display_nostr = self.truncate_text_by_width( + nostr_key, self.verification_info["nostr_public_key"], value_width) self.verification_info["nostr_public_key"].setText(display_nostr) - + hydraveil_key = operator.public_key or "N/A" self.verification_full_values["hydraveil_public_key"] = hydraveil_key - display_hydraveil = self.truncate_text_by_width(hydraveil_key, self.verification_info["hydraveil_public_key"], value_width) - self.verification_info["hydraveil_public_key"].setText(display_hydraveil) - + display_hydraveil = self.truncate_text_by_width( + hydraveil_key, self.verification_info["hydraveil_public_key"], value_width) + self.verification_info["hydraveil_public_key"].setText( + display_hydraveil) + nostr_verification = operator.nostr_attestation_event_reference or "N/A" self.verification_full_values["nostr_attestation_event_reference"] = nostr_verification - display_nostr_verif = self.truncate_text_by_width(nostr_verification, self.verification_info["nostr_attestation_event_reference"], value_width) - self.verification_info["nostr_attestation_event_reference"].setText(display_nostr_verif) + display_nostr_verif = self.truncate_text_by_width( + nostr_verification, self.verification_info["nostr_attestation_event_reference"], value_width) + self.verification_info["nostr_attestation_event_reference"].setText( + display_nostr_verif) else: self.verification_info["operator_name"].setText("N/A") self.verification_full_values["operator_name"] = "N/A" @@ -5318,9 +5691,10 @@ class LocationVerificationPage(Page): self.verification_full_values["nostr_public_key"] = "N/A" self.verification_info["hydraveil_public_key"].setText("N/A") self.verification_full_values["hydraveil_public_key"] = "N/A" - self.verification_info["nostr_attestation_event_reference"].setText("N/A") + self.verification_info["nostr_attestation_event_reference"].setText( + "N/A") self.verification_full_values["nostr_attestation_event_reference"] = "N/A" - + for key, widget in self.verification_info.items(): if key in self.verification_checkmarks: full_value = self.verification_full_values.get(key, "") @@ -5334,12 +5708,16 @@ class LocationVerificationPage(Page): if full_value and full_value != "N/A": clipboard = QApplication.clipboard() clipboard.setText(full_value) - display_name = self.verification_display_names.get(key, "Verification value") - self.custom_window.update_status(f"{display_name} copied to clipboard") + display_name = self.verification_display_names.get( + key, "Verification value") + self.custom_window.update_status( + f"{display_name} copied to clipboard") def go_back(self): if self.previous_page: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.previous_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.previous_page)) + class Settings(Page): def __init__(self, page_stack, main_window, parent=None): @@ -5358,7 +5736,7 @@ class Settings(Page): def setup_ui(self): main_container = QWidget(self) main_container.setGeometry(0, 0, 800, 520) - + self.layout = QHBoxLayout(main_container) self.layout.setContentsMargins(0, 60, 0, 0) @@ -5390,8 +5768,6 @@ class Settings(Page): ("Debug Help", self.show_debug_page) ] - - self.menu_buttons = [] for text, callback in menu_items: btn = QPushButton(text) @@ -5399,7 +5775,7 @@ class Settings(Page): btn.setCursor(Qt.CursorShape.PointingHandCursor) btn.setCheckable(True) btn.clicked.connect(callback) - + btn.setStyleSheet(f""" QPushButton {{ text-align: left; @@ -5419,10 +5795,10 @@ class Settings(Page): background: rgba(255, 255, 255, 0.05); }} """) - + self.left_layout.addWidget(btn) self.menu_buttons.append(btn) - + self.left_layout.addStretch() def create_delete_page(self): @@ -5432,14 +5808,17 @@ class Settings(Page): layout.setSpacing(15) title = QLabel("DELETE PROFILE") - title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") layout.addWidget(title) self.delete_scroll_area = QScrollArea() self.delete_scroll_area.setFixedSize(510, 300) self.delete_scroll_area.setWidgetResizable(True) - self.delete_scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) - self.delete_scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.delete_scroll_area.setHorizontalScrollBarPolicy( + Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.delete_scroll_area.setVerticalScrollBarPolicy( + Qt.ScrollBarPolicy.ScrollBarAsNeeded) self.delete_scroll_area.setStyleSheet(""" QScrollArea { background-color: transparent; @@ -5463,18 +5842,19 @@ class Settings(Page): height: 0px; } """) - + self.delete_scroll_widget = QWidget() - self.delete_scroll_widget.setStyleSheet("background-color: transparent;") + self.delete_scroll_widget.setStyleSheet( + "background-color: transparent;") self.delete_scroll_area.setWidget(self.delete_scroll_widget) - + self.profile_buttons = QButtonGroup() self.profile_buttons.setExclusive(True) - + self.create_delete_profile_buttons() - + layout.addWidget(self.delete_scroll_area) - + self.delete_button = QPushButton("Delete") self.delete_button.setEnabled(False) self.delete_button.setFixedSize(120, 40) @@ -5496,24 +5876,24 @@ class Settings(Page): """) self.delete_button.clicked.connect(self.delete_selected_profile) self.profile_buttons.buttonClicked.connect(self.on_profile_selected) - + button_layout = QHBoxLayout() button_layout.addStretch() button_layout.addWidget(self.delete_button) button_layout.addStretch() - + layout.addStretch() layout.addLayout(button_layout) - + return page def create_delete_profile_buttons(self): profiles = ProfileController.get_all() - + for index, (profile_id, profile) in enumerate(profiles.items()): row = index // 2 col = index % 2 - + btn = QPushButton(f"Profile {profile_id}\n{profile.name}") btn.setCheckable(True) btn.setFixedSize(180, 60) @@ -5537,7 +5917,7 @@ class Settings(Page): }} """) self.profile_buttons.addButton(btn, profile_id) - + if profiles: rows = (len(profiles) + 1) // 2 height = rows * 100 @@ -5550,7 +5930,8 @@ class Settings(Page): layout.setSpacing(15) title = QLabel("DEBUG HELP") - title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") layout.addWidget(title) scroll_area = QScrollArea() @@ -5590,12 +5971,14 @@ class Settings(Page): profile_selection_layout = QVBoxLayout(profile_selection_group) profile_label = QLabel("Select System-wide Profile:") - profile_label.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}") + profile_label.setStyleSheet( + f"color: white; font-size: 12px; {self.font_style}") profile_selection_layout.addWidget(profile_label) self.debug_profile_selector = QComboBox() self.debug_profile_selector.setStyleSheet(self.get_combobox_style()) - self.debug_profile_selector.currentTextChanged.connect(self.on_debug_profile_selected) + self.debug_profile_selector.currentTextChanged.connect( + self.on_debug_profile_selected) profile_selection_layout.addWidget(self.debug_profile_selector) scroll_layout.addWidget(profile_selection_group) @@ -5621,13 +6004,14 @@ class Settings(Page): ping_layout = QVBoxLayout(ping_group) self.ping_instruction_label = QLabel("") - self.ping_instruction_label.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}") + self.ping_instruction_label.setStyleSheet( + f"color: white; font-size: 12px; {self.font_style}") self.ping_instruction_label.setWordWrap(True) self.ping_instruction_label.hide() ping_layout.addWidget(self.ping_instruction_label) ping_buttons_layout = QHBoxLayout() - + self.copy_ping_button = QPushButton("Copy Ping Command") self.copy_ping_button.setFixedSize(140, 40) self.copy_ping_button.setStyleSheet(f""" @@ -5677,14 +6061,14 @@ class Settings(Page): ping_layout.addLayout(ping_buttons_layout) self.ping_result_label = QLabel("") - self.ping_result_label.setStyleSheet(f"color: white; font-size: 12px; font-weight: bold; {self.font_style}") + self.ping_result_label.setStyleSheet( + f"color: white; font-size: 12px; font-weight: bold; {self.font_style}") self.ping_result_label.setWordWrap(True) self.ping_result_label.hide() ping_layout.addWidget(self.ping_result_label) scroll_layout.addWidget(ping_group) - command_group = QGroupBox("CLI Commands") command_group.setStyleSheet(f""" QGroupBox {{ @@ -5721,11 +6105,8 @@ class Settings(Page): """) command_layout.addWidget(self.cli_command) - - - cli_buttons_layout = QHBoxLayout() - + cli_copy_button = QPushButton("Copy CLI Command") cli_copy_button.setFixedSize(140, 40) cli_copy_button.setStyleSheet(f""" @@ -5749,14 +6130,10 @@ class Settings(Page): cli_copy_button.setEnabled(False) cli_buttons_layout.addWidget(cli_copy_button) - - command_layout.addLayout(cli_buttons_layout) find_buttons_layout = QHBoxLayout() - - - + command_layout.addLayout(find_buttons_layout) scroll_layout.addWidget(command_group) @@ -5784,13 +6161,15 @@ class Settings(Page): wg_quick_layout = QVBoxLayout(wg_quick_group) wg_quick_subtitle = QLabel("This uses your Linux system's Wireguard") - wg_quick_subtitle.setStyleSheet(f"font-size: 10px; color: #CCCCCC; {self.font_style}") + wg_quick_subtitle.setStyleSheet( + f"font-size: 10px; color: #CCCCCC; {self.font_style}") wg_quick_subtitle.setWordWrap(True) wg_quick_layout.addWidget(wg_quick_subtitle) self.wg_quick_up_command = QLineEdit() self.wg_quick_up_command.setReadOnly(True) - self.wg_quick_up_command.setText("Select a profile above to see commands") + self.wg_quick_up_command.setText( + "Select a profile above to see commands") self.wg_quick_up_command.setStyleSheet(f""" QLineEdit {{ color: black; @@ -5826,7 +6205,8 @@ class Settings(Page): self.wg_quick_down_command = QLineEdit() self.wg_quick_down_command.setReadOnly(True) - self.wg_quick_down_command.setText("Select a profile above to see commands") + self.wg_quick_down_command.setText( + "Select a profile above to see commands") self.wg_quick_down_command.setStyleSheet(f""" QLineEdit {{ color: black; @@ -5862,19 +6242,17 @@ class Settings(Page): self.wg_quick_up_button = copy_wg_up_button self.wg_quick_down_button = copy_wg_down_button - self.wg_quick_up_command_widget = self.wg_quick_up_command self.wg_quick_down_command_widget = self.wg_quick_down_command scroll_layout.addWidget(wg_quick_group) - self.update_debug_profile_list() scroll_area.setWidget(scroll_content) layout.addWidget(scroll_area) - + return page def copy_cli_command(self): @@ -5888,7 +6266,8 @@ class Settings(Page): subprocess.Popen(command) self.update_status.update_status("CLI command executed") except Exception as e: - self.update_status.update_status(f"Error executing command: {str(e)}") + self.update_status.update_status( + f"Error executing command: {str(e)}") def copy_find_command(self, command_text): clipboard = QApplication.clipboard() @@ -5901,18 +6280,22 @@ class Settings(Page): subprocess.Popen(command) self.update_status.update_status("Find command executed") except Exception as e: - self.update_status.update_status(f"Error executing find command: {str(e)}") + self.update_status.update_status( + f"Error executing find command: {str(e)}") def update_debug_profile_list(self): self.debug_profile_selector.clear() profiles = ProfileController.get_all() - system_profiles = {pid: profile for pid, profile in profiles.items() if isinstance(profile, SystemProfile)} - + system_profiles = {pid: profile for pid, profile in profiles.items( + ) if isinstance(profile, SystemProfile)} + if system_profiles: for profile_id, profile in system_profiles.items(): - self.debug_profile_selector.addItem(f"Profile {profile_id}: {profile.name}", profile_id) + self.debug_profile_selector.addItem( + f"Profile {profile_id}: {profile.name}", profile_id) else: - self.debug_profile_selector.addItem("No system-wide profiles found", None) + self.debug_profile_selector.addItem( + "No system-wide profiles found", None) def on_debug_profile_selected(self, text): profile_id = self.debug_profile_selector.currentData() @@ -5924,45 +6307,50 @@ class Settings(Page): self.cli_command.setText("Select a profile above to see command") self.cli_copy_button.setEnabled(False) if hasattr(self, 'wg_quick_up_command_widget'): - self.wg_quick_up_command_widget.setText("Select a profile above to see commands") - self.wg_quick_down_command_widget.setText("Select a profile above to see commands") + self.wg_quick_up_command_widget.setText( + "Select a profile above to see commands") + self.wg_quick_down_command_widget.setText( + "Select a profile above to see commands") self.wg_quick_up_button.setEnabled(False) self.wg_quick_down_button.setEnabled(False) return profile = ProfileController.get(profile_id) - - if profile and isinstance(profile, SystemProfile): app_path = os.environ.get('APPIMAGE') or "/path/to/hydra-veil" - self.cli_command.setText(f"'{app_path}' --cli profile enable -i {profile_id}") + self.cli_command.setText( + f"'{app_path}' --cli profile enable -i {profile_id}") self.cli_copy_button.setEnabled(True) ip_address = self.extract_endpoint_ip(profile) if ip_address: - self.ping_instruction_label.setText(f"Step 1, Can you Ping it? Copy-paste the command below into your terminal. This VPN Node's IP address is {ip_address}") + self.ping_instruction_label.setText( + f"Step 1, Can you Ping it? Copy-paste the command below into your terminal. This VPN Node's IP address is {ip_address}") self.ping_instruction_label.show() self.copy_ping_button.setEnabled(True) self.test_ping_button.setEnabled(True) self.ping_result_label.hide() - - - + if hasattr(self, 'wg_quick_up_command_widget'): - self.wg_quick_up_command_widget.setText(f"sudo wg-quick up '/etc/hydra-veil/profiles/{profile_id}/wg.conf'") - self.wg_quick_down_command_widget.setText(f"sudo wg-quick down '/etc/hydra-veil/profiles/{profile_id}/wg.conf'") + self.wg_quick_up_command_widget.setText( + f"sudo wg-quick up '/etc/hydra-veil/profiles/{profile_id}/wg.conf'") + self.wg_quick_down_command_widget.setText( + f"sudo wg-quick down '/etc/hydra-veil/profiles/{profile_id}/wg.conf'") self.wg_quick_up_button.setEnabled(True) self.wg_quick_down_button.setEnabled(True) else: - self.ping_instruction_label.setText("Could not extract IP address from WireGuard configuration") + self.ping_instruction_label.setText( + "Could not extract IP address from WireGuard configuration") self.ping_instruction_label.show() self.copy_ping_button.setEnabled(False) self.test_ping_button.setEnabled(False) self.ping_result_label.hide() if hasattr(self, 'wg_quick_up_command_widget'): - self.wg_quick_up_command_widget.setText("Could not load profile configuration") - self.wg_quick_down_command_widget.setText("Could not load profile configuration") + self.wg_quick_up_command_widget.setText( + "Could not load profile configuration") + self.wg_quick_down_command_widget.setText( + "Could not load profile configuration") self.wg_quick_up_button.setEnabled(False) self.wg_quick_down_button.setEnabled(False) @@ -5972,10 +6360,10 @@ class Settings(Page): wg_conf_path = f'{profile_path}/wg.conf.bak' if not os.path.exists(wg_conf_path): return None - + with open(wg_conf_path, 'r') as f: content = f.read() - + for line in content.split('\n'): if line.strip().startswith('Endpoint = '): endpoint = line.strip().split(' = ')[1] @@ -5984,6 +6372,7 @@ class Settings(Page): return None except Exception: return None + def copy_ping_command(self): profile_id = self.debug_profile_selector.currentData() if profile_id is None: @@ -5996,7 +6385,8 @@ class Settings(Page): ping_command = f"ping {ip_address}" clipboard = QApplication.clipboard() clipboard.setText(ping_command) - self.update_status.update_status("Ping command copied to clipboard") + self.update_status.update_status( + "Ping command copied to clipboard") def test_ping_connection(self): profile_id = self.debug_profile_selector.currentData() @@ -6009,43 +6399,54 @@ class Settings(Page): if ip_address: self.test_ping_button.setEnabled(False) self.ping_result_label.setText("Testing ping...") - self.ping_result_label.setStyleSheet(f"color: #FFA500; font-size: 12px; font-weight: bold; {self.font_style}") + self.ping_result_label.setStyleSheet( + f"color: #FFA500; font-size: 12px; font-weight: bold; {self.font_style}") self.ping_result_label.show() - + def ping_test(): try: if sys.platform == "win32": - result = subprocess.run(['ping', '-n', '4', ip_address], - capture_output=True, text=True, timeout=10) + result = subprocess.run(['ping', '-n', '4', ip_address], + capture_output=True, text=True, timeout=10) else: - result = subprocess.run(['ping', '-c', '4', ip_address], - capture_output=True, text=True, timeout=10) + result = subprocess.run(['ping', '-c', '4', ip_address], + capture_output=True, text=True, timeout=10) if result.returncode == 0: - self.ping_result_label.setText("✅ Ping successful - Connection is working!") - self.ping_result_label.setStyleSheet(f"color: #4CAF50; font-size: 12px; font-weight: bold; {self.font_style}") + self.ping_result_label.setText( + "✅ Ping successful - Connection is working!") + self.ping_result_label.setStyleSheet( + f"color: #4CAF50; font-size: 12px; font-weight: bold; {self.font_style}") else: - self.ping_result_label.setText("❌ Ping failed - Connection issue detected") - self.ping_result_label.setStyleSheet(f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}") + self.ping_result_label.setText( + "❌ Ping failed - Connection issue detected") + self.ping_result_label.setStyleSheet( + f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}") except subprocess.TimeoutExpired: - self.ping_result_label.setText("❌ Ping timeout - Connection issue detected") - self.ping_result_label.setStyleSheet(f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}") + self.ping_result_label.setText( + "❌ Ping timeout - Connection issue detected") + self.ping_result_label.setStyleSheet( + f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}") except Exception as e: - self.ping_result_label.setText(f"❌ Ping error: {str(e)}") - self.ping_result_label.setStyleSheet(f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}") + self.ping_result_label.setText( + f"❌ Ping error: {str(e)}") + self.ping_result_label.setStyleSheet( + f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}") finally: self.test_ping_button.setEnabled(True) - + threading.Thread(target=ping_test, daemon=True).start() def copy_wg_quick_up_command(self): clipboard = QApplication.clipboard() clipboard.setText(self.wg_quick_up_command_widget.text()) - self.update_status.update_status("wg-quick UP command copied to clipboard") + self.update_status.update_status( + "wg-quick UP command copied to clipboard") def copy_wg_quick_down_command(self): clipboard = QApplication.clipboard() clipboard.setText(self.wg_quick_down_command_widget.text()) - self.update_status.update_status("wg-quick DOWN command copied to clipboard") + self.update_status.update_status( + "wg-quick DOWN command copied to clipboard") def on_profile_selected(self, button): self.delete_button.setEnabled(True) @@ -6066,10 +6467,10 @@ class Settings(Page): def handle_delete_confirmation(self, confirmed): if confirmed: self.update_status.update_status(f'Deleting profile...') - self.worker_thread = WorkerThread('DESTROY_PROFILE', profile_data={'id': self.selected_profile_id}) + self.worker_thread = WorkerThread('DESTROY_PROFILE', profile_data={ + 'id': self.selected_profile_id}) self.worker_thread.text_output.connect(self.delete_status_update) self.worker_thread.start() - def delete_status_update(self, message): self.update_status.update_status(message) @@ -6078,8 +6479,6 @@ class Settings(Page): self.content_layout.addWidget(self.delete_page) self.content_layout.setCurrentWidget(self.delete_page) - - def get_combobox_style(self) -> str: return f""" QComboBox {{ @@ -6150,10 +6549,9 @@ class Settings(Page): profiles = ProfileController.get_all() for profile_id, profile in profiles.items(): if profile.connection.code == 'wireguard': - - self.wireguard_profile_selector.addItem(f"Profile {profile_id}: {profile.name}", profile_id) - + self.wireguard_profile_selector.addItem( + f"Profile {profile_id}: {profile.name}", profile_id) def convert_duration(self, value: Union[str, int], to_hours: bool = True) -> Union[str, int]: if to_hours: @@ -6174,12 +6572,12 @@ class Settings(Page): days = hours // 24 return f"{days} {'day' if days == 1 else 'days'}" else: - raise ValueError(f"Hours value {hours} cannot be converted to days or weeks cleanly") - - + raise ValueError( + f"Hours value {hours} cannot be converted to days or weeks cleanly") def reverse(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def create_subscription_page(self): page = QWidget() @@ -6188,7 +6586,8 @@ class Settings(Page): layout.setContentsMargins(20, 20, 20, 20) title = QLabel("Subscription Info") - title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") layout.addWidget(title) profile_group = QGroupBox("Profile Selection") @@ -6215,7 +6614,8 @@ class Settings(Page): profiles = ProfileController.get_all() if profiles: for profile_id, profile in profiles.items(): - self.profile_selector.addItem(f"Profile {profile_id}: {profile.name}", profile_id) + self.profile_selector.addItem( + f"Profile {profile_id}: {profile.name}", profile_id) profile_layout.addWidget(self.profile_selector) layout.addWidget(profile_group) @@ -6251,10 +6651,10 @@ class Settings(Page): billing_layout = QVBoxLayout(billing_container) billing_layout.setContentsMargins(0, 0, 0, 0) billing_layout.setSpacing(5) - + stat_widget = self.create_stat_widget(label, "N/A") billing_layout.addWidget(stat_widget) - + copy_button = QPushButton("Copy") copy_button.setFixedSize(60, 30) copy_button.setStyleSheet(f""" @@ -6273,50 +6673,55 @@ class Settings(Page): """) copy_button.clicked.connect(lambda: self.copy_billing_code()) billing_layout.addWidget(copy_button) - + row, col = divmod(i, 2) subscription_layout.addWidget(billing_container, row, col) - + old_label = stat_widget.findChild(QLabel, "value_label") if old_label: old_label.setParent(None) old_label.deleteLater() - + value_label = ClickableValueLabel("N/A", stat_widget) value_label.setObjectName("value_label") - value_label.setStyleSheet(f"color: #00ffff; font-size: 12px; font-family: 'Retro Gaming', sans-serif;") + value_label.setStyleSheet( + f"color: #00ffff; font-size: 12px; font-family: 'Retro Gaming', sans-serif;") value_label.setAlignment(Qt.AlignmentFlag.AlignCenter) stat_widget.layout().insertWidget(0, value_label) - + self.subscription_info[key] = value_label else: stat_widget = self.create_stat_widget(label, "N/A") row, col = divmod(i, 2) subscription_layout.addWidget(stat_widget, row, col) - + old_label = stat_widget.findChild(QLabel, "value_label") if old_label: old_label.setParent(None) old_label.deleteLater() - + value_label = ClickableValueLabel("N/A", stat_widget) value_label.setObjectName("value_label") - value_label.setStyleSheet(f"color: #00ffff; font-size: 12px; font-family: 'Retro Gaming', sans-serif;") + value_label.setStyleSheet( + f"color: #00ffff; font-size: 12px; font-family: 'Retro Gaming', sans-serif;") value_label.setAlignment(Qt.AlignmentFlag.AlignCenter) stat_widget.layout().insertWidget(0, value_label) - + self.subscription_info[key] = value_label layout.addWidget(subscription_group) - - clipboard_hint = QLabel("💡 Click on the billing code or use the Copy button to copy it to clipboard") - clipboard_hint.setStyleSheet(f"color: #666666; font-size: 11px; font-style: italic; {self.font_style}") + + clipboard_hint = QLabel( + "💡 Click on the billing code or use the Copy button to copy it to clipboard") + clipboard_hint.setStyleSheet( + f"color: #666666; font-size: 11px; font-style: italic; {self.font_style}") clipboard_hint.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.addWidget(clipboard_hint) - + layout.addStretch() - self.profile_selector.currentIndexChanged.connect(self.update_subscription_info) + self.profile_selector.currentIndexChanged.connect( + self.update_subscription_info) if self.profile_selector.count() > 0: self.update_subscription_info(0) @@ -6329,30 +6734,35 @@ class Settings(Page): layout.setContentsMargins(20, 20, 20, 20) title = QLabel("Verification Information") - title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") layout.addWidget(title) profile_label = QLabel("Profile Selection:") - profile_label.setStyleSheet(f"color: white; font-size: 14px; {self.font_style}") + profile_label.setStyleSheet( + f"color: white; font-size: 14px; {self.font_style}") layout.addWidget(profile_label) self.verification_profile_selector = QComboBox() - self.verification_profile_selector.setStyleSheet(self.get_combobox_style()) + self.verification_profile_selector.setStyleSheet( + self.get_combobox_style()) profiles = ProfileController.get_all() if profiles: for profile_id, profile in profiles.items(): - self.verification_profile_selector.addItem(f"Profile {profile_id}: {profile.name}", profile_id) + self.verification_profile_selector.addItem( + f"Profile {profile_id}: {profile.name}", profile_id) layout.addWidget(self.verification_profile_selector) details_label = QLabel("Verification Details:") - details_label.setStyleSheet(f"color: white; font-size: 14px; margin-top: 20px; {self.font_style}") + details_label.setStyleSheet( + f"color: white; font-size: 14px; margin-top: 20px; {self.font_style}") layout.addWidget(details_label) verification_layout = QVBoxLayout() verification_layout.setSpacing(15) self.verification_info = {} self.verification_checkmarks = {} - self.verification_full_values = {} + self.verification_full_values = {} info_items = [ ("Operator Name", "operator_name"), ("Nostr Key", "nostr_public_key"), @@ -6367,7 +6777,8 @@ class Settings(Page): container_layout.setSpacing(10) label_widget = QLabel(label + ":") - label_widget.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}") + label_widget.setStyleSheet( + f"color: white; font-size: 12px; {self.font_style}") label_widget.setMinimumWidth(120) container_layout.addWidget(label_widget) @@ -6388,14 +6799,16 @@ class Settings(Page): container_layout.addWidget(value_widget, 1) checkmark_widget = QLabel("✓") - checkmark_widget.setStyleSheet(f"color: #4CAF50; font-size: 20px; font-weight: bold; {self.font_style}") + checkmark_widget.setStyleSheet( + f"color: #4CAF50; font-size: 20px; font-weight: bold; {self.font_style}") checkmark_widget.setFixedSize(20, 20) checkmark_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) - checkmark_widget.hide() + checkmark_widget.hide() container_layout.addWidget(checkmark_widget) copy_button = QPushButton() - copy_button.setIcon(QIcon(os.path.join(self.btn_path, "paste_button.png"))) + copy_button.setIcon( + QIcon(os.path.join(self.btn_path, "paste_button.png"))) copy_button.setIconSize(QSize(24, 24)) copy_button.setFixedSize(30, 30) copy_button.setStyleSheet(f""" @@ -6408,7 +6821,8 @@ class Settings(Page): border-radius: 4px; }} """) - copy_button.clicked.connect(lambda checked=False, k=key: self.copy_verification_value(k)) + copy_button.clicked.connect( + lambda checked=False, k=key: self.copy_verification_value(k)) container_layout.addWidget(copy_button) verification_layout.addWidget(container) @@ -6418,16 +6832,18 @@ class Settings(Page): layout.addLayout(verification_layout) layout.addStretch() - endpoint_verification_label = QLabel("Endpoint Verification:", page) endpoint_verification_label.setGeometry(20, 420, 150, 20) - endpoint_verification_label.setStyleSheet(f"color: white; font-size: 15px; {self.font_style}") + endpoint_verification_label.setStyleSheet( + f"color: white; font-size: 15px; {self.font_style}") endpoint_verification_label.show() self.endpoint_verification_checkbox = QCheckBox(page) self.endpoint_verification_checkbox.setGeometry(180, 415, 30, 30) - self.endpoint_verification_checkbox.setChecked(ConfigurationController.get_endpoint_verification_enabled()) - self.endpoint_verification_checkbox.setStyleSheet(self.get_checkbox_style()) + self.endpoint_verification_checkbox.setChecked( + ConfigurationController.get_endpoint_verification_enabled()) + self.endpoint_verification_checkbox.setStyleSheet( + self.get_checkbox_style()) self.endpoint_verification_checkbox.show() save_button = QPushButton(page) @@ -6437,8 +6853,10 @@ class Settings(Page): save_button.clicked.connect(self.save_verification_settings) save_button.show() - self.verification_profile_selector.currentIndexChanged.connect(self.update_verification_info) - self.verification_profile_selector.activated.connect(self.update_verification_info) + self.verification_profile_selector.currentIndexChanged.connect( + self.update_verification_info) + self.verification_profile_selector.activated.connect( + self.update_verification_info) if self.verification_profile_selector.count() > 0: self.update_verification_info(0) @@ -6450,7 +6868,7 @@ class Settings(Page): start_len = max_length // 2 - 2 end_len = max_length // 2 - 2 return text[:start_len] + "....." + text[-end_len:] - + def update_verification_info(self, index): if index < 0: return @@ -6481,18 +6899,21 @@ class Settings(Page): operator_name = operator.name or "N/A" self.verification_full_values["operator_name"] = operator_name self.verification_info["operator_name"].setText(operator_name) - + nostr_key = operator.nostr_public_key or "N/A" self.verification_full_values["nostr_public_key"] = nostr_key - self.verification_info["nostr_public_key"].setText(self.truncate_key(nostr_key) if nostr_key != "N/A" else nostr_key) - + self.verification_info["nostr_public_key"].setText( + self.truncate_key(nostr_key) if nostr_key != "N/A" else nostr_key) + hydraveil_key = operator.public_key or "N/A" self.verification_full_values["hydraveil_public_key"] = hydraveil_key - self.verification_info["hydraveil_public_key"].setText(self.truncate_key(hydraveil_key) if hydraveil_key != "N/A" else hydraveil_key) - + self.verification_info["hydraveil_public_key"].setText( + self.truncate_key(hydraveil_key) if hydraveil_key != "N/A" else hydraveil_key) + nostr_verification = operator.nostr_attestation_event_reference or "N/A" self.verification_full_values["nostr_attestation_event_reference"] = nostr_verification - self.verification_info["nostr_attestation_event_reference"].setText(self.truncate_key(nostr_verification) if nostr_verification != "N/A" else nostr_verification) + self.verification_info["nostr_attestation_event_reference"].setText(self.truncate_key( + nostr_verification) if nostr_verification != "N/A" else nostr_verification) else: self.verification_info["operator_name"].setText("N/A") self.verification_full_values["operator_name"] = "N/A" @@ -6500,9 +6921,10 @@ class Settings(Page): self.verification_full_values["nostr_public_key"] = "N/A" self.verification_info["hydraveil_public_key"].setText("N/A") self.verification_full_values["hydraveil_public_key"] = "N/A" - self.verification_info["nostr_attestation_event_reference"].setText("N/A") + self.verification_info["nostr_attestation_event_reference"].setText( + "N/A") self.verification_full_values["nostr_attestation_event_reference"] = "N/A" - + for key, widget in self.verification_info.items(): if key in self.verification_checkmarks: full_value = self.verification_full_values.get(key, "") @@ -6513,11 +6935,14 @@ class Settings(Page): def save_verification_settings(self): try: - ConfigurationController.set_endpoint_verification_enabled(self.endpoint_verification_checkbox.isChecked()) - self.update_status.update_status("Verification settings saved successfully") + ConfigurationController.set_endpoint_verification_enabled( + self.endpoint_verification_checkbox.isChecked()) + self.update_status.update_status( + "Verification settings saved successfully") except Exception as e: logging.error(f"Error saving verification settings: {str(e)}") - self.update_status.update_status("Error saving verification settings") + self.update_status.update_status( + "Error saving verification settings") def copy_verification_value(self, key): """Copy the full verification value (not truncated) to clipboard.""" @@ -6531,8 +6956,10 @@ class Settings(Page): "hydraveil_public_key": "HydraVeil Key", "nostr_attestation_event_reference": "Nostr Verification" } - display_name = verification_display_names.get(key, "Verification value") - self.update_status.update_status(f"{display_name} copied to clipboard") + display_name = verification_display_names.get( + key, "Verification value") + self.update_status.update_status( + f"{display_name} copied to clipboard") def update_subscription_info(self, index): if index < 0: @@ -6543,16 +6970,19 @@ class Settings(Page): return profile = ProfileController.get(profile_id) - + if profile and hasattr(profile, 'subscription') and profile.subscription: try: - self.subscription_info["billing_code"].setText(str(profile.subscription.billing_code)) - + self.subscription_info["billing_code"].setText( + str(profile.subscription.billing_code)) + if hasattr(profile.subscription, 'expires_at') and profile.subscription.expires_at: - expires_at = profile.subscription.expires_at.strftime("%Y-%m-%d %H:%M:%S UTC") + expires_at = profile.subscription.expires_at.strftime( + "%Y-%m-%d %H:%M:%S UTC") self.subscription_info["expires_at"].setText(expires_at) else: - self.subscription_info["expires_at"].setText("Not available") + self.subscription_info["expires_at"].setText( + "Not available") except Exception as e: print(f"Error updating subscription info: {e}") else: @@ -6565,20 +6995,21 @@ class Settings(Page): if billing_code and billing_code != "N/A": clipboard = QApplication.clipboard() clipboard.setText(billing_code) - self.update_status.update_status("Billing code copied to clipboard") + self.update_status.update_status( + "Billing code copied to clipboard") else: - self.update_status.update_status("No billing code available to copy") + self.update_status.update_status( + "No billing code available to copy") def showEvent(self, event): super().showEvent(event) - + current_index = self.content_layout.currentIndex() - + self.content_layout.removeWidget(self.account_page) self.account_page = self.create_account_page() self.content_layout.addWidget(self.account_page) - self.content_layout.removeWidget(self.subscription_page) self.subscription_page = self.create_subscription_page() self.content_layout.addWidget(self.subscription_page) @@ -6612,10 +7043,11 @@ class Settings(Page): self.content_layout.addWidget(self.debug_page) self.content_layout.setCurrentIndex(current_index) - + if self.content_layout.currentWidget() == self.subscription_page: if self.profile_selector.count() > 0: self.update_subscription_info(0) + def create_account_page(self): page = QWidget() layout = QVBoxLayout(page) @@ -6623,7 +7055,8 @@ class Settings(Page): layout.setContentsMargins(20, 20, 20, 20) title = QLabel("Account Overview") - title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") layout.addWidget(title) scroll_area = QScrollArea() @@ -6680,10 +7113,12 @@ class Settings(Page): profiles = ProfileController.get_all() total_profiles = len(profiles) - session_profiles = sum(1 for p in profiles.values() if isinstance(p, SessionProfile)) - system_profiles = sum(1 for p in profiles.values() if isinstance(p, SystemProfile)) + session_profiles = sum(1 for p in profiles.values() + if isinstance(p, SessionProfile)) + system_profiles = sum(1 for p in profiles.values() + if isinstance(p, SystemProfile)) active_profiles = sum( - 1 for p in profiles.values() + 1 for p in profiles.values() if p.subscription and p.subscription.expires_at and p.subscription.expires_at > datetime.now(timezone.utc) ) @@ -6701,9 +7136,6 @@ class Settings(Page): return widget - - - def create_system_stats(self): widget = QWidget() layout = QGridLayout(widget) @@ -6711,7 +7143,7 @@ class Settings(Page): config_path = Constants.HV_CONFIG_HOME - current_connection = self.update_status.get_current_connection(); + current_connection = self.update_status.get_current_connection() if current_connection is not None: current_connection = current_connection.capitalize() @@ -6724,7 +7156,8 @@ class Settings(Page): for i, (label, value) in enumerate(stats): info_widget = QLabel(f"{label}: {value}") - info_widget.setStyleSheet(f"font-size: 14px; color: white; padding: 5px; {self.font_style}") + info_widget.setStyleSheet( + f"font-size: 14px; color: white; padding: 5px; {self.font_style}") info_widget.setWordWrap(True) layout.addWidget(info_widget, i, 0) @@ -6743,12 +7176,14 @@ class Settings(Page): layout = QVBoxLayout(widget) value_label = QLabel(str(value)) - value_label.setObjectName("value_label") - value_label.setStyleSheet("font-family: 'Retro Gaming', sans-serif; color: #00ffff; font-size: 22px; font-weight: bold") + value_label.setObjectName("value_label") + value_label.setStyleSheet( + "font-family: 'Retro Gaming', sans-serif; color: #00ffff; font-size: 22px; font-weight: bold") value_label.setAlignment(Qt.AlignmentFlag.AlignCenter) desc_label = QLabel(label) - desc_label.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}") + desc_label.setStyleSheet( + f"color: white; font-size: 12px; {self.font_style}") desc_label.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.addWidget(value_label) @@ -6761,7 +7196,8 @@ class Settings(Page): layout.setContentsMargins(0, 5, 0, 5) text_label = QLabel(f"{label}") - text_label.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}") + text_label.setStyleSheet( + f"color: white; font-size: 12px; {self.font_style}") text_label.setFixedWidth(100) progress = QFrame() @@ -6775,7 +7211,8 @@ class Settings(Page): progress.setFixedSize(int(200 * (percentage / 100)), 20) value_label = QLabel(f"{value} ({percentage:.1f}%)") - value_label.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}") + value_label.setStyleSheet( + f"color: white; font-size: 12px; {self.font_style}") value_label.setAlignment(Qt.AlignmentFlag.AlignRight) progress_container = QFrame() @@ -6872,15 +7309,19 @@ class Settings(Page): layout.setContentsMargins(20, 20, 20, 20) title = QLabel("LOGGING SETTINGS") - title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") layout.addWidget(title) - log_text = QLabel(f"Enabling this feature means error logs will be stored on your local\nmachine at: '{Constants.HV_CACHE_HOME}/gui'.") - log_text.setStyleSheet(f"color: white; font-size: 14px; {self.font_style}") + log_text = QLabel( + f"Enabling this feature means error logs will be stored on your local\nmachine at: '{Constants.HV_CACHE_HOME}/gui'.") + log_text.setStyleSheet( + f"color: white; font-size: 14px; {self.font_style}") layout.addWidget(log_text) logs_group = QGroupBox("Log Configuration") - logs_group.setStyleSheet(f"QGroupBox {{ color: white; padding: 15px; {self.font_style} }}") + logs_group.setStyleSheet( + f"QGroupBox {{ color: white; padding: 15px; {self.font_style} }}") logs_layout = QVBoxLayout(logs_group) self.enable_gui_logging = QCheckBox("Enable GUI logging") @@ -6907,7 +7348,8 @@ class Settings(Page): try: config = self.update_status._load_gui_config() if config and "logging" in config: - self.enable_gui_logging.setChecked(config["logging"]["gui_logging_enabled"]) + self.enable_gui_logging.setChecked( + config["logging"]["gui_logging_enabled"]) except Exception as e: logging.error(f"Error loading logging settings: {str(e)}") self.enable_gui_logging.setChecked(True) @@ -6924,7 +7366,7 @@ class Settings(Page): } config["logging"]["gui_logging_enabled"] = self.enable_gui_logging.isChecked() - + self.update_status._save_gui_config(config) if self.enable_gui_logging.isChecked(): @@ -6932,9 +7374,9 @@ class Settings(Page): else: self.update_status.stop_gui_logging() + self.update_status.update_status( + "Logging settings saved successfully") - self.update_status.update_status("Logging settings saved successfully") - except Exception as e: logging.error(f"Error saving logging settings: {str(e)}") self.update_status.update_status("Error saving logging settings") @@ -6946,18 +7388,21 @@ class Settings(Page): layout.setContentsMargins(20, 20, 20, 20) title = QLabel("Create/Edit SETTINGS") - title.setStyleSheet(f"color: #808080; font-size: 15px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 15px; font-weight: bold; {self.font_style}") layout.addWidget(title) registrations_group = QGroupBox("Create/Edit Configuration") - registrations_group.setStyleSheet(f"QGroupBox {{ color: white; font-size: 15px; padding: 15px; {self.font_style} }}") + registrations_group.setStyleSheet( + f"QGroupBox {{ color: white; font-size: 15px; padding: 15px; {self.font_style} }}") registrations_layout = QVBoxLayout(registrations_group) self.enable_auto_sync = QCheckBox("Enable auto-sync on Edit") self.enable_auto_sync.setStyleSheet(self.get_checkbox_style()) registrations_layout.addWidget(self.enable_auto_sync) - self.enable_fast_registration = QCheckBox("Enable Fast-mode for Profile Creation") + self.enable_fast_registration = QCheckBox( + "Enable Fast-mode for Profile Creation") self.enable_fast_registration.setStyleSheet(self.get_checkbox_style()) registrations_layout.addWidget(self.enable_fast_registration) @@ -6985,26 +7430,32 @@ class Settings(Page): layout.setContentsMargins(20, 20, 20, 20) title = QLabel("SYSTEM-WIDE PROFILES") - title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") layout.addWidget(title) - description = QLabel("Control whether HydraVeil configures a sudo policy so system-wide WireGuard profiles can be started without entering your sudo password.") + description = QLabel( + "Control whether HydraVeil configures a sudo policy so system-wide WireGuard profiles can be started without entering your sudo password.") description.setWordWrap(True) - description.setStyleSheet(f"color: white; font-size: 14px; {self.font_style}") + description.setStyleSheet( + f"color: white; font-size: 14px; {self.font_style}") layout.addWidget(description) status_layout = QHBoxLayout() status_label = QLabel("Current status:") - status_label.setStyleSheet(f"color: white; font-size: 14px; {self.font_style}") + status_label.setStyleSheet( + f"color: white; font-size: 14px; {self.font_style}") self.systemwide_status_value = QLabel("") - self.systemwide_status_value.setStyleSheet(f"color: #e67e22; font-size: 14px; {self.font_style}") + self.systemwide_status_value.setStyleSheet( + f"color: #e67e22; font-size: 14px; {self.font_style}") status_layout.addWidget(status_label) status_layout.addWidget(self.systemwide_status_value) status_layout.addStretch() layout.addLayout(status_layout) toggle_layout = QHBoxLayout() - self.systemwide_toggle = QCheckBox("Enable \"No Sudo\" Systemwide Policy") + self.systemwide_toggle = QCheckBox( + "Enable \"No Sudo\" Systemwide Policy") self.systemwide_toggle.setStyleSheet(self.get_checkbox_style()) toggle_layout.addWidget(self.systemwide_toggle) toggle_layout.addStretch() @@ -7032,19 +7483,24 @@ class Settings(Page): layout.setContentsMargins(20, 20, 20, 20) title = QLabel("BWRAP PERMISSION") - title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + title.setStyleSheet( + f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") layout.addWidget(title) - description = QLabel("Control whether HydraVeil configures a capability policy so bwrap can be used without requiring additional permissions.") + description = QLabel( + "Control whether HydraVeil configures a capability policy so bwrap can be used without requiring additional permissions.") description.setWordWrap(True) - description.setStyleSheet(f"color: white; font-size: 14px; {self.font_style}") + description.setStyleSheet( + f"color: white; font-size: 14px; {self.font_style}") layout.addWidget(description) status_layout = QHBoxLayout() status_label = QLabel("Current status:") - status_label.setStyleSheet(f"color: white; font-size: 14px; {self.font_style}") + status_label.setStyleSheet( + f"color: white; font-size: 14px; {self.font_style}") self.bwrap_status_value = QLabel("") - self.bwrap_status_value.setStyleSheet(f"color: #e67e22; font-size: 14px; {self.font_style}") + self.bwrap_status_value.setStyleSheet( + f"color: #e67e22; font-size: 14px; {self.font_style}") status_layout.addWidget(status_label) status_layout.addWidget(self.bwrap_status_value) status_layout.addStretch() @@ -7083,10 +7539,12 @@ class Settings(Page): self.systemwide_toggle.setChecked(enabled) if enabled: self.systemwide_status_value.setText("Enabled") - self.systemwide_status_value.setStyleSheet(f"color: #2ecc71; font-size: 14px; {self.font_style}") + self.systemwide_status_value.setStyleSheet( + f"color: #2ecc71; font-size: 14px; {self.font_style}") else: self.systemwide_status_value.setText("Disabled") - self.systemwide_status_value.setStyleSheet(f"color: #e67e22; font-size: 14px; {self.font_style}") + self.systemwide_status_value.setStyleSheet( + f"color: #e67e22; font-size: 14px; {self.font_style}") def save_systemwide_settings(self): enable = self.systemwide_toggle.isChecked() @@ -7099,16 +7557,20 @@ class Settings(Page): if PolicyController.is_instated(privilege_policy): PolicyController.revoke(privilege_policy) self.load_systemwide_settings() - self.update_status.update_status("System-wide policy settings updated") + self.update_status.update_status( + "System-wide policy settings updated") except CommandNotFoundError as e: self.systemwide_status_value.setText(str(e)) - self.systemwide_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + self.systemwide_status_value.setStyleSheet( + f"color: red; font-size: 14px; {self.font_style}") except (PolicyAssignmentError, PolicyInstatementError, PolicyRevocationError) as e: self.systemwide_status_value.setText(str(e)) - self.systemwide_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + self.systemwide_status_value.setStyleSheet( + f"color: red; font-size: 14px; {self.font_style}") except Exception: self.systemwide_status_value.setText("Failed to update policy") - self.systemwide_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + self.systemwide_status_value.setStyleSheet( + f"color: red; font-size: 14px; {self.font_style}") def load_bwrap_settings(self): enabled = False @@ -7121,10 +7583,12 @@ class Settings(Page): self.bwrap_toggle.setChecked(enabled) if enabled: self.bwrap_status_value.setText("Enabled") - self.bwrap_status_value.setStyleSheet(f"color: #2ecc71; font-size: 14px; {self.font_style}") + self.bwrap_status_value.setStyleSheet( + f"color: #2ecc71; font-size: 14px; {self.font_style}") else: self.bwrap_status_value.setText("Disabled") - self.bwrap_status_value.setStyleSheet(f"color: #e67e22; font-size: 14px; {self.font_style}") + self.bwrap_status_value.setStyleSheet( + f"color: #e67e22; font-size: 14px; {self.font_style}") def save_bwrap_settings(self): enable = self.bwrap_toggle.isChecked() @@ -7137,16 +7601,20 @@ class Settings(Page): if PolicyController.is_instated(capability_policy): PolicyController.revoke(capability_policy) self.load_bwrap_settings() - self.update_status.update_status("Capability policy settings updated") + self.update_status.update_status( + "Capability policy settings updated") except CommandNotFoundError as e: self.bwrap_status_value.setText(str(e)) - self.bwrap_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + self.bwrap_status_value.setStyleSheet( + f"color: red; font-size: 14px; {self.font_style}") except (PolicyAssignmentError, PolicyInstatementError, PolicyRevocationError) as e: self.bwrap_status_value.setText(str(e)) - self.bwrap_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + self.bwrap_status_value.setStyleSheet( + f"color: red; font-size: 14px; {self.font_style}") except Exception: self.bwrap_status_value.setText("Failed to update policy") - self.bwrap_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + self.bwrap_status_value.setStyleSheet( + f"color: red; font-size: 14px; {self.font_style}") def load_registrations_settings(self) -> None: try: @@ -7154,7 +7622,8 @@ class Settings(Page): if config and "registrations" in config: registrations = config["registrations"] auto_sync = registrations.get("auto_sync_enabled", False) - fast_reg = registrations.get("fast_registration_enabled", False) + fast_reg = registrations.get( + "fast_registration_enabled", False) if "auto_sync_enabled" not in registrations or "fast_registration_enabled" not in registrations: registrations["auto_sync_enabled"] = auto_sync registrations["fast_registration_enabled"] = fast_reg @@ -7189,13 +7658,14 @@ class Settings(Page): config["registrations"]["auto_sync_enabled"] = self.enable_auto_sync.isChecked() config["registrations"]["fast_registration_enabled"] = self.enable_fast_registration.isChecked() - + self.update_status._save_gui_config(config) self.update_status.update_status("Registration settings saved") - + except Exception as e: logging.error(f"Error saving registration settings: {str(e)}") - self.update_status.update_status("Error saving registration settings") + self.update_status.update_status( + "Error saving registration settings") def is_auto_sync_enabled(self) -> bool: try: @@ -7216,12 +7686,10 @@ class Settings(Page): return registrations.get("fast_registration_enabled", False) return False except Exception as e: - logging.error(f"Error checking fast registration setting: {str(e)}") + logging.error( + f"Error checking fast registration setting: {str(e)}") return False - - - class IdPage(Page): def __init__(self, page_stack, main_window=None, parent=None): @@ -7233,7 +7701,6 @@ class IdPage(Page): # self.display.setPixmap(QPixmap(os.path.join(self.btn_path, "wireguardx.png")).scaled(self.display.size(), Qt.AspectRatioMode.KeepAspectRatio)) self.create_interface_elements() - self.connect_button = QPushButton(self) self.connect_button.setObjectName("connect_button") self.connect_button.setGeometry(625, 450, 90, 50) @@ -7245,33 +7712,29 @@ class IdPage(Page): self.button_reverse.setVisible(True) - def on_connect(self): text = self.text_edit.toPlainText() import re - pattern = r'^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$' + pattern = r'^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$' if re.match(pattern, text): self.update_status.update_status('Enabling profile in progress...') profile_data = { - 'id' : int(self.update_status.current_profile_id), + 'id': int(self.update_status.current_profile_id), 'billing_code': str(text) } menu_page = self.find_menu_page() if menu_page: menu_page.enabling_profile(profile_data) - + else: self.update_text_output('Incorrect format for the billing code') - - def find_menu_page(self): for i in range(self.page_stack.count()): page = self.page_stack.widget(i) if isinstance(page, MenuPage): return page return None - def create_interface_elements(self): self.object_selected = None @@ -7279,18 +7742,18 @@ class IdPage(Page): self.title = QLabel("Entry Id", self) self.title.setGeometry(QtCore.QRect(560, 50, 220, 40)) self.title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.button_reverse.clicked.connect(self.reverse) self.button_go.clicked.connect(self.go_selected) objects_info = [ - (QPushButton, os.path.join(self.btn_path, "new_id.png"), self.show_next, DurationSelectionPage, (575, 100, 185, 75)), - (QLabel, os.path.join(self.btn_path, "button230x220.png"), None, None, (550, 220, 250, 220)), - (QTextEdit, None, self.validate_password, DurationSelectionPage, (550, 230, 230, 190)) -] - - + (QPushButton, os.path.join(self.btn_path, "new_id.png"), + self.show_next, DurationSelectionPage, (575, 100, 185, 75)), + (QLabel, os.path.join(self.btn_path, "button230x220.png"), + None, None, (550, 220, 250, 220)), + (QTextEdit, None, self.validate_password, + DurationSelectionPage, (550, 230, 230, 190)) + ] for obj_type, icon_name, function, page_class, geometry in objects_info: obj = obj_type(self) @@ -7298,35 +7761,36 @@ class IdPage(Page): if isinstance(obj, QPushButton): obj.setIconSize(QtCore.QSize(190, 120)) obj.setIcon(QtGui.QIcon(icon_name)) - obj.clicked.connect(lambda _, func=function, page=page_class: self.show_object_selected(func, page)) + obj.clicked.connect( + lambda _, func=function, page=page_class: self.show_object_selected(func, page)) elif isinstance(obj, QLabel): - obj.setPixmap(QPixmap(icon_name).scaled(obj.size(), Qt.AspectRatioMode.KeepAspectRatio)) + obj.setPixmap(QPixmap(icon_name).scaled( + obj.size(), Qt.AspectRatioMode.KeepAspectRatio)) elif isinstance(obj, QTextEdit): - obj.setPlaceholderText("Or use an existing billing Id, enter it here") + obj.setPlaceholderText( + "Or use an existing billing Id, enter it here") obj.textChanged.connect(self.toggle_button_state) self.text_edit = obj def toggle_button_state(self): text = self.text_edit.toPlainText() - if text.strip(): + if text.strip(): self.connect_button.setEnabled(True) - else: + else: self.connect_button.setEnabled(False) - - def show_next(self): self.text_edit.clear() - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(DurationSelectionPage))) - + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(DurationSelectionPage))) def validate_password(self): self.button_go.setVisible(False) text = self.text_edit.toPlainText().strip().lower() - + # Comparar el texto con la palabra "zenaku" ignorando mayúsculas y minúsculas if text == "zenaku": self.button_go.setVisible(True) @@ -7337,28 +7801,32 @@ class IdPage(Page): def go_selected(self): if self.object_selected: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(self.object_selected))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(self.object_selected))) self.display.clear() for boton in self.buttons: boton.setChecked(False) - + self.button_go.setVisible(False) def reverse(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) class ConfettiParticle: def __init__(self, x, y): self.x = x self.y = y - self.color = QColor(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) + self.color = QColor(random.randint(0, 255), random.randint( + 0, 255), random.randint(0, 255)) self.size = random.randint(5, 15) self.speed = random.uniform(1, 3) def update(self): self.y += self.speed + class ConfettiThread(QThread): update_signal = pyqtSignal(list) @@ -7368,7 +7836,8 @@ class ConfettiThread(QThread): self.height = height self.running = True self.mutex = QMutex() - self.confetti = [ConfettiParticle(random.randint(0, width), random.randint(-height, 0)) for _ in range(100)] + self.confetti = [ConfettiParticle(random.randint( + 0, width), random.randint(-height, 0)) for _ in range(100)] def run(self): while self.running: @@ -7378,9 +7847,9 @@ class ConfettiThread(QThread): if particle.y > self.height: particle.y = random.randint(-100, 0) particle.x = random.randint(0, self.width) - + self.update_signal.emit(self.confetti.copy()) - self.msleep(16) + self.msleep(16) def stop(self): self.running = False @@ -7390,13 +7859,14 @@ class ConfettiThread(QThread): self.width = width self.height = height + class ClickableLabel(QLabel): clicked = pyqtSignal() def __init__(self, text, parent=None, **kwargs): super().__init__(text, parent, **kwargs) self.setCursor(Qt.CursorShape.PointingHandCursor) - self.hover_width = self.width() + self.hover_width = self.width() self.is_hovered = False def mousePressEvent(self, event): @@ -7422,16 +7892,19 @@ class ClickableLabel(QLabel): if self.is_hovered: painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) - hover_color = QColor(255, 255, 255, 25) - + hover_color = QColor(255, 255, 255, 25) + center_x = self.width() // 2 start_x = center_x - (self.hover_width // 2) - painter.fillRect(start_x, 0, self.hover_width, self.height(), hover_color) + painter.fillRect(start_x, 0, self.hover_width, + self.height(), hover_color) painter.end() + + class PaymentConfirmed(Page): def __init__(self, page_stack, main_window=None, parent=None): super().__init__("Id", page_stack, main_window, parent) - + self.update_status = main_window self.buttonGroup = QButtonGroup(self) self.display.setGeometry(QRect(-10, 50, 550, 460)) @@ -7440,20 +7913,24 @@ class PaymentConfirmed(Page): self.button_reverse.setVisible(False) self.confetti = [] - + self.icon_label = QLabel(self) icon = QIcon(os.path.join(self.btn_path, "check_icon.png")) pixmap = icon.pixmap(QSize(64, 64)) self.icon_label.setPixmap(pixmap) self.icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - - self.label = QLabel("Payment Completed!", alignment=Qt.AlignmentFlag.AlignCenter, parent=self) - self.label.setStyleSheet("font-size: 24px; color: #2ecc71; font-weight: bold;") - - self.billing_label = QLabel("Your billing code:", alignment=Qt.AlignmentFlag.AlignCenter, parent=self) + + self.label = QLabel("Payment Completed!", + alignment=Qt.AlignmentFlag.AlignCenter, parent=self) + self.label.setStyleSheet( + "font-size: 24px; color: #2ecc71; font-weight: bold;") + + self.billing_label = QLabel( + "Your billing code:", alignment=Qt.AlignmentFlag.AlignCenter, parent=self) self.billing_label.setStyleSheet("font-size: 18px; color: white;") - - self.billing_code = ClickableLabel("", alignment=Qt.AlignmentFlag.AlignCenter, parent=self) + + self.billing_code = ClickableLabel( + "", alignment=Qt.AlignmentFlag.AlignCenter, parent=self) self.billing_code.setStyleSheet(""" font-size: 24px; color: white; @@ -7463,15 +7940,15 @@ class PaymentConfirmed(Page): """) self.billing_code.clicked.connect(self.copy_billing_code) self.billing_code.set_hover_width(450) - + self.top_line = QFrame(self) self.top_line.setFrameShape(QFrame.Shape.HLine) self.top_line.setStyleSheet("color: #bdc3c7;") - + self.bottom_line = QFrame(self) self.bottom_line.setFrameShape(QFrame.Shape.HLine) self.bottom_line.setStyleSheet("color: #bdc3c7;") - + self.next_button = QPushButton("Next", self) self.next_button.setStyleSheet(""" QPushButton { @@ -7487,12 +7964,11 @@ class PaymentConfirmed(Page): } """) self.next_button.clicked.connect(self.on_next_button) - + self.confetti_thread = ConfettiThread(self.width(), self.height()) self.confetti_thread.update_signal.connect(self.update_confetti) self.confetti_thread.start() - def copy_billing_code(self): clipboard = QApplication.clipboard() clipboard.setText(self.billing_code.text()) @@ -7500,15 +7976,16 @@ class PaymentConfirmed(Page): original_style = self.billing_code.styleSheet() self.billing_code.setText("Copied!") - self.billing_code.setStyleSheet(original_style + "background-color: #27ae60;") + self.billing_code.setStyleSheet( + original_style + "background-color: #27ae60;") - QTimer.singleShot(1000, lambda: self.reset_billing_code_style(original_style)) + QTimer.singleShot( + 1000, lambda: self.reset_billing_code_style(original_style)) def reset_billing_code_style(self, original_style): self.billing_code.setStyleSheet(original_style) self.billing_code.setText(self.current_billing_code) - def set_billing_code(self, code): self.current_billing_code = code self.billing_code.setText(code) @@ -7518,31 +7995,36 @@ class PaymentConfirmed(Page): self.update() def paintEvent(self, event): - super().paintEvent(event) - + super().paintEvent(event) + painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) - + for particle in self.confetti: painter.setBrush(particle.color) painter.setPen(Qt.PenStyle.NoPen) - painter.drawEllipse(QPointF(particle.x, particle.y), particle.size, particle.size) - + painter.drawEllipse(QPointF(particle.x, particle.y), + particle.size, particle.size) + painter.end() def resizeEvent(self, event): super().resizeEvent(event) width = event.size().width() height = event.size().height() - - self.icon_label.setGeometry(QRect(width // 2 - 32, height // 8, 64, 64)) + + self.icon_label.setGeometry( + QRect(width // 2 - 32, height // 8, 64, 64)) self.label.setGeometry(QRect(0, height // 4, width, 50)) self.billing_label.setGeometry(QRect(0, height // 2 - 50, width, 30)) - self.top_line.setGeometry(QRect(width // 4, height // 2 + 20 , width // 2, 1)) + self.top_line.setGeometry( + QRect(width // 4, height // 2 + 20, width // 2, 1)) self.billing_code.setGeometry(QRect(0, height // 2 + 28, width, 40)) - self.bottom_line.setGeometry(QRect(width // 4, height // 2 + 75, width // 2, 1)) - self.next_button.setGeometry(QRect(width // 4, height * 3 // 4, width // 2, 50)) - + self.bottom_line.setGeometry( + QRect(width // 4, height // 2 + 75, width // 2, 1)) + self.next_button.setGeometry( + QRect(width // 4, height * 3 // 4, width // 2, 50)) + self.confetti_thread.update_dimensions(width, height) def closeEvent(self, event): @@ -7551,7 +8033,8 @@ class PaymentConfirmed(Page): super().closeEvent(event) def on_next_button(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def find_menu_page(self): for i in range(self.page_stack.count()): @@ -7559,10 +8042,11 @@ class PaymentConfirmed(Page): if isinstance(page, MenuPage): return page return None - def reverse(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(WireGuardPage))) + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(WireGuardPage))) + class ConfirmationPopup(QWidget): finished = pyqtSignal(bool) @@ -7607,7 +8091,8 @@ class ConfirmationPopup(QWidget): """) close_button.setFixedSize(30, 30) close_button.clicked.connect(self.close) - content_layout.addWidget(close_button, alignment=Qt.AlignmentFlag.AlignRight) + content_layout.addWidget( + close_button, alignment=Qt.AlignmentFlag.AlignRight) scroll_area = QScrollArea() scroll_area.setWidgetResizable(True) @@ -7668,7 +8153,7 @@ class ConfirmationPopup(QWidget): def perform_action(self): self.finished.emit(True) self.close() - + def mousePressEvent(self, event): self.oldPos = event.globalPosition().toPoint() @@ -7677,6 +8162,7 @@ class ConfirmationPopup(QWidget): self.move(self.x() + delta.x(), self.y() + delta.y()) self.oldPos = event.globalPosition().toPoint() + class EndpointVerificationPopup(QWidget): finished = pyqtSignal(bool, str) @@ -7718,7 +8204,8 @@ class EndpointVerificationPopup(QWidget): """) close_button.setFixedSize(30, 30) close_button.clicked.connect(lambda: self.close_with_action("abort")) - content_layout.addWidget(close_button, alignment=Qt.AlignmentFlag.AlignRight) + content_layout.addWidget( + close_button, alignment=Qt.AlignmentFlag.AlignRight) scroll_area = QScrollArea() scroll_area.setWidgetResizable(True) @@ -7791,7 +8278,8 @@ class EndpointVerificationPopup(QWidget): background-color: #fb8c00; } """) - continue_button.clicked.connect(lambda: self.close_with_action("continue")) + continue_button.clicked.connect( + lambda: self.close_with_action("continue")) button_layout.addWidget(continue_button) def close_with_action(self, action): @@ -7801,7 +8289,7 @@ class EndpointVerificationPopup(QWidget): def closeEvent(self, event): self.finished.emit(False, "abort") event.accept() - + def mousePressEvent(self, event): self.oldPos = event.globalPosition().toPoint() @@ -7810,11 +8298,13 @@ class EndpointVerificationPopup(QWidget): self.move(self.x() + delta.x(), self.y() + delta.y()) self.oldPos = event.globalPosition().toPoint() + class ClickableValueLabel(QLabel): def __init__(self, text: str, parent=None): super().__init__(text, parent) self.setObjectName("value_label") - self.setStyleSheet("color: #00ffff; font-size: 13px; font-weight: bold;") + self.setStyleSheet( + "color: #00ffff; font-size: 13px; font-weight: bold;") self.setCursor(Qt.CursorShape.PointingHandCursor) self.timer = QTimer(self) self.timer.setSingleShot(True) @@ -7841,34 +8331,35 @@ class SyncScreen(Page): self.update_status = main_window self.connection_manager = main_window.connection_manager self.is_tor_mode = main_window.is_tor_mode - - - self.heading_label = QLabel("You're about to fetch data from\nSimplified Privacy.", self) + self.heading_label = QLabel( + "You're about to fetch data from\nSimplified Privacy.", self) self.heading_label.setGeometry(15, 80, 750, 120) font_style = "font-size: 34px; font-weight: bold; color: white;" if self.custom_window.open_sans_family: font_style += f" font-family: '{self.custom_window.open_sans_family}';" self.heading_label.setStyleSheet(font_style) - - self.data_description = QLabel("This data includes what plans, countries,\nbrowsers, and version upgrades are\navailable. As well as coordinating billing.", self) + + self.data_description = QLabel( + "This data includes what plans, countries,\nbrowsers, and version upgrades are\navailable. As well as coordinating billing.", self) self.data_description.setGeometry(22, 190, 750, 120) font_style = "font-size: 24px; font-weight: bold; color: #ffff00;" if self.custom_window.open_sans_family: font_style += f" font-family: '{self.custom_window.open_sans_family}';" self.data_description.setStyleSheet(font_style) - - self.instructions = QLabel("Use the toggle in the bottom right to\ndecide if you want to use Tor or not.\nThen hit \"Next\"", self) + + self.instructions = QLabel( + "Use the toggle in the bottom right to\ndecide if you want to use Tor or not.\nThen hit \"Next\"", self) self.instructions.setGeometry(22, 345, 750, 120) font_style = "font-size: 28px; font-weight: bold; color: white;" if self.custom_window.open_sans_family: font_style += f" font-family: '{self.custom_window.open_sans_family}';" self.instructions.setStyleSheet(font_style) - + self.arrow_label = QLabel(self) self.arrow_label.setGeometry(520, 400, 180, 130) arrow_pixmap = QPixmap(os.path.join(self.btn_path, "arrow-down.png")) - + self.arrow_label.setPixmap(arrow_pixmap) self.arrow_label.raise_() @@ -7878,8 +8369,9 @@ class SyncScreen(Page): self.button_back.clicked.connect(self.go_back) def go_back(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) - + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + def perform_sync(self): self.button_go.setEnabled(False) self.button_back.setEnabled(False) @@ -7888,19 +8380,21 @@ class SyncScreen(Page): self.worker_thread = WorkerThread('SYNC_TOR') else: self.worker_thread = WorkerThread('SYNC') - + self.worker_thread.sync_output.connect(self.update_output) self.worker_thread.start() - + def update_output(self, available_locations, available_browsers, status, is_tor, locations, all_browsers): if isinstance(all_browsers, bool) and not all_browsers: install_page = self.page_stack.findChild(InstallSystemPackage) - install_page.configure(package_name='tor', distro='debian', is_sync=True) - self.page_stack.setCurrentIndex(self.page_stack.indexOf(install_page)) + install_page.configure( + package_name='tor', distro='debian', is_sync=True) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(install_page)) self.button_go.setEnabled(True) self.button_back.setEnabled(True) return - + if status is False: self.button_go.setEnabled(True) self.button_back.setEnabled(True) @@ -7908,18 +8402,18 @@ class SyncScreen(Page): return self.update_status.update_status('Sync complete') - - + update_available = ClientController.can_be_updated() if update_available: menu_page = self.page_stack.findChild(MenuPage) menu_page.on_update_check_finished() - - self.update_after_sync(available_locations, available_browsers, locations, all_browsers) - - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ProtocolPage))) + self.update_after_sync(available_locations, + available_browsers, locations, all_browsers) + + self.page_stack.setCurrentIndex(self.page_stack.indexOf( + self.page_stack.findChild(ProtocolPage))) def update_after_sync(self, available_locations, available_browsers, locations, all_browsers=None): @@ -7930,16 +8424,20 @@ class SyncScreen(Page): self.connection_manager.store_locations(locations) self.connection_manager.store_browsers(available_browsers) - - browser_positions = self.generate_grid_positions(len(available_browsers)) - location_positions = self.generate_grid_positions(len(available_locations)) + + browser_positions = self.generate_grid_positions( + len(available_browsers)) + location_positions = self.generate_grid_positions( + len(available_locations)) for i, location in enumerate(available_locations): - available_locations_list.append((QPushButton, location, location_positions[i])) + available_locations_list.append( + (QPushButton, location, location_positions[i])) for i, browser in enumerate(available_browsers): - available_browsers_list.append((QPushButton, browser, browser_positions[i])) - + available_browsers_list.append( + (QPushButton, browser, browser_positions[i])) + location_page = self.find_location_page() hidetor_page = self.find_hidetor_page() protocol_page = self.find_protocol_page() @@ -7958,48 +8456,48 @@ class SyncScreen(Page): menu_page = self.find_menu_page() if menu_page: menu_page.refresh_profiles_data() - + def generate_grid_positions(self, num_items): positions = [] start_x = 395 - start_y = 90 + start_y = 90 button_width = 185 button_height = 75 h_spacing = 10 - v_spacing = 105 - + v_spacing = 105 + for i in range(num_items): - col = i % 2 - row = i // 2 - + col = i % 2 + row = i // 2 + x = start_x + (col * (button_width + h_spacing)) y = start_y + (row * v_spacing) - + positions.append((x, y, button_width, button_height)) - + return positions - + def find_browser_page(self): for i in range(self.page_stack.count()): page = self.page_stack.widget(i) if isinstance(page, BrowserPage): return page return None - + def find_location_page(self): for i in range(self.page_stack.count()): page = self.page_stack.widget(i) if isinstance(page, LocationPage): return page return None - + def find_hidetor_page(self): for i in range(self.page_stack.count()): page = self.page_stack.widget(i) if isinstance(page, HidetorPage): return page return None - + def find_protocol_page(self): for i in range(self.page_stack.count()): page = self.page_stack.widget(i) @@ -8014,9 +8512,6 @@ class SyncScreen(Page): return page return None - - - class WelcomePage(Page): def __init__(self, page_stack, main_window=None, parent=None): @@ -8038,7 +8533,7 @@ class WelcomePage(Page): color: cyan; """) welcome_title.setAlignment(Qt.AlignmentFlag.AlignCenter) - + welcome_msg = QLabel( "Before we begin your journey, we need to set up a few essential components. " "Click 'Next' to take you to the installation page.", self) @@ -8053,79 +8548,80 @@ class WelcomePage(Page): def _setup_stats_display(self): stats_container = QWidget(self) stats_container.setGeometry(70, 200, 730, 240) - + stats_title = QLabel(stats_container) stats_title.setText("Features & Services") - stats_title.setGeometry(190, 10, 300, 30) + stats_title.setGeometry(190, 10, 300, 30) stats_title.setStyleSheet(""" font-size: 22px; font-weight: bold; color: cyan; """) - + grid_widget = QWidget(stats_container) - grid_widget.setGeometry(0, 70, 700, 190) + grid_widget.setGeometry(0, 70, 700, 190) grid_layout = QGridLayout(grid_widget) grid_layout.setSpacing(30) - + stats = [ ("Browsers", "browsers_mini.png", "10 Supported Browsers", True), ("WireGuard", "wireguard_mini.png", "6 Global Locations", True), ("Proxy", "just proxy_mini.png", "5 Proxy Locations", True), ("Tor", "toricon_mini.png", "Tor Network Access", True) ] - + for i, (title, icon_name, count, available) in enumerate(stats): row = i // 2 col = i % 2 - + stat_widget = QWidget() stat_layout = QHBoxLayout(stat_widget) stat_layout.setContentsMargins(20, 10, 2, 10) stat_layout.setSpacing(15) - + icon_label = QLabel() icon_path = os.path.join(self.btn_path, icon_name) - icon_label.setPixmap(QPixmap(icon_path).scaled(30, 30, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) + icon_label.setPixmap(QPixmap(icon_path).scaled( + 30, 30, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) icon_label.setFixedSize(30, 30) stat_layout.addWidget(icon_label) - + text_widget = QWidget() text_layout = QVBoxLayout(text_widget) text_layout.setSpacing(5) text_layout.setContentsMargins(0, 0, 30, 0) - + title_widget = QWidget() title_layout = QHBoxLayout(title_widget) title_layout.setContentsMargins(0, 0, 0, 0) title_layout.setSpacing(10) - + title_label = QLabel(title) - title_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #2c3e50;") + title_label.setStyleSheet( + "font-size: 16px; font-weight: bold; color: #2c3e50;") title_layout.addWidget(title_label) - + status_indicator = QLabel("●") status_indicator.setStyleSheet("color: #2ecc71; font-size: 16px;") title_layout.addWidget(status_indicator) - + title_layout.addStretch() text_layout.addWidget(title_widget) - + count_label = QLabel(count) count_label.setStyleSheet("font-size: 16px; color: #34495e;") text_layout.addWidget(count_label) - + stat_layout.addWidget(text_widget, stretch=1) - + stat_widget.setStyleSheet(""" QWidget { background-color: transparent; border-radius: 10px; } """) - - grid_layout.addWidget(stat_widget, row, col) + grid_layout.addWidget(stat_widget, row, col) def go_to_install(self): install_page = self.page_stack.findChild(InstallSystemPackage) @@ -8155,11 +8651,13 @@ class SystemwidePromptPage(Page): description.setWordWrap(True) description.setStyleSheet("font-size: 14px; color: cyan;") description.setText("If you're using Systemwide profiles, you may wish to enable them without having to enter the sudo password each time for convenience. This requires the sudo password to setup profiles and disable them (for security), but not to turn it on each time. You can choose to set this up now or later in the options menu.") - + icon_label = QLabel(self) icon_label.setGeometry(80, 300, 64, 64) - icon_pix = QPixmap(os.path.join(self.btn_path, "wireguard_system_wide.png")) - icon_label.setPixmap(icon_pix.scaled(64, 64, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) + icon_pix = QPixmap(os.path.join( + self.btn_path, "wireguard_system_wide.png")) + icon_label.setPixmap(icon_pix.scaled( + 64, 64, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) yes_button = QPushButton("Yes, enable system-wide profiles", self) yes_button.setGeometry(170, 300, 300, 50) yes_button.setStyleSheet(""" @@ -8197,10 +8695,12 @@ class SystemwidePromptPage(Page): def refresh_status(self): privilege_policy = PolicyController.get('privilege') if privilege_policy is not None and PolicyController.is_instated(privilege_policy): - self.status_label.setText("Current status: system-wide policy is enabled.") + self.status_label.setText( + "Current status: system-wide policy is enabled.") self.status_label.setStyleSheet("font-size: 14px; color: #2ecc71;") else: - self.status_label.setText("Current status: system-wide policy is disabled.") + self.status_label.setText( + "Current status: system-wide policy is disabled.") self.status_label.setStyleSheet("font-size: 14px; color: #e67e22;") def enable_systemwide(self): @@ -8212,7 +8712,8 @@ class SystemwidePromptPage(Page): self.update_status.mark_systemwide_prompt_shown() self.refresh_status() self.update_status.update_status("System-wide policy enabled") - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) except CommandNotFoundError as e: self.status_label.setText(str(e)) self.status_label.setStyleSheet("font-size: 14px; color: red;") @@ -8225,12 +8726,15 @@ class SystemwidePromptPage(Page): def skip_systemwide(self): self.update_status.mark_systemwide_prompt_shown() - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def back_to_install(self): install_page = self.page_stack.findChild(InstallSystemPackage) if install_page: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(install_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(install_page)) + class PolicySuggestionPage(Page): def __init__(self, page_stack, main_window=None, parent=None, policy_type='capability'): @@ -8251,18 +8755,20 @@ class PolicySuggestionPage(Page): policy_name = "Capability" if self.policy_type == 'capability' else "Privilege" self.title.setGeometry(20, 50, 760, 40) self.title.setText(f"Policy Suggestion: {policy_name} Policy") - + description = QLabel(self) description.setGeometry(80, 100, 640, 60) description.setWordWrap(True) description.setStyleSheet("font-size: 14px; color: cyan;") - description.setText(f"A {policy_name.lower()} policy is available and can be instated to improve functionality. Review the policy details below before proceeding.") - + description.setText( + f"A {policy_name.lower()} policy is available and can be instated to improve functionality. Review the policy details below before proceeding.") + preview_label = QLabel(self) preview_label.setGeometry(80, 170, 640, 30) - preview_label.setStyleSheet("font-size: 13px; color: white; font-weight: bold;") + preview_label.setStyleSheet( + "font-size: 13px; color: white; font-weight: bold;") preview_label.setText("Policy Preview:") - + preview_text = QTextEdit(self) preview_text.setGeometry(80, 200, 640, 150) preview_text.setReadOnly(True) @@ -8282,7 +8788,7 @@ class PolicySuggestionPage(Page): preview_text.setText(preview_content) except Exception as e: preview_text.setText(f"Error loading preview: {str(e)}") - + yes_button = QPushButton(f"Instate {policy_name} Policy", self) yes_button.setGeometry(170, 370, 250, 50) yes_button.setStyleSheet(""" @@ -8299,7 +8805,7 @@ class PolicySuggestionPage(Page): } """) yes_button.clicked.connect(self.instate_policy) - + no_button = QPushButton("Skip", self) no_button.setGeometry(440, 370, 120, 50) no_button.setStyleSheet(""" @@ -8316,17 +8822,21 @@ class PolicySuggestionPage(Page): } """) no_button.clicked.connect(self.skip_policy) - + self.refresh_status() def refresh_status(self): try: if PolicyController.is_instated(self.policy): - self.status_label.setText(f"Current status: {self.policy_type} policy is instated.") - self.status_label.setStyleSheet("font-size: 14px; color: #2ecc71;") + self.status_label.setText( + f"Current status: {self.policy_type} policy is instated.") + self.status_label.setStyleSheet( + "font-size: 14px; color: #2ecc71;") else: - self.status_label.setText(f"Current status: {self.policy_type} policy is not instated.") - self.status_label.setStyleSheet("font-size: 14px; color: #e67e22;") + self.status_label.setText( + f"Current status: {self.policy_type} policy is not instated.") + self.status_label.setStyleSheet( + "font-size: 14px; color: #e67e22;") except Exception: self.status_label.setText("Unable to determine policy status.") self.status_label.setStyleSheet("font-size: 14px; color: #e67e22;") @@ -8339,7 +8849,8 @@ class PolicySuggestionPage(Page): self.update_status.update_status(f"{policy_name} policy instated") menu_page = self.page_stack.findChild(MenuPage) if menu_page: - self.page_stack.setCurrentIndex(self.page_stack.indexOf(menu_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(menu_page)) else: self.page_stack.setCurrentIndex(0) except CommandNotFoundError as e: @@ -8359,6 +8870,7 @@ class PolicySuggestionPage(Page): else: self.page_stack.setCurrentIndex(0) + class DurationSelectionPage(Page): def __init__(self, page_stack, main_window=None, parent=None): super().__init__("Select Duration", page_stack, main_window, parent) @@ -8374,7 +8886,8 @@ class DurationSelectionPage(Page): self.combo_box = QComboBox(self) self.combo_box.setGeometry(200, 200, 400, 60) - self.combo_box.addItems(["1 month (€1)", "3 months (€3)", "6 months (€5)", "12 months (€10)"]) + self.combo_box.addItems( + ["1 month (€1)", "3 months (€3)", "6 months (€5)", "12 months (€10)"]) self.combo_box.setEditable(False) self.combo_box.setMaxVisibleItems(4) self.combo_box.setDuplicatesEnabled(True) @@ -8443,7 +8956,10 @@ class DurationSelectionPage(Page): self.page_stack.setCurrentWidget(currency_page) def reverse(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(IdPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(IdPage))) + + class CurrencySelectionPage(Page): def __init__(self, page_stack, main_window=None, parent=None): super().__init__("Select Currency", page_stack, main_window, parent) @@ -8476,7 +8992,8 @@ class CurrencySelectionPage(Page): button.setCheckable(True) self.buttons.append(button) self.buttonGroup.addButton(button, j) - button.setIcon(QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) + button.setIcon( + QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) button.clicked.connect(self.on_currency_selected) def on_currency_selected(self): @@ -8488,8 +9005,6 @@ class CurrencySelectionPage(Page): self.page_stack.setCurrentWidget(payment_details_page) self.update_status.update_status('Loading payment details...') - - def get_selected_currency(self): selected_button = self.buttonGroup.checkedButton() if selected_button: @@ -8503,6 +9018,7 @@ class CurrencySelectionPage(Page): if duration_page: self.page_stack.setCurrentWidget(duration_page) + class PaymentDetailsPage(Page): def __init__(self, page_stack, main_window=None, parent=None): super().__init__("Payment Details", page_stack, main_window, parent) @@ -8511,7 +9027,7 @@ class PaymentDetailsPage(Page): self.invoice_data = {} self.selected_duration = None self.selected_currency = None - + self.create_interface_elements() self.button_reverse.setVisible(True) @@ -8537,7 +9053,8 @@ class PaymentDetailsPage(Page): ("", "cuadro150x50", (200, 155), (150, 50)), ("Amount", None, (10, 220), (150, 50)), ("", "cuadro150x50", (200, 220), (150, 50)), - ("Hit this white icon to copy paste the address:", None, (15, 305), (500, 30)), + ("Hit this white icon to copy paste the address:", + None, (15, 305), (500, 30)), ("", "cuadro400x50", (20, 350), (400, 50)), ("Hit this icon to Scan the QR code:", None, (15, 450), (360, 30)), ] @@ -8548,19 +9065,19 @@ class PaymentDetailsPage(Page): if "Hit" in text: label.setStyleSheet("font-size: 16px;") - label.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter) + label.setAlignment( + QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter) else: label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) if image_name: - pixmap = QPixmap(os.path.join(self.btn_path, f"{image_name}.png")) + pixmap = QPixmap(os.path.join( + self.btn_path, f"{image_name}.png")) label.setPixmap(pixmap) label.setScaledContents(True) else: label.setText(text) - - line_edit_info = [ (20, 90, 400, 50), (200, 155, 150, 50), @@ -8587,7 +9104,8 @@ class PaymentDetailsPage(Page): icon = QIcon(os.path.join(self.btn_path, "paste_button.png")) button.setIcon(icon) button.setIconSize(button.size()) - button.clicked.connect(lambda checked, index=field_index: self.copy_text(index)) + button.clicked.connect( + lambda checked, index=field_index: self.copy_text(index)) currency_button_info = [ ("monero", (545, 75)), @@ -8604,9 +9122,8 @@ class PaymentDetailsPage(Page): button.setCheckable(True) button.setEnabled(False) self.currency_display_buttons.append(button) - button.setIcon(QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) - - + button.setIcon( + QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) def fetch_invoice_duration(self): duration_month_num = int(self.selected_duration.split()[0]) @@ -8620,7 +9137,7 @@ class PaymentDetailsPage(Page): if self.selected_duration: self.text_fields[1].setText(self.selected_duration) self.text_fields[1].setStyleSheet('font-size: 13px;') - + if self.selected_currency: currency_index_map = { "monero": 0, @@ -8634,24 +9151,24 @@ class PaymentDetailsPage(Page): button.setChecked(i == currency_index) button.setEnabled(i == currency_index) - - def on_request_invoice(self): total_hours = self.fetch_invoice_duration() if self.selected_currency is None: self.update_status.update_status('No currency selected') return - + profile_data = { 'id': int(self.update_status.current_profile_id), 'duration': total_hours, 'currency': 'xmr' if self.selected_currency == 'monero' else 'btc' if self.selected_currency == 'bitcoin' else 'btc-ln' if self.selected_currency == 'lightning' else 'ltc' if self.selected_currency == 'litecoin' else None } - + self.update_status.update_status('Generating Invoice...') - self.worker_thread = WorkerThread('GET_SUBSCRIPTION', profile_data=profile_data) + self.worker_thread = WorkerThread( + 'GET_SUBSCRIPTION', profile_data=profile_data) self.worker_thread.text_output.connect(self.invoice_update_text_output) - self.worker_thread.invoice_output.connect(self.on_invoice_generation_finished) + self.worker_thread.invoice_output.connect( + self.on_invoice_generation_finished) self.worker_thread.invoice_finished.connect(self.on_invoice_finished) self.worker_thread.start() @@ -8673,21 +9190,24 @@ class PaymentDetailsPage(Page): total_hours = self.fetch_invoice_duration() if self.invoice_data and self.invoice_data['duration'] == total_hours: self.update_status.update_status('Checking invoice status...') - self.check_invoice_status(self.invoice_data['billing_details'].billing_code) + self.check_invoice_status( + self.invoice_data['billing_details'].billing_code) else: self.on_request_invoice() - def check_invoice_status(self, billing_code: str): - self.worker_thread = WorkerThread('CHECK_INVOICE_STATUS', profile_data={'billing_code': billing_code}) - self.worker_thread.invoice_finished.connect(self.on_invoice_status_finished) + self.worker_thread = WorkerThread('CHECK_INVOICE_STATUS', profile_data={ + 'billing_code': billing_code}) + self.worker_thread.invoice_finished.connect( + self.on_invoice_status_finished) self.worker_thread.start() def on_invoice_status_finished(self, result): if result: self.parse_invoice_data(self.invoice_data['billing_details']) else: - self.update_status.update_status('Invoice has expired. Generating new invoice...') + self.update_status.update_status( + 'Invoice has expired. Generating new invoice...') self.on_request_invoice() def on_invoice_generation_finished(self, billing_details: object, text: str): @@ -8699,24 +9219,26 @@ class PaymentDetailsPage(Page): billing_details = { 'billing_code': invoice_data.billing_code } - + if self.selected_currency.lower() == 'lightning': currency = 'Bitcoin Lightning' else: currency = self.selected_currency - - preferred_method = next((pm for pm in invoice_data.payment_methods if pm.name.lower() == currency.lower()), None) + + preferred_method = next( + (pm for pm in invoice_data.payment_methods if pm.name.lower() == currency.lower()), None) if preferred_method: billing_details['due_amount'] = preferred_method.due billing_details['address'] = preferred_method.address else: - self.update_status.update_status('No payment method found for the selected currency.') + self.update_status.update_status( + 'No payment method found for the selected currency.') return billing_values = list(billing_details.values()) text_field_indices = [0, 2, 3] - + for i, dict_value in enumerate(billing_values): if i < 3: field_index = text_field_indices[i] @@ -8725,7 +9247,8 @@ class PaymentDetailsPage(Page): self.full_address = text metrics = self.text_fields[field_index].fontMetrics() width = self.text_fields[field_index].width() - elided_text = metrics.elidedText(text, QtCore.Qt.TextElideMode.ElideMiddle, width) + elided_text = metrics.elidedText( + text, QtCore.Qt.TextElideMode.ElideMiddle, width) self.text_fields[field_index].setText(elided_text) elif i == 1: text = str(dict_value) @@ -8738,25 +9261,28 @@ class PaymentDetailsPage(Page): font_size = 10 if len(text) > 16: font_size = 10 - self.text_fields[field_index].setStyleSheet(f"font-size: {font_size}px; font-weight: bold;") + self.text_fields[field_index].setStyleSheet( + f"font-size: {font_size}px; font-weight: bold;") else: - self.text_fields[field_index].setProperty("fullText", str(dict_value)) + self.text_fields[field_index].setProperty( + "fullText", str(dict_value)) self.text_fields[field_index].setText(str(dict_value)) self.qr_code_button.setDisabled(False) - self.update_status.update_status('Invoice generated. Awaiting payment...') - + self.update_status.update_status( + 'Invoice generated. Awaiting payment...') def on_invoice_finished(self, result): if result: self.invoice_data.clear() self.show_payment_confirmed(self.text_fields[0].text()) return - self.update_status.update_status('An error occurred when generating invoice') + self.update_status.update_status( + 'An error occurred when generating invoice') def show_payment_confirmed(self, billing_code): payment_page = self.find_payment_confirmed_page() - + if payment_page: for line in self.text_fields: line.setText('') @@ -8776,25 +9302,31 @@ class PaymentDetailsPage(Page): try: original_status = self.update_status.status_label.text() original_status = original_status.replace("Status: ", "") - + if int(field) == 3: text = self.full_address else: text = self.text_fields[int(field)].text() QApplication.clipboard().setText(text) - + if field == 0: - self.update_status.update_status('Billing code copied to clipboard!') + self.update_status.update_status( + 'Billing code copied to clipboard!') elif field == 3: - self.update_status.update_status('Address copied to clipboard!') + self.update_status.update_status( + 'Address copied to clipboard!') else: - self.update_status.update_status('Pay amount copied to clipboard!') - - QTimer.singleShot(2000, lambda: self.update_status.update_status(original_status)) + self.update_status.update_status( + 'Pay amount copied to clipboard!') + + QTimer.singleShot( + 2000, lambda: self.update_status.update_status(original_status)) except AttributeError: - self.update_status.update_status('No content available for copying') + self.update_status.update_status( + 'No content available for copying') except Exception as e: - self.update_status.update_status(f'An error occurred when copying the text') + self.update_status.update_status( + f'An error occurred when copying the text') def reverse(self): currency_page = self.page_stack.findChild(CurrencySelectionPage) @@ -8805,10 +9337,12 @@ class PaymentDetailsPage(Page): full_amount = self.text_fields[2].text() if hasattr(self, 'full_address') and self.full_address: currency_type = getattr(self, 'selected_currency', None) - qr_dialog = QRCodeDialog(self.full_address, full_amount, currency_type, self) + qr_dialog = QRCodeDialog( + self.full_address, full_amount, currency_type, self) qr_dialog.exec() else: - self.update_status.update_status('No address available for QR code') + self.update_status.update_status( + 'No address available for QR code') def fetch_invoice_duration(self): duration_month_num = int(self.selected_duration.split()[0]) @@ -8817,6 +9351,8 @@ class PaymentDetailsPage(Page): else: total_hours = duration_month_num * (30 * 24) return total_hours + + class FastRegistrationPage(Page): def __init__(self, page_stack, main_window): super().__init__("FastRegistration", page_stack, main_window) @@ -8827,10 +9363,10 @@ class FastRegistrationPage(Page): self.buttons = [] self.title.setGeometry(550, 40, 250, 40) self.title.setText("Fast Creation") - + self.button_apply.setVisible(True) self.button_apply.clicked.connect(self.create_profile) - + self.button_back.setVisible(True) try: self.button_back.clicked.disconnect() @@ -8845,19 +9381,23 @@ class FastRegistrationPage(Page): self.name_hint = QLabel(self) self.name_hint.setGeometry(265, 100, 190, 20) - self.name_hint.setStyleSheet('color: #888888; font-size: 10px; font-style: italic;') + self.name_hint.setStyleSheet( + 'color: #888888; font-size: 10px; font-style: italic;') self.name_hint.setText("Click here to edit profile name") self.name_hint.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.name = QLineEdit(self) self.name.setPlaceholderText("Enter name") self.name.setGeometry(265, 70, 190, 30) - self.name.setStyleSheet("color: cyan; border: 1px solid #666666; border-radius: 3px; background-color: rgba(0, 0, 0, 0.3);") - self.name.setCursor(QtCore.Qt.CursorShape.IBeamCursor) + self.name.setStyleSheet( + "color: cyan; border: 1px solid #666666; border-radius: 3px; background-color: rgba(0, 0, 0, 0.3);") + self.name.setCursor(QtCore.Qt.CursorShape.IBeamCursor) self.name.focusInEvent = lambda event: self.name_hint.hide() - self.name.focusOutEvent = lambda event: self.name_hint.show() if not self.name.text() else self.name_hint.hide() - - self.name.textChanged.connect(lambda text: self.name_hint.hide() if text else self.name_hint.show()) + self.name.focusOutEvent = lambda event: self.name_hint.show( + ) if not self.name.text() else self.name_hint.hide() + + self.name.textChanged.connect( + lambda text: self.name_hint.hide() if text else self.name_hint.show()) self.profile_data = {} self.selected_values = { @@ -8867,7 +9407,7 @@ class FastRegistrationPage(Page): 'browser': '', 'resolution': '1024x760' } - + self.initialize_default_selections() def initialize_default_selections(self): @@ -8876,7 +9416,7 @@ class FastRegistrationPage(Page): if locations: random_index = random.randint(0, len(locations) - 1) self.selected_values['location'] = locations[random_index] - + if not self.selected_values['browser']: browsers = self.connection_manager.get_browser_list() if browsers: @@ -8887,13 +9427,13 @@ class FastRegistrationPage(Page): profiles = ProfileController.get_all() if not profiles: return 1 - + existing_ids = sorted(profiles.keys()) - + for i in range(1, max(existing_ids) + 2): if i not in existing_ids: return i - + return 1 def showEvent(self, event): @@ -8908,7 +9448,7 @@ class FastRegistrationPage(Page): for button in self.buttons: button.deleteLater() self.buttons = [] - + if not self.name.text(): self.name_hint.show() else: @@ -8924,8 +9464,9 @@ class FastRegistrationPage(Page): def create_protocol_section(self): label = QLabel("Protocol", self) label.setGeometry(300, 150, 185, 75) - - protocol_image = QPixmap(os.path.join(self.btn_path, f"{self.selected_values['protocol']}_button.png")) + + protocol_image = QPixmap(os.path.join( + self.btn_path, f"{self.selected_values['protocol']}_button.png")) label.setPixmap(protocol_image) label.setScaledContents(True) label.show() @@ -8933,7 +9474,8 @@ class FastRegistrationPage(Page): prev_button = QPushButton(self) prev_button.setGeometry(265, 150, 30, 75) - prev_button.clicked.connect(lambda: self.show_previous_value('protocol')) + prev_button.clicked.connect( + lambda: self.show_previous_value('protocol')) prev_button.show() icon_path = os.path.join(self.btn_path, "UP_button.png") icon = QPixmap(icon_path) @@ -8947,22 +9489,26 @@ class FastRegistrationPage(Page): next_button.setGeometry(490, 150, 30, 75) next_button.clicked.connect(lambda: self.show_next_value('protocol')) next_button.show() - next_button.setIcon(QIcon(os.path.join(self.btn_path, "UP_button.png"))) + next_button.setIcon( + QIcon(os.path.join(self.btn_path, "UP_button.png"))) next_button.setIconSize(next_button.size()) self.buttons.append(next_button) def create_connection_section(self): label = QLabel("Connection", self) label.setGeometry(150, 250, 185, 75) - + if self.selected_values['connection']: - connection_image = QPixmap(os.path.join(self.btn_path, f"{self.selected_values['connection']}_button.png")) + connection_image = QPixmap(os.path.join( + self.btn_path, f"{self.selected_values['connection']}_button.png")) if connection_image.isNull(): - fallback_path = os.path.join(self.btn_path, "browser-only_button.png") + fallback_path = os.path.join( + self.btn_path, "browser-only_button.png") connection_image = QPixmap(fallback_path) else: - connection_image = QPixmap(os.path.join(self.btn_path, "browser-only_button.png")) - + connection_image = QPixmap(os.path.join( + self.btn_path, "browser-only_button.png")) + label.setPixmap(connection_image) label.setScaledContents(True) label.show() @@ -8970,7 +9516,8 @@ class FastRegistrationPage(Page): prev_button = QPushButton(self) prev_button.setGeometry(115, 250, 30, 75) - prev_button.clicked.connect(lambda: self.show_previous_value('connection')) + prev_button.clicked.connect( + lambda: self.show_previous_value('connection')) prev_button.show() icon_path = os.path.join(self.btn_path, "UP_button.png") icon = QPixmap(icon_path) @@ -8984,18 +9531,20 @@ class FastRegistrationPage(Page): next_button.setGeometry(340, 250, 30, 75) next_button.clicked.connect(lambda: self.show_next_value('connection')) next_button.show() - next_button.setIcon(QIcon(os.path.join(self.btn_path, "UP_button.png"))) + next_button.setIcon( + QIcon(os.path.join(self.btn_path, "UP_button.png"))) next_button.setIconSize(next_button.size()) self.buttons.append(next_button) def create_location_section(self): info_label = QLabel("Click on the location for more info", self) info_label.setGeometry(480, 80, 300, 20) - info_label.setStyleSheet("color: #888888; font-size: 14px; font-style: italic;") + info_label.setStyleSheet( + "color: #888888; font-size: 14px; font-style: italic;") info_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight) info_label.show() self.labels.append(info_label) - + arrow_label = QLabel(self) arrow_label.setGeometry(540, 100, 150, 150) arrow_pixmap = QPixmap(os.path.join(self.btn_path, "arrow.png")) @@ -9005,44 +9554,56 @@ class FastRegistrationPage(Page): arrow_label.setScaledContents(True) arrow_label.show() self.labels.append(arrow_label) - + label = QPushButton(self) label.setGeometry(435, 250, 185, 75) label.setFlat(True) label.setStyleSheet("background: transparent; border: none;") - + if self.selected_values['location']: - image_path = os.path.join(self.btn_path, f"button_{self.selected_values['location']}.png") + image_path = os.path.join( + self.btn_path, f"button_{self.selected_values['location']}.png") location_image = QPixmap(image_path) - locations = self.connection_manager.get_location_info(self.selected_values['location']) - provider = locations.operator.name if locations and hasattr(locations, 'operator') else None - fallback_path = os.path.join(self.btn_path, "default_location_button.png") - + locations = self.connection_manager.get_location_info( + self.selected_values['location']) + provider = locations.operator.name if locations and hasattr( + locations, 'operator') else None + fallback_path = os.path.join( + self.btn_path, "default_location_button.png") + if location_image.isNull(): if locations and hasattr(locations, 'country_name'): - location_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider) + location_name = locations.country_name + location_image = LocationPage.create_location_button_image( + location_name, fallback_path, provider) else: - location_image = LocationPage.create_location_button_image(self.selected_values['location'], fallback_path, provider) + location_image = LocationPage.create_location_button_image( + self.selected_values['location'], fallback_path, provider) else: if locations and hasattr(locations, 'country_name'): - location_image = LocationPage.create_location_button_image(f'{locations.country_code}_{locations.code}', fallback_path, provider, image_path) + location_image = LocationPage.create_location_button_image( + f'{locations.country_code}_{locations.code}', fallback_path, provider, image_path) else: - location_image = LocationPage.create_location_button_image(self.selected_values['location'], fallback_path, provider, image_path) + location_image = LocationPage.create_location_button_image( + self.selected_values['location'], fallback_path, provider, image_path) else: - location_image = QPixmap(os.path.join(self.btn_path, "default_location_button.png")) - + location_image = QPixmap(os.path.join( + self.btn_path, "default_location_button.png")) + label.setIcon(QIcon(location_image)) label.setIconSize(QSize(185, 75)) if self.selected_values['location']: label.location_icon_name = self.selected_values['location'] label.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) - label.clicked.connect(lambda checked, loc=self.selected_values['location']: self.show_location_verification(loc)) + label.clicked.connect( + lambda checked, loc=self.selected_values['location']: self.show_location_verification(loc)) label.show() self.labels.append(label) prev_button = QPushButton(self) prev_button.setGeometry(400, 250, 30, 75) - prev_button.clicked.connect(lambda: self.show_previous_value('location')) + prev_button.clicked.connect( + lambda: self.show_previous_value('location')) prev_button.show() icon_path = os.path.join(self.btn_path, "UP_button.png") icon = QPixmap(icon_path) @@ -9056,22 +9617,26 @@ class FastRegistrationPage(Page): next_button.setGeometry(625, 250, 30, 75) next_button.clicked.connect(lambda: self.show_next_value('location')) next_button.show() - next_button.setIcon(QIcon(os.path.join(self.btn_path, "UP_button.png"))) + next_button.setIcon( + QIcon(os.path.join(self.btn_path, "UP_button.png"))) next_button.setIconSize(next_button.size()) self.buttons.append(next_button) def create_browser_section(self): label = QLabel("Browser", self) label.setGeometry(150, 350, 185, 75) - + if self.selected_values['browser']: - browser_image = BrowserPage.create_browser_button_image(self.selected_values['browser'], self.btn_path) + browser_image = BrowserPage.create_browser_button_image( + self.selected_values['browser'], self.btn_path) if browser_image.isNull(): - fallback_path = os.path.join(self.btn_path, "default_browser_button.png") - browser_image = BrowserPage.create_browser_button_image(self.selected_values['browser'], fallback_path, True) + fallback_path = os.path.join( + self.btn_path, "default_browser_button.png") + browser_image = BrowserPage.create_browser_button_image( + self.selected_values['browser'], fallback_path, True) else: browser_image = QPixmap() - + label.setPixmap(browser_image) label.setScaledContents(True) label.show() @@ -9079,7 +9644,8 @@ class FastRegistrationPage(Page): prev_button = QPushButton(self) prev_button.setGeometry(115, 350, 30, 75) - prev_button.clicked.connect(lambda: self.show_previous_value('browser')) + prev_button.clicked.connect( + lambda: self.show_previous_value('browser')) prev_button.show() icon_path = os.path.join(self.btn_path, "UP_button.png") icon = QPixmap(icon_path) @@ -9093,7 +9659,8 @@ class FastRegistrationPage(Page): next_button.setGeometry(340, 350, 30, 75) next_button.clicked.connect(lambda: self.show_next_value('browser')) next_button.show() - next_button.setIcon(QIcon(os.path.join(self.btn_path, "UP_button.png"))) + next_button.setIcon( + QIcon(os.path.join(self.btn_path, "UP_button.png"))) next_button.setIconSize(next_button.size()) self.buttons.append(next_button) @@ -9102,11 +9669,13 @@ class FastRegistrationPage(Page): label.setGeometry(435, 350, 185, 75) screen_page = self.page_stack.findChild(ScreenPage) if self.selected_values['resolution']: - - resolution_image = screen_page.create_resolution_button_image(self.selected_values['resolution']) + + resolution_image = screen_page.create_resolution_button_image( + self.selected_values['resolution']) else: - resolution_image = screen_page.create_resolution_button_image("1024x760") - + resolution_image = screen_page.create_resolution_button_image( + "1024x760") + label.setPixmap(resolution_image) label.setScaledContents(True) label.show() @@ -9114,7 +9683,8 @@ class FastRegistrationPage(Page): prev_button = QPushButton(self) prev_button.setGeometry(400, 350, 30, 75) - prev_button.clicked.connect(lambda: self.show_previous_value('resolution')) + prev_button.clicked.connect( + lambda: self.show_previous_value('resolution')) prev_button.show() icon_path = os.path.join(self.btn_path, "UP_button.png") icon = QPixmap(icon_path) @@ -9128,13 +9698,14 @@ class FastRegistrationPage(Page): next_button.setGeometry(625, 350, 30, 75) next_button.clicked.connect(lambda: self.show_next_value('resolution')) next_button.show() - next_button.setIcon(QIcon(os.path.join(self.btn_path, "UP_button.png"))) + next_button.setIcon( + QIcon(os.path.join(self.btn_path, "UP_button.png"))) next_button.setIconSize(next_button.size()) self.buttons.append(next_button) def update_ui_state_for_connection(self): is_system_wide = self.selected_values['connection'] == 'system-wide' - + for button in self.buttons: if hasattr(button, 'geometry'): button_geometry = button.geometry() @@ -9142,7 +9713,6 @@ class FastRegistrationPage(Page): if button_geometry.x() in [115, 340, 400, 625]: button.setEnabled(not is_system_wide) - def show_previous_value(self, key): if key == 'protocol': protocols = ['wireguard', 'hidetor'] @@ -9179,11 +9749,12 @@ class FastRegistrationPage(Page): elif browsers: self.selected_values[key] = browsers[0] elif key == 'resolution': - resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] + resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', + '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] current_index = resolutions.index(self.selected_values[key]) previous_index = (current_index - 1) % len(resolutions) self.selected_values[key] = resolutions[previous_index] - + self.create_interface_elements() def show_next_value(self, key): @@ -9222,20 +9793,24 @@ class FastRegistrationPage(Page): elif browsers: self.selected_values[key] = browsers[0] elif key == 'resolution': - resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] + resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', + '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] current_index = resolutions.index(self.selected_values[key]) next_index = (current_index + 1) % len(resolutions) self.selected_values[key] = resolutions[next_index] - + self.create_interface_elements() def go_back(self): - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def show_location_verification(self, location_icon_name): - verification_page = LocationVerificationPage(self.page_stack, self.update_status, location_icon_name, self) + verification_page = LocationVerificationPage( + self.page_stack, self.update_status, location_icon_name, self) self.page_stack.addWidget(verification_page) - self.page_stack.setCurrentIndex(self.page_stack.indexOf(verification_page)) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(verification_page)) def create_profile(self): profile_name = self.name.text() @@ -9262,7 +9837,7 @@ class FastRegistrationPage(Page): self.profile_data = profile_data self.update_status.write_data(profile_data) - + resume_page = self.find_resume_page() if resume_page: if self.selected_values['protocol'] == 'wireguard': @@ -9273,7 +9848,8 @@ class FastRegistrationPage(Page): self.go_back() def create_wireguard_profile(self, profile_data): - location_info = self.connection_manager.get_location_info(profile_data['location']) + location_info = self.connection_manager.get_location_info( + profile_data['location']) if not location_info: self.update_status.update_status('Invalid location selected') return @@ -9292,12 +9868,15 @@ class FastRegistrationPage(Page): resume_page = self.find_resume_page() if resume_page: if profile_data['connection'] == 'system-wide': - resume_page.handle_core_action_create_profile('CREATE_SYSTEM_PROFILE', profile_data_for_resume, 'system') + resume_page.handle_core_action_create_profile( + 'CREATE_SYSTEM_PROFILE', profile_data_for_resume, 'system') else: - resume_page.handle_core_action_create_profile('CREATE_SESSION_PROFILE', profile_data_for_resume, 'session') + resume_page.handle_core_action_create_profile( + 'CREATE_SESSION_PROFILE', profile_data_for_resume, 'session') def create_tor_profile(self, profile_data): - location_info = self.connection_manager.get_location_info(profile_data['location']) + location_info = self.connection_manager.get_location_info( + profile_data['location']) if not location_info: self.update_status.update_status('Invalid location selected') return @@ -9317,9 +9896,8 @@ class FastRegistrationPage(Page): resume_page = self.find_resume_page() if resume_page: - resume_page.handle_core_action_create_profile('CREATE_SESSION_PROFILE', profile_data_for_resume, 'session') - - + resume_page.handle_core_action_create_profile( + 'CREATE_SESSION_PROFILE', profile_data_for_resume, 'session') def find_resume_page(self): for i in range(self.page_stack.count()): @@ -9328,6 +9906,7 @@ class FastRegistrationPage(Page): return page return None + class FastModePromptPage(Page): def __init__(self, page_stack, main_window): super().__init__("FastModePrompt", page_stack, main_window) @@ -9344,7 +9923,8 @@ class FastModePromptPage(Page): v.setContentsMargins(0, 0, 0, 0) v.setSpacing(20) - large_text = QLabel("Would you like to switch to convenient \"fast mode\" for profile creation going forward? (recommended)") + large_text = QLabel( + "Would you like to switch to convenient \"fast mode\" for profile creation going forward? (recommended)") large_text.setWordWrap(True) large_text.setStyleSheet("color: white; font-size: 18px;") large_text.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) @@ -9358,13 +9938,15 @@ class FastModePromptPage(Page): yes_btn = QPushButton("Yes Fast Mode") yes_btn.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) yes_btn.setFixedSize(240, 56) - yes_btn.setStyleSheet("background-color: #27ae60; color: white; font-weight: bold; font-size: 16px; border: none; border-radius: 6px;") + yes_btn.setStyleSheet( + "background-color: #27ae60; color: white; font-weight: bold; font-size: 16px; border: none; border-radius: 6px;") yes_btn.clicked.connect(self.choose_yes) no_btn = QPushButton("No Keep This") no_btn.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) no_btn.setFixedSize(160, 42) - no_btn.setStyleSheet("background-color: #c0392b; color: white; font-size: 14px; border: none; border-radius: 6px;") + no_btn.setStyleSheet( + "background-color: #c0392b; color: white; font-size: 14px; border: none; border-radius: 6px;") no_btn.clicked.connect(self.choose_no) h.addStretch() @@ -9373,7 +9955,8 @@ class FastModePromptPage(Page): h.addStretch() v.addWidget(buttons_row) - small_text = QLabel("You can toggle this anytime in the \"Options\" Menu, under \"Create/Edit\"") + small_text = QLabel( + "You can toggle this anytime in the \"Options\" Menu, under \"Create/Edit\"") small_text.setWordWrap(True) small_text.setStyleSheet("color: #999999; font-size: 12px;") small_text.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) @@ -9381,7 +9964,8 @@ class FastModePromptPage(Page): def finalize(self): self.update_status.mark_fast_mode_prompt_shown() - self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) + self.page_stack.setCurrentIndex( + self.page_stack.indexOf(self.page_stack.findChild(MenuPage))) def choose_yes(self): self.update_status.set_fast_mode_enabled(True) @@ -9397,7 +9981,7 @@ class FastModePromptPage(Page): if locations: random_index = random.randint(0, len(locations) - 1) self.selected_values['location'] = locations[random_index] - + if not self.selected_values['browser']: browsers = self.connection_manager.get_browser_list() if browsers: @@ -9408,14 +9992,16 @@ class FastModePromptPage(Page): profiles = ProfileController.get_all() if not profiles: return 1 - + existing_ids = sorted(profiles.keys()) - + for i in range(1, max(existing_ids) + 2): if i not in existing_ids: return i - + return 1 + + class QRCodeDialog(QDialog): def __init__(self, address_text, full_amount, currency_type=None, parent=None): super().__init__(parent) @@ -9423,44 +10009,51 @@ class QRCodeDialog(QDialog): self.setWindowTitle("Payment Address QR Code") self.setFixedSize(400, 450) self.setModal(True) - + layout = QVBoxLayout(self) - + title_label = QLabel("Scan QR Code to Copy Address", self) title_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - title_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #00ffff; margin: 10px;") + title_label.setStyleSheet( + "font-size: 16px; font-weight: bold; color: #00ffff; margin: 10px;") layout.addWidget(title_label) - + qr_label = QLabel(self) qr_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - qr_label.setStyleSheet("margin: 10px; border: 2px solid #00ffff; border-radius: 10px;") - + qr_label.setStyleSheet( + "margin: 10px; border: 2px solid #00ffff; border-radius: 10px;") + qr_pixmap = self.generate_qr_code(address_text, full_amount) qr_label.setPixmap(qr_pixmap) layout.addWidget(qr_label) amount_label = QLabel("Amount:", self) - amount_label.setStyleSheet("font-size: 12px; color: #ffffff; margin-top: 10px;") + amount_label.setStyleSheet( + "font-size: 12px; color: #ffffff; margin-top: 10px;") layout.addWidget(amount_label) - + amount_text_label = QLabel(full_amount, self) - amount_text_label.setStyleSheet("font-size: 10px; color: #cccccc; margin: 5px; padding: 5px; border: 1px solid #666; border-radius: 5px;") + amount_text_label.setStyleSheet( + "font-size: 10px; color: #cccccc; margin: 5px; padding: 5px; border: 1px solid #666; border-radius: 5px;") layout.addWidget(amount_text_label) - + address_label = QLabel("Address:", self) - address_label.setStyleSheet("font-size: 12px; color: #ffffff; margin-top: 10px;") + address_label.setStyleSheet( + "font-size: 12px; color: #ffffff; margin-top: 10px;") layout.addWidget(address_label) - + address_text_label = QLabel(address_text, self) address_text_label.setWordWrap(True) - address_text_label.setStyleSheet("font-size: 10px; color: #cccccc; margin: 5px; padding: 5px; border: 1px solid #666; border-radius: 5px;") + address_text_label.setStyleSheet( + "font-size: 10px; color: #cccccc; margin: 5px; padding: 5px; border: 1px solid #666; border-radius: 5px;") layout.addWidget(address_text_label) - + close_button = QPushButton("Close", self) - close_button.setStyleSheet("font-size: 14px; padding: 8px; margin: 10px;") + close_button.setStyleSheet( + "font-size: 14px; padding: 8px; margin: 10px;") close_button.clicked.connect(self.close) layout.addWidget(close_button) - + self.setStyleSheet(""" QDialog { background-color: #2c3e50; @@ -9468,7 +10061,7 @@ class QRCodeDialog(QDialog): border-radius: 10px; } """) - + def generate_qr_code(self, text, full_amount): qr = qrcode.QRCode( version=1, @@ -9476,7 +10069,7 @@ class QRCodeDialog(QDialog): box_size=8, border=4, ) - + if self.currency_type: currency_lower = self.currency_type.lower() if currency_lower == 'bitcoin': @@ -9491,25 +10084,24 @@ class QRCodeDialog(QDialog): qr_data = f"{text}?amount={full_amount}" else: qr_data = text - + qr.add_data(qr_data) qr.make(fit=True) - + qr_image = qr.make_image(fill_color="black", back_color="white") - + buffer = BytesIO() qr_image.save(buffer, format='PNG') buffer.seek(0) - + pixmap = QPixmap() pixmap.loadFromData(buffer.getvalue()) - - return pixmap.scaled(150, 150, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) + return pixmap.scaled(150, 150, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) if __name__ == "__main__": app = QApplication(sys.argv) window = CustomWindow() window.show() - sys.exit(app.exec()) \ No newline at end of file + sys.exit(app.exec())