diff --git a/.gitignore b/.gitignore index 103e267..1ad4954 100644 --- a/.gitignore +++ b/.gitignore @@ -400,3 +400,4 @@ http-client.private.env.json # Github Copilot persisted session migrations, see: https://github.com/microsoft/copilot-intellij-feedback/issues/712#issuecomment-3322062215 .idea/**/copilot.data.migration.*.xml src/config.json +config.json diff --git a/src/config/config_manager.py b/src/config/config_manager.py index 8dc3015..c0dc2ad 100644 --- a/src/config/config_manager.py +++ b/src/config/config_manager.py @@ -2,20 +2,7 @@ import json from pathlib import Path from typing import Any, Callable, NotRequired, TypedDict, cast -# Configuration du chemin du fichier de configuration avec son nom. -def _get_config_path() -> Path: - from sys import argv, executable - import os - import sys - from pathlib import Path - - # Si l'app est packagée (PyInstaller) - if getattr(sys, "frozen", False): - base_path = Path(executable).parent - else: - base_path = Path(os.path.realpath(argv[0])).parent - - return base_path / "config.json" +from utils import get_bundle_dir class ConfigData(TypedDict): discord_user_id: NotRequired[str] @@ -29,7 +16,7 @@ class ConfigField(TypedDict): validator: Validator normalizer: Normalizer -CONFIG_PATH = _get_config_path() +CONFIG_PATH = get_bundle_dir() / "config.json" DISCORD_USER_KEY = "discord_user_id" VOLUME_KEY = "volume" @@ -49,7 +36,7 @@ CONFIG_SCHEMA: dict[str, ConfigField] = { class ConfigManager: def __init__(self, path: Path | None = None) -> None: - self.path = path or _get_config_path() + self.path = path or CONFIG_PATH self._data: ConfigData = self._load() self._dirty = False diff --git a/src/constants.py b/src/constants.py index eae8571..81daa54 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,20 +1,27 @@ +from enum import Enum + from PySide6.QtGui import QColor # --------------------------------------------------------------------------- # Constants # --------------------------------------------------------------------------- -URLS = { - "discord": "https://discord.gg/A7eanmSkp2", - "intranet": "https://la-taniere.fun/connexion/", -} - -RESOURCES_MP3 = ":/assets/the-beat-of-nature.mp3" -RESOURCES_FONT = ":/assets/Avocado-Cake-Demo.otf" - -GLOW_COLOR = QColor(255, 140, 0, 255) -GLOW_BLUR_BASE = 15 -GLOW_BLUR_PEAK = 70 -GLOW_ANIM_DURATION = 1200 NO_STAFF = True NO_DISCORD = True + +# --------------------------------------------------------------------------- +# ENUMS +# --------------------------------------------------------------------------- +class Resources(Enum): + MP3 = ":/assets/the-beat-of-nature.mp3" + FONT = ":/assets/Avocado-Cake-Demo.otf" + +class Urls(Enum): + DISCORD = "https://discord.gg/A7eanmSkp2" + INTRANET = "https://la-taniere.fun/connexion/" + +class Glow(Enum): + COLOR = QColor(255, 140, 0, 255) + BLUR_BASE = 15 + BLUR_PEAK = 70 + ANIM_DURATION = 1200 diff --git a/src/controllers/audio_controller.py b/src/controllers/audio_controller.py index 2e367d4..fe772a6 100644 --- a/src/controllers/audio_controller.py +++ b/src/controllers/audio_controller.py @@ -3,7 +3,7 @@ from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput from config.config_manager import ConfigManager, VOLUME_KEY -from constants import RESOURCES_MP3 +from constants import Resources class AudioController: # Encapsule toute la logique audio : lecture, volume, mute. @@ -20,7 +20,7 @@ class AudioController: self._player.setLoops(-1) # Chargement du MP3 depuis les ressources Qt - mp3file = QFile(RESOURCES_MP3) + mp3file = QFile(Resources.MP3.value) mp3file.open(QFile.ReadOnly) mp3data = mp3file.readAll() mp3file.close() diff --git a/src/controllers/glow_animator.py b/src/controllers/glow_animator.py index 46a903c..ffc1caf 100644 --- a/src/controllers/glow_animator.py +++ b/src/controllers/glow_animator.py @@ -1,7 +1,7 @@ from PySide6.QtCore import QPropertyAnimation, QEasingCurve from PySide6.QtWidgets import QGraphicsDropShadowEffect -from constants import GLOW_COLOR, GLOW_BLUR_BASE, GLOW_BLUR_PEAK, GLOW_ANIM_DURATION +from constants import Glow class GlowAnimator: @@ -11,15 +11,15 @@ class GlowAnimator: self._widget = widget self._effect = QGraphicsDropShadowEffect(widget) - self._effect.setBlurRadius(GLOW_BLUR_BASE) + self._effect.setBlurRadius(Glow.BLUR_BASE.value) self._effect.setOffset(0, 0) - self._effect.setColor(GLOW_COLOR) + self._effect.setColor(Glow.COLOR.value) self._anim = QPropertyAnimation(self._effect, b"blurRadius") - self._anim.setDuration(GLOW_ANIM_DURATION) - self._anim.setStartValue(GLOW_BLUR_BASE) - self._anim.setKeyValueAt(0.5, GLOW_BLUR_PEAK) - self._anim.setEndValue(GLOW_BLUR_BASE) + self._anim.setDuration(Glow.ANIM_DURATION.value) + self._anim.setStartValue(Glow.BLUR_BASE.value) + self._anim.setKeyValueAt(0.5, Glow.BLUR_PEAK.value) + self._anim.setEndValue(Glow.BLUR_BASE.value) self._anim.setEasingCurve(QEasingCurve.InOutQuad) self._anim.setLoopCount(-1) diff --git a/src/main.py b/src/main.py index b429bab..75e27f4 100644 --- a/src/main.py +++ b/src/main.py @@ -1,5 +1,5 @@ import sys -from pathlib import Path +from utils import get_bundle_dir from PySide6.QtCore import QResource from PySide6.QtGui import QFontDatabase, QFont @@ -9,16 +9,13 @@ from PySide6.QtWidgets import QApplication import resources # noqa: F401 - required to register Qt resources from ui.main_window import MainWindow -from constants import RESOURCES_FONT +from constants import Resources # --------------------------------------------------------------------------- # Bundle path resolution # --------------------------------------------------------------------------- -if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'): - bundle_dir = Path(sys._MEIPASS) -else: - bundle_dir = Path(__file__).resolve().parent.parent +bundle_dir = get_bundle_dir() QResource.registerResource(f"{bundle_dir}/resources.py") @@ -28,7 +25,7 @@ QResource.registerResource(f"{bundle_dir}/resources.py") # --------------------------------------------------------------------------- def load_custom_font() -> str: - font_id = QFontDatabase.addApplicationFont(RESOURCES_FONT) + font_id = QFontDatabase.addApplicationFont(Resources.FONT.value) if font_id == -1: raise RuntimeError("Failed to load font from resources.") font_families = QFontDatabase.applicationFontFamilies(font_id) diff --git a/src/ui/main_window.py b/src/ui/main_window.py index bb4c602..0c7b621 100644 --- a/src/ui/main_window.py +++ b/src/ui/main_window.py @@ -8,7 +8,7 @@ from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QMainWindow, QSizePolicy from config.config_manager import ConfigManager -from constants import NO_DISCORD, URLS, NO_STAFF +from constants import NO_DISCORD, NO_STAFF, Urls from controllers.audio_controller import AudioController from controllers.glow_animator import GlowAnimator from controllers.window_dragger import WindowDragger @@ -91,10 +91,10 @@ class MainWindow(QMainWindow): @staticmethod def _on_discord() -> None: - webbrowser.open(URLS["discord"]) + webbrowser.open(Urls.DISCORD.value) def _on_intranet(self) -> None: - webbrowser.open(URLS["intranet"]) + webbrowser.open(Urls.INTRANET.value) self._glow.start() def _on_discord_auth_btn(self) -> None: diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..5a7d6ef --- /dev/null +++ b/src/utils.py @@ -0,0 +1,7 @@ +import sys +from pathlib import Path + +def get_bundle_dir() -> Path: + if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'): + return Path(sys._MEIPASS) + return Path(__file__).resolve().parent.parent