Files
Playtube/playtube/settings_tab.py
T
Fojadrachi c1465a4e49 Einstellungen: Versionsnummer, Update-Status und GitHub-Link in heller Schrift
Die drei Texte nutzten palette(mid) (dunkles Grau) und waren im dunklen Design kaum
lesbar. Jetzt palette(text) (weiss im dunklen, dunkel im hellen Design). Der
Update-Fortschrittsbalken bekommt eine helle Beschriftung und einen gut sichtbaren
blauen Balken.
2026-09-19 19:46:28 +02:00

216 lines
8.6 KiB
Python

"""Einstellungen-Tab: Discord-RPC, Auto-Update und Start-Tab direkt in der App
bearbeitbar, ohne config.json von Hand anfassen zu muessen."""
from __future__ import annotations
from typing import Any
from PySide6.QtCore import Signal
from PySide6.QtWidgets import (
QCheckBox,
QComboBox,
QFormLayout,
QGroupBox,
QHBoxLayout,
QLabel,
QLineEdit,
QMessageBox,
QProgressBar,
QPushButton,
QSpinBox,
QVBoxLayout,
QWidget,
)
from . import __version__ as APP_VERSION
from .config import APP_NAME, save_config
from .updater import GITHUB_REPO
# Helle Schrift fuer Versionsnummer, Update-Status und GitHub-Link. palette(text) ist die
# Standard-Textfarbe (im dunklen Design weiss, im hellen dunkel) - das fruehere
# palette(mid) war ein dunkles Grau, das auf dem dunklen Hintergrund kaum lesbar war.
_LIGHT_TEXT_STYLE = "color: palette(text);"
# Update-Fortschrittsbalken: helle Beschriftung und gut sichtbarer Balken. Sobald ein
# Stylesheet gesetzt ist, zeichnet Qt den Balken nicht mehr mit dem nativen Stil - deshalb
# hier Rahmen, Hintergrund und Balken (chunk) vollstaendig angegeben.
_PROGRESS_BAR_STYLE = """
QProgressBar {
color: palette(text);
background-color: palette(base);
border: 1px solid palette(mid);
border-radius: 4px;
text-align: center;
}
QProgressBar::chunk {
background-color: #2f81f7;
border-radius: 3px;
}
"""
class SettingsTab(QWidget):
"""Speichert Aenderungen sofort in config.json und meldet sie per Signal an
MainWindow, damit Discord-RPC/Auto-Update ohne Neustart neu konfiguriert werden."""
settingsSaved = Signal(dict)
checkUpdatesRequested = Signal()
installUpdateRequested = Signal()
def __init__(self, config: dict[str, Any], parent=None):
super().__init__(parent)
self._config = config
outer = QVBoxLayout(self)
outer.setContentsMargins(32, 28, 32, 28)
outer.setSpacing(18)
header = QVBoxLayout()
header.setSpacing(2)
title = QLabel(f"{APP_NAME}-Einstellungen")
title.setStyleSheet("font-size: 20px; font-weight: 600;")
header.addWidget(title)
version_label = QLabel(f"Version {APP_VERSION}")
version_label.setStyleSheet(_LIGHT_TEXT_STYLE)
header.addWidget(version_label)
outer.addLayout(header)
discord_cfg = config.get("discord", {})
discord_box = QGroupBox("Discord Rich Presence")
discord_form = QFormLayout(discord_box)
self._discord_enabled = QCheckBox("Aktiviert")
self._discord_enabled.setChecked(bool(discord_cfg.get("enabled", True)))
self._client_id = QLineEdit(str(discord_cfg.get("client_id", "")))
self._client_id.setPlaceholderText("Discord Application Client-ID")
self._discord_interval = QSpinBox()
# Minimum 15s: Discord ignoriert Rich-Presence-Updates, die haeufiger kommen,
# stillschweigend (fuehrt zu "eingefrorenem" Bild/Fortschrittsbalken).
self._discord_interval.setRange(15, 120)
self._discord_interval.setSuffix(" s")
self._discord_interval.setValue(max(15, int(discord_cfg.get("update_interval_seconds", 15))))
self._show_idle = QCheckBox("Status anzeigen, wenn gerade nichts läuft")
self._show_idle.setChecked(bool(discord_cfg.get("show_idle_presence", True)))
discord_form.addRow(self._discord_enabled)
discord_form.addRow("Client-ID:", self._client_id)
discord_form.addRow("Update-Intervall:", self._discord_interval)
discord_form.addRow(self._show_idle)
outer.addWidget(discord_box)
updates_cfg = config.get("updates", {})
update_box = QGroupBox("Automatische Updates")
update_form = QFormLayout(update_box)
self._updates_enabled = QCheckBox("Aktiviert")
self._updates_enabled.setChecked(bool(updates_cfg.get("enabled", True)))
self._check_interval = QSpinBox()
self._check_interval.setRange(1, 168)
self._check_interval.setSuffix(" h")
self._check_interval.setValue(int(updates_cfg.get("check_interval_hours", 6)))
update_form.addRow(self._updates_enabled)
update_form.addRow("Prüfintervall:", self._check_interval)
update_actions = QHBoxLayout()
self._check_updates_btn = QPushButton("Jetzt nach Updates suchen")
self._check_updates_btn.clicked.connect(self.checkUpdatesRequested.emit)
update_actions.addWidget(self._check_updates_btn)
self._install_update_btn = QPushButton("Update installieren")
self._install_update_btn.setVisible(False)
self._install_update_btn.clicked.connect(self.installUpdateRequested.emit)
update_actions.addWidget(self._install_update_btn)
update_actions.addStretch(1)
update_form.addRow(update_actions)
self._update_status_label = QLabel("")
self._update_status_label.setStyleSheet(_LIGHT_TEXT_STYLE)
self._update_status_label.setWordWrap(True)
update_form.addRow(self._update_status_label)
self._update_progress = QProgressBar()
self._update_progress.setRange(0, 100)
self._update_progress.setTextVisible(True)
self._update_progress.setStyleSheet(_PROGRESS_BAR_STYLE)
self._update_progress.setVisible(False)
update_form.addRow(self._update_progress)
outer.addWidget(update_box)
general_box = QGroupBox("Allgemein")
general_form = QFormLayout(general_box)
self._start_tab = QComboBox()
self._start_tab.addItem("YouTube", "youtube")
self._start_tab.addItem("YouTube Music", "music")
idx = self._start_tab.findData(config.get("start_tab", "youtube"))
self._start_tab.setCurrentIndex(max(0, idx))
general_form.addRow("Beim Start öffnen:", self._start_tab)
outer.addWidget(general_box)
button_row = QHBoxLayout()
save_btn = QPushButton("Speichern")
save_btn.clicked.connect(self._on_save)
button_row.addWidget(save_btn)
button_row.addStretch(1)
outer.addLayout(button_row)
info = QLabel(f"github.com/{GITHUB_REPO}")
info.setStyleSheet(_LIGHT_TEXT_STYLE)
outer.addWidget(info)
outer.addStretch(1)
def _on_save(self) -> None:
self._config.setdefault("discord", {})
self._config.setdefault("updates", {})
self._config["discord"]["enabled"] = self._discord_enabled.isChecked()
self._config["discord"]["client_id"] = self._client_id.text().strip()
self._config["discord"]["update_interval_seconds"] = self._discord_interval.value()
self._config["discord"]["show_idle_presence"] = self._show_idle.isChecked()
self._config["updates"]["enabled"] = self._updates_enabled.isChecked()
self._config["updates"]["check_interval_hours"] = self._check_interval.value()
self._config["start_tab"] = self._start_tab.currentData()
save_config(self._config)
self.settingsSaved.emit(self._config)
QMessageBox.information(
self,
"Gespeichert",
"Einstellungen gespeichert und übernommen (Discord-Verbindung wurde "
"mit den neuen Werten neu gestartet).",
)
# ----------------------------------------------------- Update-Status (von MainWindow)
def set_checking(self) -> None:
self._check_updates_btn.setEnabled(False)
self._install_update_btn.setVisible(False)
self._update_progress.setVisible(False)
self._update_status_label.setText("Suche nach Updates …")
def set_check_done(self) -> None:
self._check_updates_btn.setEnabled(True)
def set_update_status(self, text: str) -> None:
self._update_status_label.setText(text)
def show_update_available(self, version: str) -> None:
self._update_status_label.setText(f"Neue Version verfügbar: {version}")
self._install_update_btn.setVisible(True)
def hide_install_button(self) -> None:
self._install_update_btn.setVisible(False)
def set_download_progress(self, percent: int) -> None:
"""percent: 0-100 fuer einen konkreten Fortschritt, -1 fuer unbestimmt
(z.B. waehrend Entpacken/Installieren), negativ->versteckt den Balken nicht
automatisch - dafuer set_progress_hidden() aufrufen."""
if percent < 0:
self._update_progress.setRange(0, 0) # "laufender" Balken ohne Prozentzahl
else:
self._update_progress.setRange(0, 100)
self._update_progress.setValue(percent)
self._update_progress.setVisible(True)
def set_progress_hidden(self) -> None:
self._update_progress.setVisible(False)
self._update_progress.setRange(0, 100)