diff --git a/La Tanière Launcher.spec b/La Tanière Launcher.spec index 110236a..789382d 100644 --- a/La Tanière Launcher.spec +++ b/La Tanière Launcher.spec @@ -1,23 +1,45 @@ # -*- mode: python ; coding: utf-8 -*- +import os +from pathlib import Path + +# 🔥 Base path fiable (indépendant du dossier de lancement) +BASE_DIR = Path(os.getcwd()).resolve() + +if not (BASE_DIR / "src").exists(): + raise Exception("Lance PyInstaller depuis la racine du projet") + +print("BASE_DIR =", BASE_DIR) + +# ------------------------------------------------------------------ +# Analysis +# ------------------------------------------------------------------ a = Analysis( - ['src\\main.py'], + [str(BASE_DIR / 'src' / 'main.py')], pathex=['src'], binaries=[], datas=[ - ('.\\styles\\styles.qss', 'styles'), - ('.\\ui\\mainwindow_vertical_pager.ui', 'ui') + # Assets critiques + (str(BASE_DIR / 'assets' / 'Icon.ico'), 'assets'), + + # Styles + (str(BASE_DIR / 'styles' / 'styles.qss'), 'styles'), + + # UI (tu peux ajouter d'autres .ui ici) + (str(BASE_DIR / 'ui' / 'mainwindow_vertical_pager.ui'), 'ui'), ], hiddenimports=[ "asyncio", - "pypresence", - "pypresence.baseclient", + "pypresence" ], hookspath=[], hooksconfig={ - "qt_plugins": ["platforms", "styles"] + # 🔥 STRICT MINIMUM + "qt_plugins": ["platforms"] }, runtime_hooks=[], + + # 🔥 Exclusions excludes=[ # PySide6 - modules non utilisés 'PySide6.Qt3DAnimation', @@ -173,8 +195,9 @@ a = Analysis( optimize=2, ) -# --- Filtre des DLLs Qt inutiles --- -# Ces DLLs sont incluses par analyse binaire malgré les excludes Python +# ------------------------------------------------------------------ +# 🔥 Nettoyage DLL Qt (SAFE) +# ------------------------------------------------------------------ unwanted_dlls = [ 'Qt6Pdf', 'Qt6Quick', @@ -222,13 +245,13 @@ a.binaries = [ if not any(u.lower() in name.lower() for u in unwanted_dlls) ] -# AJOUTE CECI ICI : -# On filtre la liste des fichiers de données (datas) -# On exclut tout ce qui se trouve dans le dossier 'translations' de PySide6 -a.datas = [f for f in a.datas if "translations" not in f[0].lower()] - -# Si tu veux aussi supprimer les traductions système de Qt (fichiers .qm) -a.datas = [f for f in a.datas if not f[0].endswith('.qm')] +# ------------------------------------------------------------------ +# 🔥 Suppression traductions Qt (gain taille) +# ------------------------------------------------------------------ +a.datas = [ + f for f in a.datas + if "translations" not in f[0].lower() and not f[0].endswith('.qm') +] pyz = PYZ(a.pure, a.zipped_data) @@ -243,6 +266,8 @@ exe = EXE( debug=False, bootloader_ignore_signals=False, strip=False, + + # 🔥 Compression max upx=True, upx_exclude=[ "_uuid.pyd", @@ -256,11 +281,17 @@ exe = EXE( "msvcp*.dll", ], runtime_tmpdir=None, - console=True, + console=False, + + # 🔥 ONEFILE + onefile=True, + disable_windowed_traceback=True, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, - icon=['assets\\Icon.ico'], + + # 🔥 Icône EXE (important mais pas suffisant seul) + icon=str(BASE_DIR / 'assets' / 'Icon.ico'), ) diff --git a/src/main.py b/src/main.py index 2c23996..1cb570d 100644 --- a/src/main.py +++ b/src/main.py @@ -1,8 +1,12 @@ +import ctypes import sys +import os +import tempfile + from tools.utils import get_internal_dir from PySide6.QtCore import QResource -from PySide6.QtGui import QFontDatabase, QFont +from PySide6.QtGui import QFontDatabase, QFont, QIcon from PySide6.QtWidgets import QApplication # Imports pour la gestion de la configuration @@ -19,6 +23,8 @@ from ui.main_window import MainWindow # Ne pas supprimer ! Enregistre les ressources Qt import resources # noqa: F401 - required to register Qt resources +if getattr(sys, 'frozen', False): + os.environ["TMPDIR"] = tempfile.gettempdir() # --------------------------------------------------------------------------- # Bundle path resolution @@ -26,6 +32,11 @@ import resources # noqa: F401 - required to register Qt resources bundle_dir = get_internal_dir() QResource.registerResource(f"{bundle_dir}/resources.py") +# --------------------------------------------------------------------------- +# Fix barre des tâches Windows +# --------------------------------------------------------------------------- +if sys.platform.startswith("win"): + ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("LaTaniere.Launcher.1") # --------------------------------------------------------------------------- # Font helper @@ -46,6 +57,10 @@ def load_custom_font() -> str: if __name__ == "__main__": app = QApplication(sys.argv) + # Icône sur l'application ET la barre des tâches + icon = QIcon(str(get_internal_dir() / "assets" / "Icon.ico")) + app.setWindowIcon(icon) + # 1. Initialisation UNIQUE du gestionnaire de config config = ConfigManager() @@ -89,6 +104,7 @@ if __name__ == "__main__": # 4. Lancement de l'application si tout est OK window = MainWindow(bundle_dir, config) + window.setWindowIcon(icon) # 🔥 important # Note: Assure-toi que self.show() est bien dans le __init__ de MainWindow # ou ajoute window.show() ici si tu l'en lèves du constructeur. diff --git a/src/ui/main_window.py b/src/ui/main_window.py index 8dbed67..1ebe4d5 100644 --- a/src/ui/main_window.py +++ b/src/ui/main_window.py @@ -3,6 +3,7 @@ from sys import platform from os import environ from PySide6 import QtGui +from PySide6.QtGui import QIcon from PySide6.QtCore import Qt, QTimer from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QMainWindow, QSizePolicy @@ -47,6 +48,8 @@ class MainWindow(QMainWindow): self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Window) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) + self.setWindowIcon(QIcon(str(bundle_dir / "assets" / "Icon.ico"))) + # Par défaut on affiche la page normal pour la connexion au serveur self.ui.stackedWidget.setCurrentIndex(0) # On cache par défaut les infos liste d'attente