PythonApplicationTemplate/app/ui/windows/activation_window.py
2025-10-30 18:10:23 +01:00

241 lines
10 KiB
Python

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()