Compare commits
7 Commits
a31c9dc186
...
b317e4760b
Author | SHA1 | Date | |
---|---|---|---|
b317e4760b
|
|||
6d3e0982c9
|
|||
372832b41d
|
|||
58a01d36fb
|
|||
5d84dbad8e
|
|||
61964d21c7
|
|||
2971a594dc
|
@@ -145,14 +145,17 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: release/
|
path: release/
|
||||||
|
|
||||||
- name: Get Changes between Tags
|
- name: Extract changelog for version
|
||||||
id: changes
|
id: changelog
|
||||||
uses: https://github.com/simbo/changes-between-tags-action@v1
|
run: |
|
||||||
|
VERSION="${{ env.VERSION }}"
|
||||||
|
VERSION=${VERSION#v} # Remove 'v' prefix if present
|
||||||
|
awk "/^## \\[$VERSION\\]/ {flag=1; next} /^## \\[/ || /^---/ {flag=0} flag" CHANGELOG.md > changelog.txt
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: https://gitea.com/actions/gitea-release-action@v1
|
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||||
with:
|
with:
|
||||||
body: ${{ steps.changes.outputs.changes }}
|
body_path: changelog.txt
|
||||||
token: ${{ env.GITEA_TOKEN }}
|
token: ${{ env.GITEA_TOKEN }}
|
||||||
tag_name: ${{ env.VERSION }}
|
tag_name: ${{ env.VERSION }}
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
@@ -8,6 +8,8 @@
|
|||||||
### Added
|
### Added
|
||||||
- Кнопки сброса настроек и очистки кэша
|
- Кнопки сброса настроек и очистки кэша
|
||||||
- Начальная интеграция с EGS с помощью [Legendary](https://github.com/derrod/legendary)
|
- Начальная интеграция с EGS с помощью [Legendary](https://github.com/derrod/legendary)
|
||||||
|
- Бейдж EGS
|
||||||
|
- Бейдж PortProton
|
||||||
- Зависимость на `xdg-utils`
|
- Зависимость на `xdg-utils`
|
||||||
- Интеграция статуса WeAntiCheatYet в карточку
|
- Интеграция статуса WeAntiCheatYet в карточку
|
||||||
- Стили в AddGameDialog
|
- Стили в AddGameDialog
|
||||||
@@ -25,12 +27,14 @@
|
|||||||
### Changed
|
### Changed
|
||||||
- Обновлены все иконки
|
- Обновлены все иконки
|
||||||
- Переименован `_get_steam_home` → `get_steam_home`
|
- Переименован `_get_steam_home` → `get_steam_home`
|
||||||
|
- Переименован `steam_game` → `game_source`
|
||||||
- Догика контекстного меню вынесена в `ContextMenuManager`
|
- Догика контекстного меню вынесена в `ContextMenuManager`
|
||||||
- Бейдж Steam теперь открывает Steam Community
|
- Бейдж Steam теперь открывает Steam Community
|
||||||
- Изменена лицензия с MIT на GPL-3.0 для совместимости с кодом от legendary
|
- Изменена лицензия с MIT на GPL-3.0 для совместимости с кодом от legendary
|
||||||
- Оптимизирована генерация карточек для предотвращения лагов при поиске и изменения размера окна
|
- Оптимизирована генерация карточек для предотвращения лагов при поиске и изменения размера окна
|
||||||
- Бейджи с карточек так же теперь дублируются и на странице с деталями, а не только в библиотеке
|
- Бейджи с карточек так же теперь дублируются и на странице с деталями, а не только в библиотеке
|
||||||
- Установка ширины бейджа в две трети ширины карточки
|
- Установка ширины бейджа в две трети ширины карточки
|
||||||
|
- Бейджи источников (`Steam`, `EGS`, `PortProton`) теперь отображаются только при активном фильтре `all` или `favorites`
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Обработка несуществующей темы с возвратом к “standart”
|
- Обработка несуществующей темы с возвратом к “standart”
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
# Base directory of the project
|
# Base directory of the project
|
||||||
BASE_DIR = Path(__file__).parent.parent
|
BASE_DIR = Path(__file__).parent.parent
|
||||||
@@ -13,6 +14,7 @@ FEDORA_SPEC = BASE_DIR / "build-aux" / "fedora.spec"
|
|||||||
PYPROJECT = BASE_DIR / "pyproject.toml"
|
PYPROJECT = BASE_DIR / "pyproject.toml"
|
||||||
APP_PY = BASE_DIR / "portprotonqt" / "app.py"
|
APP_PY = BASE_DIR / "portprotonqt" / "app.py"
|
||||||
GITEA_WORKFLOW = BASE_DIR / ".gitea" / "workflows" / "build.yml"
|
GITEA_WORKFLOW = BASE_DIR / ".gitea" / "workflows" / "build.yml"
|
||||||
|
CHANGELOG = BASE_DIR / "CHANGELOG.md"
|
||||||
|
|
||||||
def bump_appimage(path: Path, old: str, new: str) -> bool:
|
def bump_appimage(path: Path, old: str, new: str) -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -27,7 +29,6 @@ def bump_appimage(path: Path, old: str, new: str) -> bool:
|
|||||||
path.write_text(new_text, encoding='utf-8')
|
path.write_text(new_text, encoding='utf-8')
|
||||||
return bool(count)
|
return bool(count)
|
||||||
|
|
||||||
|
|
||||||
def bump_arch(path: Path, old: str, new: str) -> bool:
|
def bump_arch(path: Path, old: str, new: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Update pkgver in PKGBUILD
|
Update pkgver in PKGBUILD
|
||||||
@@ -41,7 +42,6 @@ def bump_arch(path: Path, old: str, new: str) -> bool:
|
|||||||
path.write_text(new_text, encoding='utf-8')
|
path.write_text(new_text, encoding='utf-8')
|
||||||
return bool(count)
|
return bool(count)
|
||||||
|
|
||||||
|
|
||||||
def bump_fedora(path: Path, old: str, new: str) -> bool:
|
def bump_fedora(path: Path, old: str, new: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Update only the '%global pypi_version' line in fedora.spec
|
Update only the '%global pypi_version' line in fedora.spec
|
||||||
@@ -55,7 +55,6 @@ def bump_fedora(path: Path, old: str, new: str) -> bool:
|
|||||||
path.write_text(new_text, encoding='utf-8')
|
path.write_text(new_text, encoding='utf-8')
|
||||||
return bool(count)
|
return bool(count)
|
||||||
|
|
||||||
|
|
||||||
def bump_pyproject(path: Path, old: str, new: str) -> bool:
|
def bump_pyproject(path: Path, old: str, new: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Update version in pyproject.toml under [project]
|
Update version in pyproject.toml under [project]
|
||||||
@@ -69,7 +68,6 @@ def bump_pyproject(path: Path, old: str, new: str) -> bool:
|
|||||||
path.write_text(new_text, encoding='utf-8')
|
path.write_text(new_text, encoding='utf-8')
|
||||||
return bool(count)
|
return bool(count)
|
||||||
|
|
||||||
|
|
||||||
def bump_app_py(path: Path, old: str, new: str) -> bool:
|
def bump_app_py(path: Path, old: str, new: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Update __app_version__ in app.py
|
Update __app_version__ in app.py
|
||||||
@@ -83,7 +81,6 @@ def bump_app_py(path: Path, old: str, new: str) -> bool:
|
|||||||
path.write_text(new_text, encoding='utf-8')
|
path.write_text(new_text, encoding='utf-8')
|
||||||
return bool(count)
|
return bool(count)
|
||||||
|
|
||||||
|
|
||||||
def bump_workflow(path: Path, old: str, new: str) -> bool:
|
def bump_workflow(path: Path, old: str, new: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Update VERSION in Gitea Actions workflow
|
Update VERSION in Gitea Actions workflow
|
||||||
@@ -97,6 +94,19 @@ def bump_workflow(path: Path, old: str, new: str) -> bool:
|
|||||||
path.write_text(new_text, encoding='utf-8')
|
path.write_text(new_text, encoding='utf-8')
|
||||||
return bool(count)
|
return bool(count)
|
||||||
|
|
||||||
|
def bump_changelog(path: Path, old: str, new: str) -> bool:
|
||||||
|
"""
|
||||||
|
Update [Unreleased] to [new] - YYYY-MM-DD in CHANGELOG.md
|
||||||
|
"""
|
||||||
|
if not path.exists():
|
||||||
|
return False
|
||||||
|
text = path.read_text(encoding='utf-8')
|
||||||
|
pattern = re.compile(r"(?m)^##\s*\[Unreleased\]$")
|
||||||
|
current_date = date.today().strftime('%Y-%m-%d')
|
||||||
|
new_text, count = pattern.subn(f"## [{new}] - {current_date}", text)
|
||||||
|
if count:
|
||||||
|
path.write_text(new_text, encoding='utf-8')
|
||||||
|
return bool(count)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='Bump project version in specific files')
|
parser = argparse.ArgumentParser(description='Bump project version in specific files')
|
||||||
@@ -111,7 +121,8 @@ def main():
|
|||||||
(FEDORA_SPEC, bump_fedora),
|
(FEDORA_SPEC, bump_fedora),
|
||||||
(PYPROJECT, bump_pyproject),
|
(PYPROJECT, bump_pyproject),
|
||||||
(APP_PY, bump_app_py),
|
(APP_PY, bump_app_py),
|
||||||
(GITEA_WORKFLOW, bump_workflow)
|
(GITEA_WORKFLOW, bump_workflow),
|
||||||
|
(CHANGELOG, bump_changelog)
|
||||||
]
|
]
|
||||||
|
|
||||||
updated = []
|
updated = []
|
||||||
@@ -126,6 +137,5 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print(f"No occurrences of version {old} found in specified files.")
|
print(f"No occurrences of version {old} found in specified files.")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@@ -40,7 +40,7 @@ class ContextMenuManager:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
menu = QMenu(self.parent)
|
menu = QMenu(self.parent)
|
||||||
if game_card.steam_game != "true":
|
if game_card.game_source not in ("steam", "epic"):
|
||||||
desktop_dir = subprocess.check_output(['xdg-user-dir', 'DESKTOP']).decode('utf-8').strip()
|
desktop_dir = subprocess.check_output(['xdg-user-dir', 'DESKTOP']).decode('utf-8').strip()
|
||||||
desktop_path = os.path.join(desktop_dir, f"{game_card.name}.desktop")
|
desktop_path = os.path.join(desktop_dir, f"{game_card.name}.desktop")
|
||||||
if os.path.exists(desktop_path):
|
if os.path.exists(desktop_path):
|
||||||
|
@@ -133,7 +133,7 @@ class FlowLayout(QLayout):
|
|||||||
class ClickableLabel(QLabel):
|
class ClickableLabel(QLabel):
|
||||||
clicked = Signal()
|
clicked = Signal()
|
||||||
|
|
||||||
def __init__(self, *args, icon=None, icon_size=16, icon_space=5, **kwargs):
|
def __init__(self, *args, icon=None, icon_size=16, icon_space=5, change_cursor=True, **kwargs):
|
||||||
"""
|
"""
|
||||||
Поддерживаются вызовы:
|
Поддерживаются вызовы:
|
||||||
- ClickableLabel("текст", parent=...) – первый аргумент строка,
|
- ClickableLabel("текст", parent=...) – первый аргумент строка,
|
||||||
@@ -143,6 +143,7 @@ class ClickableLabel(QLabel):
|
|||||||
icon: QIcon или None – иконка, которая будет отрисована вместе с текстом.
|
icon: QIcon или None – иконка, которая будет отрисована вместе с текстом.
|
||||||
icon_size: int – размер иконки (ширина и высота).
|
icon_size: int – размер иконки (ширина и высота).
|
||||||
icon_space: int – отступ между иконкой и текстом.
|
icon_space: int – отступ между иконкой и текстом.
|
||||||
|
change_cursor: bool – изменять ли курсор на PointingHandCursor при наведении (по умолчанию True).
|
||||||
"""
|
"""
|
||||||
if args and isinstance(args[0], str):
|
if args and isinstance(args[0], str):
|
||||||
text = args[0]
|
text = args[0]
|
||||||
@@ -161,7 +162,8 @@ class ClickableLabel(QLabel):
|
|||||||
self._icon = icon
|
self._icon = icon
|
||||||
self._icon_size = icon_size
|
self._icon_size = icon_size
|
||||||
self._icon_space = icon_space
|
self._icon_space = icon_space
|
||||||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
if change_cursor:
|
||||||
|
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
|
|
||||||
def setIcon(self, icon):
|
def setIcon(self, icon):
|
||||||
"""Устанавливает иконку и перерисовывает виджет."""
|
"""Устанавливает иконку и перерисовывает виджет."""
|
||||||
|
@@ -5,7 +5,7 @@ from collections.abc import Callable
|
|||||||
import portprotonqt.themes.standart.styles as default_styles
|
import portprotonqt.themes.standart.styles as default_styles
|
||||||
from portprotonqt.image_utils import load_pixmap_async, round_corners
|
from portprotonqt.image_utils import load_pixmap_async, round_corners
|
||||||
from portprotonqt.localization import _
|
from portprotonqt.localization import _
|
||||||
from portprotonqt.config_utils import read_favorites, save_favorites
|
from portprotonqt.config_utils import read_favorites, save_favorites, read_display_filter
|
||||||
from portprotonqt.theme_manager import ThemeManager
|
from portprotonqt.theme_manager import ThemeManager
|
||||||
from portprotonqt.config_utils import read_theme_from_config
|
from portprotonqt.config_utils import read_theme_from_config
|
||||||
from portprotonqt.custom_widgets import ClickableLabel
|
from portprotonqt.custom_widgets import ClickableLabel
|
||||||
@@ -27,7 +27,7 @@ class GameCard(QFrame):
|
|||||||
openGameFolderRequested = Signal(str, str) # name, exec_line
|
openGameFolderRequested = Signal(str, str) # name, exec_line
|
||||||
|
|
||||||
def __init__(self, name, description, cover_path, appid, controller_support, exec_line,
|
def __init__(self, name, description, cover_path, appid, controller_support, exec_line,
|
||||||
last_launch, formatted_playtime, protondb_tier, anticheat_status, last_launch_ts, playtime_seconds, steam_game,
|
last_launch, formatted_playtime, protondb_tier, anticheat_status, last_launch_ts, playtime_seconds, game_source,
|
||||||
select_callback, theme=None, card_width=250, parent=None, context_menu_manager=None):
|
select_callback, theme=None, card_width=250, parent=None, context_menu_manager=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -40,7 +40,7 @@ class GameCard(QFrame):
|
|||||||
self.formatted_playtime = formatted_playtime
|
self.formatted_playtime = formatted_playtime
|
||||||
self.protondb_tier = protondb_tier
|
self.protondb_tier = protondb_tier
|
||||||
self.anticheat_status = anticheat_status
|
self.anticheat_status = anticheat_status
|
||||||
self.steam_game = steam_game
|
self.game_source = game_source
|
||||||
self.last_launch_ts = last_launch_ts
|
self.last_launch_ts = last_launch_ts
|
||||||
self.playtime_seconds = playtime_seconds
|
self.playtime_seconds = playtime_seconds
|
||||||
|
|
||||||
@@ -51,6 +51,7 @@ class GameCard(QFrame):
|
|||||||
self.theme_manager = ThemeManager()
|
self.theme_manager = ThemeManager()
|
||||||
self.theme = theme if theme is not None else default_styles
|
self.theme = theme if theme is not None else default_styles
|
||||||
|
|
||||||
|
self.display_filter = read_display_filter()
|
||||||
self.current_theme_name = read_theme_from_config()
|
self.current_theme_name = read_theme_from_config()
|
||||||
|
|
||||||
# Дополнительное пространство для анимации
|
# Дополнительное пространство для анимации
|
||||||
@@ -105,7 +106,6 @@ class GameCard(QFrame):
|
|||||||
def on_cover_loaded(pixmap):
|
def on_cover_loaded(pixmap):
|
||||||
label = label_ref()
|
label = label_ref()
|
||||||
if label is None:
|
if label is None:
|
||||||
# QLabel уже удалён — ничего не делаем
|
|
||||||
return
|
return
|
||||||
label.setPixmap(round_corners(pixmap, 15))
|
label.setPixmap(round_corners(pixmap, 15))
|
||||||
|
|
||||||
@@ -121,6 +121,10 @@ class GameCard(QFrame):
|
|||||||
self.update_favorite_icon()
|
self.update_favorite_icon()
|
||||||
self.favoriteLabel.raise_()
|
self.favoriteLabel.raise_()
|
||||||
|
|
||||||
|
steam_visible = (str(game_source).lower() == "steam" and self.display_filter in ("all", "favorites"))
|
||||||
|
egs_visible = (str(game_source).lower() == "epic" and self.display_filter in ("all", "favorites"))
|
||||||
|
portproton_visible = (str(game_source).lower() == "portproton" and self.display_filter in ("all", "favorites"))
|
||||||
|
|
||||||
# ProtonDB бейдж
|
# ProtonDB бейдж
|
||||||
tier_text = self.getProtonDBText(protondb_tier)
|
tier_text = self.getProtonDBText(protondb_tier)
|
||||||
if tier_text:
|
if tier_text:
|
||||||
@@ -134,11 +138,11 @@ class GameCard(QFrame):
|
|||||||
icon_space=3,
|
icon_space=3,
|
||||||
)
|
)
|
||||||
self.protondbLabel.setStyleSheet(self.theme.get_protondb_badge_style(protondb_tier))
|
self.protondbLabel.setStyleSheet(self.theme.get_protondb_badge_style(protondb_tier))
|
||||||
self.protondbLabel.setFixedWidth(int(card_width * 2/3)) # Устанавливаем ширину в 2/3 ширины карточки
|
self.protondbLabel.setFixedWidth(int(card_width * 2/3))
|
||||||
protondb_visible = True
|
protondb_visible = True
|
||||||
else:
|
else:
|
||||||
self.protondbLabel = ClickableLabel("", parent=coverWidget, icon_size=16, icon_space=3)
|
self.protondbLabel = ClickableLabel("", parent=coverWidget, icon_size=16, icon_space=3)
|
||||||
self.protondbLabel.setFixedWidth(int(card_width * 2/3)) # Устанавливаем ширину даже для невидимого бейджа
|
self.protondbLabel.setFixedWidth(int(card_width * 2/3))
|
||||||
self.protondbLabel.setVisible(False)
|
self.protondbLabel.setVisible(False)
|
||||||
protondb_visible = False
|
protondb_visible = False
|
||||||
|
|
||||||
@@ -152,8 +156,7 @@ class GameCard(QFrame):
|
|||||||
icon_space=5,
|
icon_space=5,
|
||||||
)
|
)
|
||||||
self.steamLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
self.steamLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
||||||
self.steamLabel.setFixedWidth(int(card_width * 2/3)) # Устанавливаем ширину в 2/3 ширины карточки
|
self.steamLabel.setFixedWidth(int(card_width * 2/3))
|
||||||
steam_visible = (str(steam_game).lower() == "true")
|
|
||||||
self.steamLabel.setVisible(steam_visible)
|
self.steamLabel.setVisible(steam_visible)
|
||||||
|
|
||||||
# Epic Games Store бейдж
|
# Epic Games Store бейдж
|
||||||
@@ -164,12 +167,26 @@ class GameCard(QFrame):
|
|||||||
parent=coverWidget,
|
parent=coverWidget,
|
||||||
icon_size=16,
|
icon_size=16,
|
||||||
icon_space=5,
|
icon_space=5,
|
||||||
|
change_cursor=False
|
||||||
)
|
)
|
||||||
self.egsLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
self.egsLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
||||||
self.egsLabel.setFixedWidth(int(card_width * 2/3)) # Устанавливаем ширину в 2/3 ширины карточки
|
self.egsLabel.setFixedWidth(int(card_width * 2/3))
|
||||||
egs_visible = (str(steam_game).lower() == "epic")
|
|
||||||
self.egsLabel.setVisible(egs_visible)
|
self.egsLabel.setVisible(egs_visible)
|
||||||
|
|
||||||
|
# PortProton badge
|
||||||
|
portproton_icon = self.theme_manager.get_icon("ppqt-tray")
|
||||||
|
self.portprotonLabel = ClickableLabel(
|
||||||
|
"PortProton",
|
||||||
|
icon=portproton_icon,
|
||||||
|
parent=coverWidget,
|
||||||
|
icon_size=16,
|
||||||
|
icon_space=5,
|
||||||
|
change_cursor=False
|
||||||
|
)
|
||||||
|
self.portprotonLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
||||||
|
self.portprotonLabel.setFixedWidth(int(card_width * 2/3))
|
||||||
|
self.portprotonLabel.setVisible(portproton_visible)
|
||||||
|
|
||||||
# WeAntiCheatYet бейдж
|
# WeAntiCheatYet бейдж
|
||||||
anticheat_text = self.getAntiCheatText(anticheat_status)
|
anticheat_text = self.getAntiCheatText(anticheat_status)
|
||||||
if anticheat_text:
|
if anticheat_text:
|
||||||
@@ -183,11 +200,11 @@ class GameCard(QFrame):
|
|||||||
icon_space=3,
|
icon_space=3,
|
||||||
)
|
)
|
||||||
self.anticheatLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
self.anticheatLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
||||||
self.anticheatLabel.setFixedWidth(int(card_width * 2/3)) # Устанавливаем ширину в 2/3 ширины карточки
|
self.anticheatLabel.setFixedWidth(int(card_width * 2/3))
|
||||||
anticheat_visible = True
|
anticheat_visible = True
|
||||||
else:
|
else:
|
||||||
self.anticheatLabel = ClickableLabel("", parent=coverWidget, icon_size=16, icon_space=3)
|
self.anticheatLabel = ClickableLabel("", parent=coverWidget, icon_size=16, icon_space=3)
|
||||||
self.anticheatLabel.setFixedWidth(int(card_width * 2/3)) # Устанавливаем ширину даже для невидимого бейджа
|
self.anticheatLabel.setFixedWidth(int(card_width * 2/3))
|
||||||
self.anticheatLabel.setVisible(False)
|
self.anticheatLabel.setVisible(False)
|
||||||
anticheat_visible = False
|
anticheat_visible = False
|
||||||
|
|
||||||
@@ -196,7 +213,7 @@ class GameCard(QFrame):
|
|||||||
badge_spacing = 5
|
badge_spacing = 5
|
||||||
top_y = 10
|
top_y = 10
|
||||||
badge_y_positions = []
|
badge_y_positions = []
|
||||||
badge_width = int(card_width * 2/3) # Фиксированная ширина бейджей
|
badge_width = int(card_width * 2/3)
|
||||||
if steam_visible:
|
if steam_visible:
|
||||||
steam_x = card_width - badge_width - right_margin
|
steam_x = card_width - badge_width - right_margin
|
||||||
self.steamLabel.move(steam_x, top_y)
|
self.steamLabel.move(steam_x, top_y)
|
||||||
@@ -206,6 +223,11 @@ class GameCard(QFrame):
|
|||||||
egs_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
egs_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
self.egsLabel.move(egs_x, egs_y)
|
self.egsLabel.move(egs_x, egs_y)
|
||||||
badge_y_positions.append(egs_y + self.egsLabel.height())
|
badge_y_positions.append(egs_y + self.egsLabel.height())
|
||||||
|
if portproton_visible:
|
||||||
|
portproton_x = card_width - badge_width - right_margin
|
||||||
|
portproton_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
|
self.portprotonLabel.move(portproton_x, portproton_y)
|
||||||
|
badge_y_positions.append(portproton_y + self.portprotonLabel.height())
|
||||||
if protondb_visible:
|
if protondb_visible:
|
||||||
protondb_x = card_width - badge_width - right_margin
|
protondb_x = card_width - badge_width - right_margin
|
||||||
protondb_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
protondb_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
@@ -218,6 +240,7 @@ class GameCard(QFrame):
|
|||||||
|
|
||||||
self.anticheatLabel.raise_()
|
self.anticheatLabel.raise_()
|
||||||
self.protondbLabel.raise_()
|
self.protondbLabel.raise_()
|
||||||
|
self.portprotonLabel.raise_()
|
||||||
self.egsLabel.raise_()
|
self.egsLabel.raise_()
|
||||||
self.steamLabel.raise_()
|
self.steamLabel.raise_()
|
||||||
self.protondbLabel.clicked.connect(self.open_protondb_report)
|
self.protondbLabel.clicked.connect(self.open_protondb_report)
|
||||||
@@ -232,6 +255,53 @@ class GameCard(QFrame):
|
|||||||
nameLabel.setStyleSheet(self.theme.GAME_CARD_NAME_LABEL_STYLE)
|
nameLabel.setStyleSheet(self.theme.GAME_CARD_NAME_LABEL_STYLE)
|
||||||
layout.addWidget(nameLabel)
|
layout.addWidget(nameLabel)
|
||||||
|
|
||||||
|
def update_badge_visibility(self, display_filter: str):
|
||||||
|
"""Update badge visibility based on the provided display_filter."""
|
||||||
|
self.display_filter = display_filter
|
||||||
|
self.steam_visible = (str(self.game_source).lower() == "steam" and display_filter in ("all", "favorites"))
|
||||||
|
self.egs_visible = (str(self.game_source).lower() == "epic" and display_filter in ("all", "favorites"))
|
||||||
|
self.portproton_visible = (str(self.game_source).lower() == "portproton" and display_filter in ("all", "favorites"))
|
||||||
|
|
||||||
|
self.steamLabel.setVisible(self.steam_visible)
|
||||||
|
self.egsLabel.setVisible(self.egs_visible)
|
||||||
|
self.portprotonLabel.setVisible(self.portproton_visible)
|
||||||
|
|
||||||
|
# Reposition badges
|
||||||
|
right_margin = 8
|
||||||
|
badge_spacing = 5
|
||||||
|
top_y = 10
|
||||||
|
badge_y_positions = []
|
||||||
|
badge_width = int(self.coverLabel.width() * 2/3)
|
||||||
|
if self.steam_visible:
|
||||||
|
steam_x = self.coverLabel.width() - badge_width - right_margin
|
||||||
|
self.steamLabel.move(steam_x, top_y)
|
||||||
|
badge_y_positions.append(top_y + self.steamLabel.height())
|
||||||
|
if self.egs_visible:
|
||||||
|
egs_x = self.coverLabel.width() - badge_width - right_margin
|
||||||
|
egs_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
|
self.egsLabel.move(egs_x, egs_y)
|
||||||
|
badge_y_positions.append(egs_y + self.egsLabel.height())
|
||||||
|
if self.portproton_visible:
|
||||||
|
portproton_x = self.coverLabel.width() - badge_width - right_margin
|
||||||
|
portproton_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
|
self.portprotonLabel.move(portproton_x, portproton_y)
|
||||||
|
badge_y_positions.append(portproton_y + self.portprotonLabel.height())
|
||||||
|
if self.protondbLabel.isVisible():
|
||||||
|
protondb_x = self.coverLabel.width() - badge_width - right_margin
|
||||||
|
protondb_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
|
self.protondbLabel.move(protondb_x, protondb_y)
|
||||||
|
badge_y_positions.append(protondb_y + self.protondbLabel.height())
|
||||||
|
if self.anticheatLabel.isVisible():
|
||||||
|
anticheat_x = self.coverLabel.width() - badge_width - right_margin
|
||||||
|
anticheat_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
|
self.anticheatLabel.move(anticheat_x, anticheat_y)
|
||||||
|
|
||||||
|
self.anticheatLabel.raise_()
|
||||||
|
self.protondbLabel.raise_()
|
||||||
|
self.portprotonLabel.raise_()
|
||||||
|
self.egsLabel.raise_()
|
||||||
|
self.steamLabel.raise_()
|
||||||
|
|
||||||
def _show_context_menu(self, pos):
|
def _show_context_menu(self, pos):
|
||||||
"""Delegate context menu display to ContextMenuManager."""
|
"""Delegate context menu display to ContextMenuManager."""
|
||||||
if self.context_menu_manager:
|
if self.context_menu_manager:
|
||||||
@@ -475,7 +545,7 @@ class GameCard(QFrame):
|
|||||||
self.last_launch,
|
self.last_launch,
|
||||||
self.formatted_playtime,
|
self.formatted_playtime,
|
||||||
self.protondb_tier,
|
self.protondb_tier,
|
||||||
self.steam_game,
|
self.game_source,
|
||||||
self.anticheat_status
|
self.anticheat_status
|
||||||
)
|
)
|
||||||
super().mousePressEvent(event)
|
super().mousePressEvent(event)
|
||||||
@@ -492,7 +562,7 @@ class GameCard(QFrame):
|
|||||||
self.last_launch,
|
self.last_launch,
|
||||||
self.formatted_playtime,
|
self.formatted_playtime,
|
||||||
self.protondb_tier,
|
self.protondb_tier,
|
||||||
self.steam_game,
|
self.game_source,
|
||||||
self.anticheat_status
|
self.anticheat_status
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@@ -314,7 +314,7 @@ class MainWindow(QMainWindow):
|
|||||||
'controller_support': '',
|
'controller_support': '',
|
||||||
'protondb_tier': '',
|
'protondb_tier': '',
|
||||||
'name': name,
|
'name': name,
|
||||||
'steam_game': 'true'
|
'game_source': 'steam'
|
||||||
}
|
}
|
||||||
last_launch = format_last_launch(datetime.fromtimestamp(last_played)) if last_played else _("Never")
|
last_launch = format_last_launch(datetime.fromtimestamp(last_played)) if last_played else _("Never")
|
||||||
steam_games.append((
|
steam_games.append((
|
||||||
@@ -330,7 +330,7 @@ class MainWindow(QMainWindow):
|
|||||||
info.get("anticheat_status", ""),
|
info.get("anticheat_status", ""),
|
||||||
last_played,
|
last_played,
|
||||||
playtime_seconds,
|
playtime_seconds,
|
||||||
"true"
|
"steam"
|
||||||
))
|
))
|
||||||
processed_count += 1
|
processed_count += 1
|
||||||
self.pending_games.append(None)
|
self.pending_games.append(None)
|
||||||
@@ -462,7 +462,6 @@ class MainWindow(QMainWindow):
|
|||||||
final_cover = (user_cover if user_cover else
|
final_cover = (user_cover if user_cover else
|
||||||
builtin_cover if builtin_cover else
|
builtin_cover if builtin_cover else
|
||||||
steam_info.get("cover", "") or entry.get("Icon", ""))
|
steam_info.get("cover", "") or entry.get("Icon", ""))
|
||||||
steam_game = "false"
|
|
||||||
callback((
|
callback((
|
||||||
final_name,
|
final_name,
|
||||||
final_desc,
|
final_desc,
|
||||||
@@ -476,7 +475,7 @@ class MainWindow(QMainWindow):
|
|||||||
steam_info.get("anticheat_status", ""),
|
steam_info.get("anticheat_status", ""),
|
||||||
get_last_launch_timestamp(exe_name) if exe_name else 0,
|
get_last_launch_timestamp(exe_name) if exe_name else 0,
|
||||||
playtime_seconds,
|
playtime_seconds,
|
||||||
steam_game
|
"portproton"
|
||||||
))
|
))
|
||||||
|
|
||||||
get_steam_game_info_async(desktop_name, exec_line, on_steam_info)
|
get_steam_game_info_async(desktop_name, exec_line, on_steam_info)
|
||||||
@@ -1109,10 +1108,13 @@ class MainWindow(QMainWindow):
|
|||||||
self.statusBar().showMessage(_("Cache cleared"), 3000)
|
self.statusBar().showMessage(_("Cache cleared"), 3000)
|
||||||
|
|
||||||
def applySettingsDelayed(self):
|
def applySettingsDelayed(self):
|
||||||
"""Применяет настройки с учетом нового фильтра и обновляет список игр."""
|
"""Applies settings with the new filter and updates the game list."""
|
||||||
read_time_config()
|
read_time_config()
|
||||||
self.games = [] # Очищаем текущий список игр
|
self.games = []
|
||||||
self.loadGames() # Загружаем игры с новым фильтром
|
self.loadGames()
|
||||||
|
display_filter = read_display_filter()
|
||||||
|
for card in self.game_card_cache.values():
|
||||||
|
card.update_badge_visibility(display_filter)
|
||||||
|
|
||||||
def savePortProtonSettings(self):
|
def savePortProtonSettings(self):
|
||||||
"""
|
"""
|
||||||
@@ -1139,7 +1141,17 @@ class MainWindow(QMainWindow):
|
|||||||
fullscreen = self.fullscreenCheckBox.isChecked()
|
fullscreen = self.fullscreenCheckBox.isChecked()
|
||||||
save_fullscreen_config(fullscreen)
|
save_fullscreen_config(fullscreen)
|
||||||
|
|
||||||
# Запускаем отложенное применение настроек через таймер
|
for card in self.game_card_cache.values():
|
||||||
|
card.update_badge_visibility(filter_key)
|
||||||
|
|
||||||
|
if self.currentDetailPage and self.current_exec_line:
|
||||||
|
current_game = next((game for game in self.games if game[4] == self.current_exec_line), None)
|
||||||
|
if current_game:
|
||||||
|
self.stackedWidget.removeWidget(self.currentDetailPage)
|
||||||
|
self.currentDetailPage.deleteLater()
|
||||||
|
self.currentDetailPage = None
|
||||||
|
self.openGameDetailPage(*current_game)
|
||||||
|
|
||||||
self.settingsDebounceTimer.start()
|
self.settingsDebounceTimer.start()
|
||||||
|
|
||||||
self.settings_saved.emit()
|
self.settings_saved.emit()
|
||||||
@@ -1320,7 +1332,7 @@ class MainWindow(QMainWindow):
|
|||||||
def darkenColor(self, color, factor=200):
|
def darkenColor(self, color, factor=200):
|
||||||
return color.darker(factor)
|
return color.darker(factor)
|
||||||
|
|
||||||
def openGameDetailPage(self, name, description, cover_path=None, appid="", exec_line="", controller_support="", last_launch="", formatted_playtime="", protondb_tier="", steam_game="", anticheat_status=""):
|
def openGameDetailPage(self, name, description, cover_path=None, appid="", exec_line="", controller_support="", last_launch="", formatted_playtime="", protondb_tier="", game_source="", anticheat_status=""):
|
||||||
detailPage = QWidget()
|
detailPage = QWidget()
|
||||||
self._animations = {}
|
self._animations = {}
|
||||||
imageLabel = QLabel()
|
imageLabel = QLabel()
|
||||||
@@ -1388,7 +1400,11 @@ class MainWindow(QMainWindow):
|
|||||||
favoriteLabelCover.move(8, 8)
|
favoriteLabelCover.move(8, 8)
|
||||||
favoriteLabelCover.raise_()
|
favoriteLabelCover.raise_()
|
||||||
|
|
||||||
# Добавляем бейджи (ProtonDB, Steam, WeAntiCheatYet)
|
# Добавляем бейджи (ProtonDB, Steam, PortProton, WeAntiCheatYet)
|
||||||
|
display_filter = read_display_filter()
|
||||||
|
steam_visible = (str(game_source).lower() == "steam" and display_filter in ("all", "favorites"))
|
||||||
|
egs_visible = (str(game_source).lower() == "epic" and display_filter in ("all", "favorites"))
|
||||||
|
portproton_visible = (str(game_source).lower() == "portproton" and display_filter in ("all", "favorites"))
|
||||||
right_margin = 8
|
right_margin = 8
|
||||||
badge_spacing = 5
|
badge_spacing = 5
|
||||||
top_y = 10
|
top_y = 10
|
||||||
@@ -1428,7 +1444,6 @@ class MainWindow(QMainWindow):
|
|||||||
)
|
)
|
||||||
steamLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
steamLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
||||||
steamLabel.setFixedWidth(badge_width)
|
steamLabel.setFixedWidth(badge_width)
|
||||||
steam_visible = (str(steam_game).lower() == "true")
|
|
||||||
steamLabel.setVisible(steam_visible)
|
steamLabel.setVisible(steam_visible)
|
||||||
steamLabel.clicked.connect(lambda: QDesktopServices.openUrl(QUrl(f"https://steamcommunity.com/app/{appid}")))
|
steamLabel.clicked.connect(lambda: QDesktopServices.openUrl(QUrl(f"https://steamcommunity.com/app/{appid}")))
|
||||||
|
|
||||||
@@ -1440,12 +1455,26 @@ class MainWindow(QMainWindow):
|
|||||||
parent=coverFrame,
|
parent=coverFrame,
|
||||||
icon_size=16,
|
icon_size=16,
|
||||||
icon_space=5,
|
icon_space=5,
|
||||||
|
change_cursor=False
|
||||||
)
|
)
|
||||||
egsLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
egsLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
||||||
egsLabel.setFixedWidth(badge_width)
|
egsLabel.setFixedWidth(badge_width)
|
||||||
egs_visible = (str(steam_game).lower() == "epic")
|
|
||||||
egsLabel.setVisible(egs_visible)
|
egsLabel.setVisible(egs_visible)
|
||||||
|
|
||||||
|
# PortProton badge
|
||||||
|
portproton_icon = self.theme_manager.get_icon("ppqt-tray")
|
||||||
|
portprotonLabel = ClickableLabel(
|
||||||
|
"PortProton",
|
||||||
|
icon=portproton_icon,
|
||||||
|
parent=coverFrame,
|
||||||
|
icon_size=16,
|
||||||
|
icon_space=5,
|
||||||
|
change_cursor=False
|
||||||
|
)
|
||||||
|
portprotonLabel.setStyleSheet(self.theme.STEAM_BADGE_STYLE)
|
||||||
|
portprotonLabel.setFixedWidth(badge_width)
|
||||||
|
portprotonLabel.setVisible(portproton_visible)
|
||||||
|
|
||||||
# WeAntiCheatYet бейдж
|
# WeAntiCheatYet бейдж
|
||||||
anticheat_text = GameCard.getAntiCheatText(anticheat_status)
|
anticheat_text = GameCard.getAntiCheatText(anticheat_status)
|
||||||
if anticheat_text:
|
if anticheat_text:
|
||||||
@@ -1469,6 +1498,11 @@ class MainWindow(QMainWindow):
|
|||||||
anticheat_visible = False
|
anticheat_visible = False
|
||||||
|
|
||||||
# Расположение бейджей
|
# Расположение бейджей
|
||||||
|
right_margin = 8
|
||||||
|
badge_spacing = 5
|
||||||
|
top_y = 10
|
||||||
|
badge_y_positions = []
|
||||||
|
badge_width = int(300 * 2/3)
|
||||||
if steam_visible:
|
if steam_visible:
|
||||||
steam_x = 300 - badge_width - right_margin
|
steam_x = 300 - badge_width - right_margin
|
||||||
steamLabel.move(steam_x, top_y)
|
steamLabel.move(steam_x, top_y)
|
||||||
@@ -1478,6 +1512,11 @@ class MainWindow(QMainWindow):
|
|||||||
egs_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
egs_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
egsLabel.move(egs_x, egs_y)
|
egsLabel.move(egs_x, egs_y)
|
||||||
badge_y_positions.append(egs_y + egsLabel.height())
|
badge_y_positions.append(egs_y + egsLabel.height())
|
||||||
|
if portproton_visible:
|
||||||
|
portproton_x = 300 - badge_width - right_margin
|
||||||
|
portproton_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
|
portprotonLabel.move(portproton_x, portproton_y)
|
||||||
|
badge_y_positions.append(portproton_y + portprotonLabel.height())
|
||||||
if protondb_visible:
|
if protondb_visible:
|
||||||
protondb_x = 300 - badge_width - right_margin
|
protondb_x = 300 - badge_width - right_margin
|
||||||
protondb_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
protondb_y = badge_y_positions[-1] + badge_spacing if badge_y_positions else top_y
|
||||||
@@ -1490,6 +1529,8 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
anticheatLabel.raise_()
|
anticheatLabel.raise_()
|
||||||
protondbLabel.raise_()
|
protondbLabel.raise_()
|
||||||
|
portprotonLabel.raise_()
|
||||||
|
egsLabel.raise_()
|
||||||
steamLabel.raise_()
|
steamLabel.raise_()
|
||||||
|
|
||||||
contentFrameLayout.addWidget(coverFrame)
|
contentFrameLayout.addWidget(coverFrame)
|
||||||
@@ -1637,7 +1678,7 @@ class MainWindow(QMainWindow):
|
|||||||
focused_widget.last_launch,
|
focused_widget.last_launch,
|
||||||
focused_widget.formatted_playtime,
|
focused_widget.formatted_playtime,
|
||||||
focused_widget.protondb_tier,
|
focused_widget.protondb_tier,
|
||||||
focused_widget.steam_game
|
focused_widget.game_source
|
||||||
)
|
)
|
||||||
|
|
||||||
def goBackDetailPage(self, page: QWidget | None) -> None:
|
def goBackDetailPage(self, page: QWidget | None) -> None:
|
||||||
|
Reference in New Issue
Block a user