diff --git a/CHANGELOG.md b/CHANGELOG.md index dcb5636..a4c0377 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 1.0.1 (2026-01-30) + +### GUI + +- **dialogs/about.py** - Dialog "O programu" zobrazující název, verzi, autora a popis. Červený DEV badge pokud je aktivní vývojářský režim (ENV_DEBUG) +- **tray_app.py** - Položka "O programu..." v tray menu + +### Interní + +- **version.py** - Modul pro získání verze z pyproject.toml s fallbackem do _version.py +- **_version.py** - Automaticky aktualizovaný fallback soubor s poslední známou verzí + ## 1.0.0 (2026-01-30) První kompletní verze aplikace Vault. diff --git a/pyproject.toml b/pyproject.toml index e8ad5db..f9f178c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "vault" -version = "1.0.0" +version = "1.0.1" description = "" authors = [ {name = "Jan Doubravský",email = "jan.doubravsky@gmail.com"} diff --git a/src/_version.py b/src/_version.py new file mode 100644 index 0000000..5c4105c --- /dev/null +++ b/src/_version.py @@ -0,0 +1 @@ +__version__ = "1.0.1" diff --git a/src/ui/dialogs/about.py b/src/ui/dialogs/about.py new file mode 100644 index 0000000..855f0c5 --- /dev/null +++ b/src/ui/dialogs/about.py @@ -0,0 +1,73 @@ +"""About program dialog.""" + +from PySide6.QtCore import Qt +from PySide6.QtWidgets import ( + QDialog, + QHBoxLayout, + QLabel, + QPushButton, + QVBoxLayout, + QWidget, +) + +from src.version import get_version, is_dev + + +class AboutDialog(QDialog): + """Dialog showing program information.""" + + def __init__(self, parent: QWidget | None = None) -> None: + super().__init__(parent) + self.setWindowTitle("O programu") + self.setFixedWidth(360) + self._setup_ui() + + def _setup_ui(self) -> None: + """Set up dialog UI.""" + layout = QVBoxLayout(self) + layout.setSpacing(12) + + # App name + name_label = QLabel("Vault") + name_label.setStyleSheet("font-size: 22px; font-weight: bold;") + name_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.addWidget(name_label) + + # Version row + version = get_version() + version_text = f"Verze {version}" + if is_dev(): + version_text += ' DEV' + + version_label = QLabel(version_text) + version_label.setTextFormat(Qt.TextFormat.RichText) + version_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + version_label.setStyleSheet("font-size: 13px; color: #888;") + layout.addWidget(version_label) + + layout.addSpacing(8) + + # Description + desc_label = QLabel("Bezpečné úložiště souborů s podporou replik\na automatické synchronizace.") + desc_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + desc_label.setWordWrap(True) + layout.addWidget(desc_label) + + layout.addSpacing(4) + + # Author + author_label = QLabel("Autor: Jan Doubravský") + author_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + author_label.setStyleSheet("font-size: 11px; color: #aaa;") + layout.addWidget(author_label) + + layout.addStretch() + + # Close button + btn_layout = QHBoxLayout() + btn_layout.addStretch() + close_btn = QPushButton("Zavřít") + close_btn.clicked.connect(self.accept) + btn_layout.addWidget(close_btn) + btn_layout.addStretch() + layout.addLayout(btn_layout) diff --git a/src/ui/tray_app.py b/src/ui/tray_app.py index 1b24df9..d189312 100644 --- a/src/ui/tray_app.py +++ b/src/ui/tray_app.py @@ -117,6 +117,9 @@ class VaultTrayApp: menu.addSeparator() + # About + menu.addAction("O programu...").triggered.connect(self._show_about) + # Quit menu.addAction("Ukončit").triggered.connect(self._quit) @@ -362,6 +365,13 @@ class VaultTrayApp: logger.error(f"Resize failed: {e}") self._notifications.notify("Chyba", f"Nepodařilo se zvětšit vault: {e}", critical=True) + def _show_about(self) -> None: + """Show about dialog.""" + from src.ui.dialogs.about import AboutDialog + + dialog = AboutDialog() + dialog.exec() + def _quit(self) -> None: """Quit the application.""" if self._vault.is_open: diff --git a/src/version.py b/src/version.py new file mode 100644 index 0000000..7db21ad --- /dev/null +++ b/src/version.py @@ -0,0 +1,59 @@ +from __future__ import annotations + +import os +import tomllib +from pathlib import Path + +from dotenv import load_dotenv +from loguru import logger + +_ROOT = Path(__file__).resolve().parent.parent + +load_dotenv(_ROOT / ".env") + + +def _project_root() -> Path: + """Return the project root directory (where pyproject.toml lives).""" + return Path(__file__).resolve().parent.parent + + +def get_version() -> str: + """Get the current version string. + + Reads from pyproject.toml if available and updates the fallback + ``_version.py``. Falls back to ``_version.py`` when the toml file + is not present (e.g. in a packaged distribution). + """ + toml_path = _project_root() / "pyproject.toml" + + if toml_path.is_file(): + try: + with open(toml_path, "rb") as f: + data = tomllib.load(f) + version = data["tool"]["poetry"]["version"] + _update_fallback(version) + return version + except Exception: + logger.debug("Failed to read version from pyproject.toml, using fallback") + + # Fallback + from src._version import __version__ + return __version__ + + +def _update_fallback(version: str) -> None: + """Write the version to ``_version.py`` so it's available even without toml.""" + fallback_path = Path(__file__).resolve().parent / "_version.py" + try: + new_content = f'__version__ = "{version}"\n' + # Only write if changed + if fallback_path.is_file() and fallback_path.read_text() == new_content: + return + fallback_path.write_text(new_content) + except Exception: + logger.debug("Failed to update _version.py fallback") + + +def is_dev() -> bool: + """Return True if running in development mode (ENV_DEBUG is set).""" + return os.getenv("ENV_DEBUG", "").strip().lower() == "true"