From 93c37a905b55d17a8e4292ff5a7e296fc6e2cbfc Mon Sep 17 00:00:00 2001 From: Xarkam Date: Fri, 20 Mar 2026 11:26:56 +0100 Subject: [PATCH] Fix server handler on .exe, add hazard stripe button --- La Tanière Launcher.spec | 21 ++++++++-- src/config/constants.py | 2 +- src/discord/discord_oauth.py | 7 ++-- src/discord/discord_tools.py | 2 +- src/ui/custom_message_box.py | 1 - src/ui/hazard_stripes.py | 75 ++++++++++++++++++++++++++++++++++++ src/ui/main_window.py | 28 +++++++++++++- styles/styles.qss | 19 +++++++-- 8 files changed, 140 insertions(+), 15 deletions(-) create mode 100644 src/ui/hazard_stripes.py diff --git a/La Tanière Launcher.spec b/La Tanière Launcher.spec index c00ce85..a79f2f7 100644 --- a/La Tanière Launcher.spec +++ b/La Tanière Launcher.spec @@ -8,7 +8,11 @@ a = Analysis( ('.\\styles\\styles.qss', 'styles'), ('.\\ui\\mainwindow_vertical_pager.ui', 'ui') ], - hiddenimports=[], + hiddenimports=[ + "asyncio", + "pypresence", + "pypresence.baseclient", + ], hookspath=[], hooksconfig={ "qt_plugins": ["platforms", "styles"] @@ -107,8 +111,8 @@ a = Analysis( # Concurrency non utilisée dans ton code "multiprocessing", - "concurrent", - "asyncio", + #"concurrent", + #"asyncio", # REPL / terminal "readline", @@ -218,6 +222,15 @@ 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')] + + pyz = PYZ(a.pure, a.zipped_data) exe = EXE( @@ -243,7 +256,7 @@ exe = EXE( "msvcp*.dll", ], runtime_tmpdir=None, - console=True, + console=False, disable_windowed_traceback=True, argv_emulation=False, target_arch=None, diff --git a/src/config/constants.py b/src/config/constants.py index 14c4b31..c22227e 100644 --- a/src/config/constants.py +++ b/src/config/constants.py @@ -7,7 +7,7 @@ from PySide6.QtGui import QColor # --------------------------------------------------------------------------- NO_STAFF = True -NO_WHITELIST = True +NO_WHITELIST = False REDIRECT_URI = "http://localhost:5000/callback" SCOPES = ["identify"] diff --git a/src/discord/discord_oauth.py b/src/discord/discord_oauth.py index 4e78cb1..b52d128 100644 --- a/src/discord/discord_oauth.py +++ b/src/discord/discord_oauth.py @@ -12,6 +12,10 @@ os.environ['PYTHONWARNINGS'] = 'ignore' class OAuthCallbackHandler(BaseHTTPRequestHandler): code: str | None = None + # Ajoute ceci pour empêcher le serveur d'écrire dans la console/stderr + def log_message(self, format, *args): + return # Ne fait rien, donc pas de blocage sur stdout/stderr + def do_GET(self): """ callback pour discord auth @@ -55,9 +59,6 @@ def get_discord_user_id() -> str: webbrowser.open(f"{auth_url}?{urlencode(params)}") server = HTTPServer(("localhost", 5000), OAuthCallbackHandler) - # la ligne suivante sert à cacher le stderr output pour ne pas afficher l'url de callback dans la console - # valable en debug mode - os.dup2(os.open(os.devnull, os.O_WRONLY), 2) server.handle_request() if not OAuthCallbackHandler.code: diff --git a/src/discord/discord_tools.py b/src/discord/discord_tools.py index 26f76b4..f0e3d94 100644 --- a/src/discord/discord_tools.py +++ b/src/discord/discord_tools.py @@ -1,6 +1,6 @@ import psutil -from pypresence.presence import Presence +from pypresence import Presence from fivemserver.get_server_token import GetServerTokenForDiscord from config.constants import Urls from discord.discord_oauth import CLIENT_ID diff --git a/src/ui/custom_message_box.py b/src/ui/custom_message_box.py index e196f45..e7abe2c 100644 --- a/src/ui/custom_message_box.py +++ b/src/ui/custom_message_box.py @@ -1,4 +1,3 @@ -import sys from PySide6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QWidget, QGraphicsDropShadowEffect) from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve diff --git a/src/ui/hazard_stripes.py b/src/ui/hazard_stripes.py new file mode 100644 index 0000000..9fb5172 --- /dev/null +++ b/src/ui/hazard_stripes.py @@ -0,0 +1,75 @@ +# ui/hazard_stripes.py + +from PySide6.QtWidgets import QPushButton, QStyleOptionButton, QStyle +from PySide6.QtGui import QPainter, QColor, QPainterPath, QPen, QPolygon +from PySide6.QtCore import Qt, QPoint + + +class HazardButton(QPushButton): + def __init__(self, parent=None): + super().__init__(parent) + self._hazard = False + + def set_hazard(self, enabled: bool): + self._hazard = enabled + self.update() + + def paintEvent(self, event): + if not hasattr(self, '_hazard'): + self.__dict__['_hazard'] = False + + p = QPainter(self) + p.setRenderHint(QPainter.RenderHint.Antialiasing) + + r = self.rect() + radius = 4 + + path = QPainterPath() + path.addRoundedRect(r, radius, radius) + p.setClipPath(path) + + if self._hazard: + p.fillRect(r, QColor("#FFD700")) + + p.setPen(Qt.PenStyle.NoPen) + p.setBrush(QColor("#000000")) + + stripe_width = 20 + stripe_gap = 30 + period = stripe_width + stripe_gap + diag = r.width() + r.height() + + for x in range(-diag, diag * 2, period): + stripe = QPolygon([ + QPoint(x, r.bottom() + 10), + QPoint(x + stripe_width, r.bottom() + 10), + QPoint(x + stripe_width + r.height() + 10, r.top() - 10), + QPoint(x + r.height() + 10, r.top() - 10), + ]) + p.drawPolygon(stripe) + + # ↓ Fond semi-transparent derrière le texte + text_bg = QColor(255, 215, 0, 230) # noir à 63% d'opacité + p.setPen(Qt.PenStyle.NoPen) + p.setBrush(text_bg) + bg_rect = r.adjusted(60, 8, -60, -8) # marges internes + p.drawRoundedRect(bg_rect, 4, 4) + + else: + p.fillRect(r, QColor("#FFD700")) + + p.setClipping(False) + p.setPen(QPen(QColor("#000000"), 2)) + p.setBrush(Qt.BrushStyle.NoBrush) + p.drawRoundedRect(r.adjusted(1, 1, -1, -1), radius, radius) + + p.setClipping(False) + opt = QStyleOptionButton() + self.initStyleOption(opt) + opt.palette.setColor( + opt.palette.ColorRole.ButtonText, + self.palette().color(self.palette().ColorRole.ButtonText) + ) + self.style().drawControl( + QStyle.ControlElement.CE_PushButtonLabel, opt, p, self + ) diff --git a/src/ui/main_window.py b/src/ui/main_window.py index 53ef5bd..a3594c7 100644 --- a/src/ui/main_window.py +++ b/src/ui/main_window.py @@ -8,12 +8,13 @@ from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QMainWindow, QSizePolicy from config.config_manager import ConfigManager +from config.constants import NO_STAFF, Urls, NO_WHITELIST +from ui.custom_message_box import CustomMessageBox +from ui.hazard_stripes import HazardButton from controllers.audio_controller import AudioController from controllers.glow_animator import GlowAnimator from controllers.window_dragger import WindowDragger from discord import discord_oauth -from config.constants import NO_STAFF, Urls, NO_WHITELIST -from ui.custom_message_box import CustomMessageBox from tools.utils import quit_application from fake_patch_notes import patch_note @@ -34,6 +35,29 @@ class MainWindow(QMainWindow): self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Window) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) + # Test bouton en contruction + en_chantier = True + if en_chantier: + old_btn = self.ui.connexion_btn + parent_layout = self.ui.verticalLayout_6 # layout direct du bouton dans le .ui + + index = parent_layout.indexOf(old_btn) + + new_btn = HazardButton(old_btn.parentWidget()) + new_btn.setObjectName("connexion_btn") + new_btn.setText("EN MAINTENANCE") + new_btn.setIcon(old_btn.icon()) + new_btn.setIconSize(old_btn.iconSize()) + new_btn.setMinimumSize(old_btn.minimumSize()) + new_btn.set_hazard(True) + + parent_layout.takeAt(index) + old_btn.deleteLater() + parent_layout.insertWidget(index, new_btn) + + self.ui.connexion_btn = new_btn + self.ui.connexion_btn.clicked.connect(self._on_connexion) + # centrage vertical du bouton connexion if NO_STAFF: self.ui.staff_btn.hide() diff --git a/styles/styles.qss b/styles/styles.qss index a15623c..1a60377 100644 --- a/styles/styles.qss +++ b/styles/styles.qss @@ -45,7 +45,7 @@ QLabel#queue_lbl { } -QPushButton#connexion_btn { +QPushButton#connexion_btn[chantier="false"] { /* Dégradé chaleureux : Orange vers Orange-Rouge */ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop: 0 #ff9d00, @@ -57,7 +57,7 @@ QPushButton#connexion_btn { padding: 10px; } -QPushButton#connexion_btn:hover { +QPushButton#connexion_btn[chantier="false"]:hover { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop: 0 #ffb338, stop: 1 #ff7a29); @@ -66,7 +66,7 @@ QPushButton#connexion_btn:hover { outline: none; } -QPushButton#connexionBtn:pressed { +QPushButton#connexion_btn[chantier="false"]:pressed { background: #cc5200; padding-top: 12px; /* Effet d'enfoncement */ } @@ -81,6 +81,19 @@ QPushButton#staff_btn { padding: 5px 15px; } +HazardButton#connexion_btn { + color: rgb(0, 0, 0); + font-weight: bold; +} + +HazardButton#connexion_btn:hover { + color: #ffffff; +} + +HazardButton#connexion_btn:pressed { + color: #333333; +} + QPushButton#staff_btn:hover { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FF6046, stop:1 #FF527B);