Interfície en català, botó Esborra i botons d'icona segons l'estat

This commit is contained in:
2026-05-29 21:55:34 +02:00
parent 235a3966d2
commit 694d67f11e
6 changed files with 117 additions and 45 deletions
+45 -15
View File
@@ -4,14 +4,14 @@ from __future__ import annotations
from pathlib import Path
from PySide6.QtCore import Qt, Signal
from PySide6.QtCore import QSize, Qt, Signal
from PySide6.QtGui import QPalette, QPixmap
from PySide6.QtWidgets import (
QFrame,
QHBoxLayout,
QLabel,
QPushButton,
QSizePolicy,
QStyle,
QVBoxLayout,
)
@@ -27,6 +27,7 @@ class GameRow(QFrame):
download_requested = Signal(object) # Game
run_requested = Signal(object) # Game
delete_requested = Signal(object) # Game
def __init__(self, game: Game, root: Path, parent=None) -> None:
super().__init__(parent)
@@ -63,17 +64,31 @@ class GameRow(QFrame):
text_box.addStretch(1)
layout.addLayout(text_box, stretch=1)
# --- Botones ---
self.download_btn = QPushButton("Download")
self.run_btn = QPushButton("Run")
for btn in (self.download_btn, self.run_btn):
btn.setMinimumWidth(96)
btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
# --- Botons (icones compactes amb tooltip; visibilitat segons l'estat) ---
style = self.style()
self._icon_download = style.standardIcon(QStyle.SP_ArrowDown)
self._icon_update = style.standardIcon(QStyle.SP_BrowserReload)
self.download_btn = QPushButton()
self.run_btn = QPushButton()
self.run_btn.setIcon(style.standardIcon(QStyle.SP_MediaPlay))
self.run_btn.setToolTip("Juga")
self.delete_btn = QPushButton()
self.delete_btn.setIcon(style.standardIcon(QStyle.SP_TrashIcon))
self.delete_btn.setToolTip("Esborra")
for btn in (self.download_btn, self.run_btn, self.delete_btn):
btn.setFixedSize(36, 30)
btn.setIconSize(QSize(18, 18))
self.download_btn.clicked.connect(lambda: self.download_requested.emit(self.game))
self.run_btn.clicked.connect(lambda: self.run_requested.emit(self.game))
btn_box = QVBoxLayout()
self.delete_btn.clicked.connect(lambda: self.delete_requested.emit(self.game))
btn_box = QHBoxLayout()
btn_box.setSpacing(4)
btn_box.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
btn_box.addWidget(self.download_btn)
btn_box.addWidget(self.run_btn)
btn_box.addWidget(self.delete_btn)
layout.addLayout(btn_box)
self.refresh()
@@ -92,7 +107,7 @@ class GameRow(QFrame):
"""Recarga icono, descripción y estado desde la cache local."""
meta = load_meta(self.root, self.game.id)
self._set_icon()
self.desc_label.setText(meta.description or "(sin descripción todavía)")
self.desc_label.setText(meta.description or "(sense descripció encara)")
self._set_status(meta)
def _set_icon(self) -> None:
@@ -113,18 +128,32 @@ class GameRow(QFrame):
)
def _set_status(self, meta: GameMeta) -> None:
if not self.is_installed():
self.status_label.setText("No instalado")
installed = self.is_installed()
# Visibilitat dels botons segons l'estat:
# - Juga / Esborra: només si està descarregat.
# - Descarrega: si no està descarregat o hi ha update pendent.
self.run_btn.setVisible(installed)
self.delete_btn.setVisible(installed)
self.download_btn.setVisible((not installed) or self._update_available)
if installed and self._update_available:
self.download_btn.setIcon(self._icon_update)
self.download_btn.setToolTip("Actualitza")
else:
self.download_btn.setIcon(self._icon_download)
self.download_btn.setToolTip("Descarrega")
if not installed:
self.status_label.setText("No descarregat")
self.status_label.setStyleSheet("color: #cc8855; font-size: 11px;")
self.run_btn.setEnabled(True) # se permite, avisará si no está
elif self._update_available:
self.status_label.setText("⬆ Actualización disponible")
self.status_label.setText("⬆ Actualització disponible")
self.status_label.setStyleSheet(
"color: #e0a030; font-weight: bold; font-size: 11px;"
)
else:
ver = f" {meta.version}" if meta.version else ""
self.status_label.setText(f"Instalado{ver}")
self.status_label.setText(f"Descarregat{ver}")
self.status_label.setStyleSheet("color: #6fae6f; font-size: 11px;")
# --------------------------------------------------------------- busy UI
@@ -132,6 +161,7 @@ class GameRow(QFrame):
def set_busy(self, busy: bool, message: str = "") -> None:
self.download_btn.setEnabled(not busy)
self.run_btn.setEnabled(not busy)
self.delete_btn.setEnabled(not busy)
if busy and message:
self.status_label.setText(message)
self.status_label.setStyleSheet("color: #d0d060; font-size: 11px;")
+39 -13
View File
@@ -8,6 +8,7 @@ from PySide6.QtCore import QThreadPool, Qt
from PySide6.QtGui import QAction
from PySide6.QtWidgets import (
QMainWindow,
QMessageBox,
QPlainTextEdit,
QScrollArea,
QSplitter,
@@ -15,6 +16,7 @@ from PySide6.QtWidgets import (
QWidget,
)
from .. import gitops
from ..config import Config, Game
from ..settings import load_settings, save_settings
from ..workers import CheckUpdatesWorker, DownloadWorker, RunWorker
@@ -53,6 +55,7 @@ class MainWindow(QMainWindow):
row = GameRow(game, root)
row.download_requested.connect(self._on_download)
row.run_requested.connect(self._on_run)
row.delete_requested.connect(self._on_delete)
self.rows[game.id] = row
list_layout.addWidget(row)
list_layout.addStretch(1)
@@ -82,14 +85,14 @@ class MainWindow(QMainWindow):
# --------------------------------------------------------------- menú
def _build_menu(self) -> None:
menu = self.menuBar().addMenu("Opciones")
menu = self.menuBar().addMenu("Opcions")
self.action_hide = QAction("Ocultar juegos no descargados", self, checkable=True)
self.action_hide = QAction("Amaga els jocs no descarregats", self, checkable=True)
self.action_hide.setChecked(self.settings.hide_not_downloaded)
self.action_hide.toggled.connect(self._on_toggle_hide)
menu.addAction(self.action_hide)
self.action_check = QAction("Comprobar actualizaciones", self)
self.action_check = QAction("Comprova actualitzacions", self)
self.action_check.triggered.connect(self._check_updates)
menu.addAction(self.action_check)
@@ -107,7 +110,7 @@ class MainWindow(QMainWindow):
def _check_updates(self) -> None:
self.action_check.setEnabled(False)
self._log("=== Comprobando actualizaciones ===")
self._log("=== Comprovant actualitzacions ===")
worker = CheckUpdatesWorker(self.root, self.config.games)
worker.signals.log.connect(self._log)
worker.signals.result.connect(self._mark_update)
@@ -127,11 +130,11 @@ class MainWindow(QMainWindow):
def _check_done(self, _payload) -> None:
self.action_check.setEnabled(True)
self._log("=== Comprobación de actualizaciones terminada ===")
self._log("=== Comprovació d'actualitzacions acabada ===")
def _check_error(self, msg: str) -> None:
self.action_check.setEnabled(True)
self._log(f"!!! Error comprobando actualizaciones: {msg}")
self._log(f"!!! Error comprovant actualitzacions: {msg}")
# --------------------------------------------------------------- helpers
@@ -146,12 +149,12 @@ class MainWindow(QMainWindow):
worker.signals.finished.connect(lambda *_: self._workers.discard(worker))
worker.signals.error.connect(lambda *_: self._workers.discard(worker))
# --------------------------------------------------------------- acciones
# --------------------------------------------------------------- accions
def _on_download(self, game: Game) -> None:
row = self.rows[game.id]
row.set_busy(True, "Descargando")
self._log(f"=== Download: {game.name} ===")
row.set_busy(True, "Descarregant")
self._log(f"=== Descàrrega: {game.name} ===")
worker = DownloadWorker(self.root, game)
worker.signals.log.connect(self._log)
@@ -161,7 +164,7 @@ class MainWindow(QMainWindow):
self.pool.start(worker)
def _download_done(self, game: Game) -> None:
self._log(f"=== {game.name}: descarga completada ===")
self._log(f"=== {game.name}: descàrrega completada ===")
row = self.rows[game.id]
row.set_busy(False)
row.set_update_available(False) # recién traído del remoto → al día
@@ -174,8 +177,8 @@ class MainWindow(QMainWindow):
def _on_run(self, game: Game) -> None:
row = self.rows[game.id]
row.set_busy(True, "Ejecutando")
self._log(f"=== Run: {game.name} ===")
row.set_busy(True, "Executant")
self._log(f"=== Juga: {game.name} ===")
worker = RunWorker(self.root, game)
worker.signals.log.connect(self._log)
@@ -185,7 +188,7 @@ class MainWindow(QMainWindow):
self.pool.start(worker)
def _run_done(self, game: Game, code: int) -> None:
self._log(f"=== {game.name}: finalizó con código {code} ===")
self._log(f"=== {game.name}: ha finalitzat amb codi {code} ===")
row = self.rows[game.id]
row.set_busy(False)
row.refresh()
@@ -195,3 +198,26 @@ class MainWindow(QMainWindow):
row = self.rows[game.id]
row.set_busy(False)
row.refresh()
def _on_delete(self, game: Game) -> None:
resp = QMessageBox.question(
self,
"Esborrar descàrrega",
f"Segur que vols esborrar la descàrrega local de «{game.name}»?\n\n"
"S'eliminarà el clon i les dades en local (no es treu de la llista).",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No,
)
if resp != QMessageBox.Yes:
return
self._log(f"=== Esborra: {game.name} ===")
gitops.delete_local(self.root, game, log=self._log)
if game.id in self.settings.updates_pending:
self.settings.updates_pending = [
g for g in self.settings.updates_pending if g != game.id
]
save_settings(self.settings)
row = self.rows[game.id]
row.set_update_available(False)
row.refresh()
self._apply_filter() # si està actiu "amaga no descarregats", ara s'amaga