from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QFrame, QSizePolicy) from PyQt6.QtCore import Qt, QThread, pyqtSignal from app.core.main_manager import MainManager, NotificationType from app.ui.widgets.loading_bar import LoadingBar import webbrowser import os from dotenv import load_dotenv import app.utils.paths as paths # Load environment variables load_dotenv(paths.resource_path(".env")) class ActivationThread(QThread): """Thread pour l'activation afin de ne pas bloquer l'UI""" finished = pyqtSignal(dict) progress = pyqtSignal(int) def __init__(self, license_manager, license_key): super().__init__() self.license_manager = license_manager self.license_key = license_key def run(self): self.progress.emit(30) result = self.license_manager.activate_license(self.license_key) self.progress.emit(100) self.finished.emit(result) class ActivationWindow(QWidget): """Fenêtre d'activation de licence modernisée""" def __init__(self, parent=None): super().__init__(parent) self.main_manager = MainManager.get_instance() self.license_manager = self.main_manager.get_license_manager() self.language_manager = self.main_manager.get_language_manager() self.theme_manager = self.main_manager.get_theme_manager() self.alert_manager = self.main_manager.get_alert_manager() self.observer_manager = self.main_manager.get_observer_manager() self.settings_manager = self.main_manager.get_settings_manager() self.observer_manager.subscribe(NotificationType.LANGUAGE, self.update_language) self.observer_manager.subscribe(NotificationType.THEME, self.update_theme) self.activation_thread = None self.setup_ui() self.update_license_status() def setup_ui(self): layout = QVBoxLayout(self) layout.setSpacing(20) layout.setContentsMargins(20, 20, 20, 20) layout.setAlignment(Qt.AlignmentFlag.AlignTop) # === Section titre === self.title_label = QLabel(self.language_manager.get_text("activate_license")) self.title_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) self.title_label.setWordWrap(True) layout.addWidget(self.title_label) # === Spacer flexible === layout.addStretch(1) # === Section clé de licence === key_layout = QHBoxLayout() self.key_title = QLabel(self.language_manager.get_text("license_key_section")) self.key_title.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed) key_layout.addWidget(self.key_title) self.key_input = QLineEdit() self.key_input.setPlaceholderText("XXXX-XXXX-XXXX-XXXX-XXXX") self.key_input.textChanged.connect(self.format_license_key) self.key_input.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) key_layout.addWidget(self.key_input) layout.addLayout(key_layout) # === Barre de progression === self.progress_bar = LoadingBar(self.language_manager.get_text("loading")) self.progress_bar.setVisible(False) self.progress_bar.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) layout.addWidget(self.progress_bar) # === Spacer flexible === layout.addStretch(1) # === Section statut === self.status_label = QLabel() self.status_label.setWordWrap(True) self.status_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) layout.addWidget(self.status_label) # === Spacer flexible === layout.addStretch(1) # === Boutons d'action === button_layout = QHBoxLayout() button_layout.setSpacing(10) self.activate_btn = QPushButton(self.language_manager.get_text("activate")) self.activate_btn.clicked.connect(self.activate_license) self.activate_btn.setDefault(True) self.activate_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) button_layout.addWidget(self.activate_btn) self.buy_btn = QPushButton(self.language_manager.get_text("buy_license")) self.buy_btn.clicked.connect(self.open_purchase_page) self.buy_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) button_layout.addWidget(self.buy_btn) self.compare_btn = QPushButton(self.language_manager.get_text("compare_versions")) self.compare_btn.clicked.connect(self.show_features_comparison) self.compare_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) button_layout.addWidget(self.compare_btn) layout.addLayout(button_layout) def show_features_comparison(self): """Affiche la comparaison des versions dans une alerte""" comparison_text = f"{self.language_manager.get_text('comparaisons')}\n\n" for version in self.settings_manager.get_config("features_by_license").keys(): comparison_text += f"{self.language_manager.get_text(version+'_version')}:\n" features = self.settings_manager.get_config("features_by_license").get(version, []) for feature in features: feature_desc = self.language_manager.get_text(feature) comparison_text += f" • {feature_desc}\n" comparison_text += "\n" self.alert_manager.show_info(comparison_text, parent=self) def update_license_status(self): """Met à jour l'affichage du statut de la licence""" if self.license_manager.is_activated(): license_info = self.license_manager.get_license_info() license_type = license_info.get("type", "free").upper() status_text = f"✓ {self.language_manager.get_text('license_active')}\n" status_text += f"{self.language_manager.get_text('license_type')}: {license_type}\n" if license_info.get("email"): status_text += f"{self.language_manager.get_text('license_email')}: {license_info['email']}\n" if license_info.get("expires_at"): status_text += f"{self.language_manager.get_text('license_expires')}: {license_info['expires_at']}" self.status_label.setText(status_text) self.key_input.setEnabled(False) self.activate_btn.setEnabled(False) else: status_text = f"{self.language_manager.get_text('no_license')}" self.status_label.setText(status_text) def format_license_key(self, text): """Formate automatiquement la clé de licence (XXXX-XXXX-...)""" text = text.replace("-", "").upper() formatted = "-".join([text[i:i+4] for i in range(0, len(text), 4)]) if len(formatted) > 24: formatted = formatted[:24] self.key_input.blockSignals(True) self.key_input.setText(formatted) self.key_input.blockSignals(False) self.key_input.setCursorPosition(len(formatted)) def activate_license(self): """Lance l'activation de la licence""" license_key = self.key_input.text().replace("-", "") if len(license_key) < 16: self.alert_manager.show_error("invalid_license_key") return # Disable inputs during activation self.activate_btn.setEnabled(False) self.key_input.setEnabled(False) self.buy_btn.setEnabled(False) # Show progress bar with initial message self.progress_bar.set_label(self.language_manager.get_text("loading")) self.progress_bar.set_progress(0) self.progress_bar.setVisible(True) # Start activation thread self.activation_thread = ActivationThread(self.license_manager, license_key) self.activation_thread.finished.connect(self.on_activation_finished) self.activation_thread.progress.connect(self.on_activation_progress) self.activation_thread.start() def on_activation_progress(self, value): """Update progress bar during activation""" self.progress_bar.set_progress(value) def on_activation_finished(self, result): """Callback quand l'activation est terminée""" # Hide progress bar self.progress_bar.setVisible(False) # Re-enable inputs self.activate_btn.setEnabled(True) self.key_input.setEnabled(True) self.buy_btn.setEnabled(True) if result["success"]: # Show success message using AlertManager success_msg = result['message'] if result.get("data"): success_msg += f"\n\n{self.language_manager.get_text('license_type')}: {result['data'].get('type', 'N/A')}" success_msg += f"\n{self.language_manager.get_text('license_email')}: {result['data'].get('email', 'N/A')}" self.alert_manager.show_info(success_msg, parent=self) self.update_license_status() # Clear the input field self.key_input.clear() else: # Show error message using AlertManager self.alert_manager.show_info(f"✗ {result['message']}", parent=self) def open_purchase_page(self): """Ouvre la page d'achat dans le navigateur""" purchase_url = os.getenv("PURCHASE_URL") if purchase_url: webbrowser.open(purchase_url) else: self.alert_manager.show_error("PURCHASE_URL non définie dans .env", parent=self) def update_language(self): """Met à jour tous les textes selon la nouvelle langue""" self.title_label.setText(self.language_manager.get_text("activate_license")) self.activate_btn.setText(self.language_manager.get_text("activate")) self.buy_btn.setText(self.language_manager.get_text("buy_license")) self.compare_btn.setText(self.language_manager.get_text("compare_versions")) self.progress_bar.set_label(self.language_manager.get_text("loading")) self.key_title.setText(self.language_manager.get_text("license_key_section")) self.update_license_status() def update_theme(self): """Met à jour le style selon le nouveau thème""" self.update_license_status()