Fix server handler on .exe, add hazard stripe button

This commit is contained in:
2026-03-20 11:26:56 +01:00
parent 945abae5f1
commit 93c37a905b
8 changed files with 140 additions and 15 deletions

View File

@@ -8,7 +8,11 @@ a = Analysis(
('.\\styles\\styles.qss', 'styles'), ('.\\styles\\styles.qss', 'styles'),
('.\\ui\\mainwindow_vertical_pager.ui', 'ui') ('.\\ui\\mainwindow_vertical_pager.ui', 'ui')
], ],
hiddenimports=[], hiddenimports=[
"asyncio",
"pypresence",
"pypresence.baseclient",
],
hookspath=[], hookspath=[],
hooksconfig={ hooksconfig={
"qt_plugins": ["platforms", "styles"] "qt_plugins": ["platforms", "styles"]
@@ -107,8 +111,8 @@ a = Analysis(
# Concurrency non utilisée dans ton code # Concurrency non utilisée dans ton code
"multiprocessing", "multiprocessing",
"concurrent", #"concurrent",
"asyncio", #"asyncio",
# REPL / terminal # REPL / terminal
"readline", "readline",
@@ -218,6 +222,15 @@ a.binaries = [
if not any(u.lower() in name.lower() for u in unwanted_dlls) 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) pyz = PYZ(a.pure, a.zipped_data)
exe = EXE( exe = EXE(
@@ -243,7 +256,7 @@ exe = EXE(
"msvcp*.dll", "msvcp*.dll",
], ],
runtime_tmpdir=None, runtime_tmpdir=None,
console=True, console=False,
disable_windowed_traceback=True, disable_windowed_traceback=True,
argv_emulation=False, argv_emulation=False,
target_arch=None, target_arch=None,

View File

@@ -7,7 +7,7 @@ from PySide6.QtGui import QColor
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
NO_STAFF = True NO_STAFF = True
NO_WHITELIST = True NO_WHITELIST = False
REDIRECT_URI = "http://localhost:5000/callback" REDIRECT_URI = "http://localhost:5000/callback"
SCOPES = ["identify"] SCOPES = ["identify"]

View File

@@ -12,6 +12,10 @@ os.environ['PYTHONWARNINGS'] = 'ignore'
class OAuthCallbackHandler(BaseHTTPRequestHandler): class OAuthCallbackHandler(BaseHTTPRequestHandler):
code: str | None = None 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): def do_GET(self):
""" """
callback pour discord auth callback pour discord auth
@@ -55,9 +59,6 @@ def get_discord_user_id() -> str:
webbrowser.open(f"{auth_url}?{urlencode(params)}") webbrowser.open(f"{auth_url}?{urlencode(params)}")
server = HTTPServer(("localhost", 5000), OAuthCallbackHandler) 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() server.handle_request()
if not OAuthCallbackHandler.code: if not OAuthCallbackHandler.code:

View File

@@ -1,6 +1,6 @@
import psutil import psutil
from pypresence.presence import Presence from pypresence import Presence
from fivemserver.get_server_token import GetServerTokenForDiscord from fivemserver.get_server_token import GetServerTokenForDiscord
from config.constants import Urls from config.constants import Urls
from discord.discord_oauth import CLIENT_ID from discord.discord_oauth import CLIENT_ID

View File

@@ -1,4 +1,3 @@
import sys
from PySide6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, from PySide6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QWidget, QGraphicsDropShadowEffect) QLabel, QPushButton, QWidget, QGraphicsDropShadowEffect)
from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve

75
src/ui/hazard_stripes.py Normal file
View File

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

View File

@@ -8,12 +8,13 @@ from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QMainWindow, QSizePolicy from PySide6.QtWidgets import QMainWindow, QSizePolicy
from config.config_manager import ConfigManager 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.audio_controller import AudioController
from controllers.glow_animator import GlowAnimator from controllers.glow_animator import GlowAnimator
from controllers.window_dragger import WindowDragger from controllers.window_dragger import WindowDragger
from discord import discord_oauth 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 tools.utils import quit_application
from fake_patch_notes import patch_note from fake_patch_notes import patch_note
@@ -34,6 +35,29 @@ class MainWindow(QMainWindow):
self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Window) self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Window)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) 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 # centrage vertical du bouton connexion
if NO_STAFF: if NO_STAFF:
self.ui.staff_btn.hide() self.ui.staff_btn.hide()

View File

@@ -45,7 +45,7 @@ QLabel#queue_lbl {
} }
QPushButton#connexion_btn { QPushButton#connexion_btn[chantier="false"] {
/* Dégradé chaleureux : Orange vers Orange-Rouge */ /* Dégradé chaleureux : Orange vers Orange-Rouge */
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop: 0 #ff9d00, stop: 0 #ff9d00,
@@ -57,7 +57,7 @@ QPushButton#connexion_btn {
padding: 10px; padding: 10px;
} }
QPushButton#connexion_btn:hover { QPushButton#connexion_btn[chantier="false"]:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop: 0 #ffb338, stop: 0 #ffb338,
stop: 1 #ff7a29); stop: 1 #ff7a29);
@@ -66,7 +66,7 @@ QPushButton#connexion_btn:hover {
outline: none; outline: none;
} }
QPushButton#connexionBtn:pressed { QPushButton#connexion_btn[chantier="false"]:pressed {
background: #cc5200; background: #cc5200;
padding-top: 12px; /* Effet d'enfoncement */ padding-top: 12px; /* Effet d'enfoncement */
} }
@@ -81,6 +81,19 @@ QPushButton#staff_btn {
padding: 5px 15px; 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 { QPushButton#staff_btn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF6046, stop:1 #FF527B); stop:0 #FF6046, stop:1 #FF527B);