diff --git a/build.sh b/build.sh index 4100244..79b8afb 100755 --- a/build.sh +++ b/build.sh @@ -100,8 +100,9 @@ if [ "$OS" = "darwin" ]; then mv "$PRODUCED" "$APP" fi - echo "[build] sembrando games.toml en Contents/Resources…" + echo "[build] sembrando games.toml y icon.png en Contents/Resources…" cp games.toml "$APP/Contents/Resources/games.toml" + cp assets/icon.png "$APP/Contents/Resources/icon.png" # usado por el diálogo «Quant a» # Bundle ad-hoc (sin Developer ID): quitamos quarantine para abrir sin fricción local. xattr -dr com.apple.quarantine "$APP" 2>/dev/null || true diff --git a/jlauncher/__main__.py b/jlauncher/__main__.py index b27ffe9..7821a79 100644 --- a/jlauncher/__main__.py +++ b/jlauncher/__main__.py @@ -4,10 +4,11 @@ from __future__ import annotations import sys +from PySide6.QtGui import QIcon from PySide6.QtWidgets import QApplication, QMessageBox from .config import load_config -from .paths import config_file, data_root +from .paths import app_icon_path, config_file, data_root from .ui.main_window import MainWindow from .ui.theme import apply_theme @@ -15,6 +16,9 @@ from .ui.theme import apply_theme def main() -> int: app = QApplication(sys.argv) app.setApplicationName("jlauncher") + icon_path = app_icon_path() + if icon_path is not None: + app.setWindowIcon(QIcon(str(icon_path))) # Tema del sistema para el posible diálogo de error previo a la ventana; # MainWindow re-aplica el modo guardado (system/light/dark) y vigila los cambios. apply_theme(app) diff --git a/jlauncher/paths.py b/jlauncher/paths.py index d50f58e..b15dc17 100644 --- a/jlauncher/paths.py +++ b/jlauncher/paths.py @@ -55,6 +55,20 @@ def macos_app_bundle() -> Path | None: return None +def app_icon_path() -> Path | None: + """Ruta al PNG del icono para la UI (icono de ventana/Dock y diálogo «Quant a»). + + En .app vive en ``Contents/Resources/icon.png``; desde fuente, en ``assets/icon.png``. + Devuelve None si no se encuentra. + """ + bundle = macos_app_bundle() + if bundle is not None: + candidate = bundle / "Contents" / "Resources" / "icon.png" + else: + candidate = base_dir() / "assets" / "icon.png" + return candidate if candidate.exists() else None + + def support_dir() -> Path: """Carpeta de soporte escribible en macOS (.app); se crea si no existe.""" root = ( diff --git a/jlauncher/ui/main_window.py b/jlauncher/ui/main_window.py index c17372d..768f750 100644 --- a/jlauncher/ui/main_window.py +++ b/jlauncher/ui/main_window.py @@ -5,10 +5,14 @@ from __future__ import annotations from pathlib import Path from PySide6.QtCore import QEasingCurve, QPropertyAnimation, QThreadPool, Qt, QTimer -from PySide6.QtGui import QAction, QActionGroup +from PySide6.QtGui import QAction, QActionGroup, QPixmap from PySide6.QtWidgets import ( QApplication, + QDialog, + QDialogButtonBox, + QHBoxLayout, QInputDialog, + QLabel, QLineEdit, QMainWindow, QMessageBox, @@ -21,6 +25,7 @@ from PySide6.QtWidgets import ( from .. import __version__, gitops from ..config import Config, Game +from ..paths import app_icon_path from ..settings import load_settings, save_settings from ..workers import CheckUpdatesWorker, DownloadWorker, RunWorker from . import theme @@ -257,13 +262,73 @@ class MainWindow(QMainWindow): help_menu.addAction(self.action_about) def _show_about(self) -> None: - QMessageBox.about( - self, - f"Quant a {APP_NAME}", - f"{APP_NAME}
" - f"Versió {__version__}

" - "© 2026 JailDesigner", - ) + """Diàleg «Quant a» personalitzat: icona, nom gran i tot centrat.""" + dlg = QDialog(self) + dlg.setWindowTitle(f"Quant a {APP_NAME}") + dlg.setModal(True) + + lay = QVBoxLayout(dlg) + lay.setContentsMargins(40, 30, 40, 24) + lay.setSpacing(0) + + # Logo (si el trobem); s'escala suau des del PNG gran. + icon_path = app_icon_path() + if icon_path is not None: + pix = QPixmap(str(icon_path)) + if not pix.isNull(): + logo = QLabel(alignment=Qt.AlignCenter) + logo.setPixmap( + pix.scaled( + 96, 96, Qt.KeepAspectRatio, Qt.SmoothTransformation + ) + ) + lay.addWidget(logo) + lay.addSpacing(16) + + # Nom de l'app: gran, en negreta i amb el morat de la marca. + name = QLabel(APP_NAME, alignment=Qt.AlignCenter) + nf = name.font() + nf.setPointSize(nf.pointSize() + 13) + nf.setBold(True) + name.setFont(nf) + name.setStyleSheet("color: #7c4dff;") + lay.addWidget(name) + lay.addSpacing(4) + + # Versió en cursiva i atenuada. + ver = QLabel(f"Versió {__version__}", alignment=Qt.AlignCenter) + vf = ver.font() + vf.setItalic(True) + vf.setPointSize(vf.pointSize() + 1) + ver.setFont(vf) + ver.setStyleSheet("color: #8a8a8a;") + lay.addWidget(ver) + lay.addSpacing(18) + + # Lema discret. + tag = QLabel("Clona, compila i juga · jailgames", alignment=Qt.AlignCenter) + tag.setStyleSheet("color: #8a8a8a;") + lay.addWidget(tag) + lay.addSpacing(14) + + copy = QLabel("© 2026 JailDesigner", alignment=Qt.AlignCenter) + cf = copy.font() + cf.setPointSize(cf.pointSize() - 1) + copy.setFont(cf) + lay.addWidget(copy) + lay.addSpacing(24) + + # Botó OK centrat. + buttons = QDialogButtonBox(QDialogButtonBox.Ok) + buttons.button(QDialogButtonBox.Ok).setText("D'acord") + buttons.accepted.connect(dlg.accept) + row = QHBoxLayout() + row.addStretch(1) + row.addWidget(buttons) + row.addStretch(1) + lay.addLayout(row) + + dlg.exec() def _build_theme_menu(self, parent_menu) -> None: """Submenú Tema amb tres opcions exclusives: Sistema / Clar / Fosc."""