Compare commits
30 Commits
v0.1.2
...
d0eea92139
Author | SHA1 | Date | |
---|---|---|---|
d0eea92139
|
|||
04726491c0
|
|||
bd1b7c07ae
|
|||
e6161d2e3f
|
|||
b82080600f
|
|||
05693514aa
|
|||
1c2835a933
|
|||
d229914fb6
|
|||
ce69a18249
|
|||
4d58830910 | |||
016ba537be
|
|||
6eeb93f6ba
|
|||
3f5d058740
|
|||
1a9228b76d
|
|||
e9e0bea854
|
|||
f7d9f5c150
|
|||
bcb5987d31
|
|||
b1aa987e4e
|
|||
f4c8b70bd0
|
|||
ff960df77c
|
|||
a57f509295
|
|||
32bbe89911
|
|||
593db00166
|
|||
79a78c785b
|
|||
0b92d058a9
|
|||
9df22edfc9
|
|||
4559231712
|
|||
18dbd42369
|
|||
76c0e607c5
|
|||
a91c9dacd8
|
@@ -40,7 +40,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
fedora_version: [40, 41, 42, rawhide]
|
fedora_version: [41, 42, rawhide]
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: fedora:${{ matrix.fedora_version }}
|
image: fedora:${{ matrix.fedora_version }}
|
||||||
|
@@ -97,7 +97,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
fedora_version: [40, 41, 42, rawhide]
|
fedora_version: [41, 42, rawhide]
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: fedora:${{ matrix.fedora_version }}
|
image: fedora:${{ matrix.fedora_version }}
|
||||||
|
26
CHANGELOG.md
26
CHANGELOG.md
@@ -3,6 +3,23 @@
|
|||||||
Все заметные изменения в этом проекте фиксируются в этом файле.
|
Все заметные изменения в этом проекте фиксируются в этом файле.
|
||||||
Формат основан на [Keep a Changelog](https://keepachangelog.com/) и придерживается принципов [Semantic Versioning](https://semver.org/).
|
Формат основан на [Keep a Changelog](https://keepachangelog.com/) и придерживается принципов [Semantic Versioning](https://semver.org/).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Аргумент `--session` для запуска приложения в gamescope с GAMESCOPE_CMD
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Удалены сборки для Fedora 40
|
||||||
|
- Перенесены параметры анимации GameCard в `styles.py` с подробной документацией для поддержки кастомизации тем.
|
||||||
|
- Статус выделения и наведения на карточки теперь взаимоисключают друг друга
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Дублирование обводки выделения карточек при быстром перемешении мыши
|
||||||
|
- Завершение приложения при закритие окна
|
||||||
|
- Использование системной палитры в темах
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [0.1.2] - 2025-06-15
|
## [0.1.2] - 2025-06-15
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -64,6 +81,10 @@
|
|||||||
- Корректная обработка событий геймпада во время игры
|
- Корректная обработка событий геймпада во время игры
|
||||||
- Убийсво всех процессов "зомби" при закрытии программы
|
- Убийсво всех процессов "зомби" при закрытии программы
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
- @Vector_null
|
||||||
|
- @Dervart
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## [0.1.1] – 2025-05-17
|
## [0.1.1] – 2025-05-17
|
||||||
@@ -84,6 +105,11 @@
|
|||||||
- Зависание GUI
|
- Зависание GUI
|
||||||
- Сбой при повреждённом Steam
|
- Сбой при повреждённом Steam
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
- @Vector_null
|
||||||
|
- @Dervart
|
||||||
|
- @alex2844
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
> См. подробности по каждому коммиту в истории репозитория.
|
> См. подробности по каждому коммиту в истории репозитория.
|
||||||
|
10
README.md
10
README.md
@@ -4,7 +4,6 @@
|
|||||||
<p align="center">Удобный графический интерфейс для управления и запуска игр из PortProton, Steam и Epic Games Store. Оно объединяет библиотеки игр в единый центр для лёгкой навигации и организации. Лёгкая структура и кроссплатформенная поддержка обеспечивают цельный игровой опыт без необходимости использования нескольких лаунчеров. Интеграция с PortProton упрощает запуск Windows-игр на Linux с минимальной настройкой.</p>
|
<p align="center">Удобный графический интерфейс для управления и запуска игр из PortProton, Steam и Epic Games Store. Оно объединяет библиотеки игр в единый центр для лёгкой навигации и организации. Лёгкая структура и кроссплатформенная поддержка обеспечивают цельный игровой опыт без необходимости использования нескольких лаунчеров. Интеграция с PortProton упрощает запуск Windows-игр на Linux с минимальной настройкой.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## В планах
|
## В планах
|
||||||
|
|
||||||
- [X] Адаптировать структуру проекта для поддержки инструментов сборки
|
- [X] Адаптировать структуру проекта для поддержки инструментов сборки
|
||||||
@@ -15,7 +14,8 @@
|
|||||||
- [X] Вынести все константы, такие как уровень закругления карточек, в темы (частично выполнено)
|
- [X] Вынести все константы, такие как уровень закругления карточек, в темы (частично выполнено)
|
||||||
- [X] Добавить метаданные для тем (скриншоты, описание, домашняя страница и автор)
|
- [X] Добавить метаданные для тем (скриншоты, описание, домашняя страница и автор)
|
||||||
- [ ] Продумать систему вкладок вместо текущей
|
- [ ] Продумать систему вкладок вместо текущей
|
||||||
- [X] [Добавить сессию Gamescope, аналогичную той, что используется в SteamOS](https://git.linux-gaming.ru/Boria138/gamescope-session-portprotonqt)
|
- [ ] [Добавить сессию Gamescope, аналогичную той, что используется в SteamOS](https://git.linux-gaming.ru/Boria138/gamescope-session-portprotonqt)
|
||||||
|
- [ ] Разобраться почему теряется часть стилей в Gamescope
|
||||||
- [ ] Разработать адаптивный дизайн (за эталон берётся Steam Deck с разрешением 1280×800)
|
- [ ] Разработать адаптивный дизайн (за эталон берётся Steam Deck с разрешением 1280×800)
|
||||||
- [ ] Переделать скриншоты для соответствия [гайдлайнам Flathub](https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/quality-guidelines#screenshots)
|
- [ ] Переделать скриншоты для соответствия [гайдлайнам Flathub](https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/quality-guidelines#screenshots)
|
||||||
- [X] Получать описания и названия игр из базы данных Steam
|
- [X] Получать описания и названия игр из базы данных Steam
|
||||||
@@ -41,7 +41,10 @@
|
|||||||
- [X] Добавить парсинг ярлыков из Steam
|
- [X] Добавить парсинг ярлыков из Steam
|
||||||
- [X] Добавить парсинг ярлыков из EGS (скрыто для переработки)
|
- [X] Добавить парсинг ярлыков из EGS (скрыто для переработки)
|
||||||
- [ ] Избавиться от бинарника legendary
|
- [ ] Избавиться от бинарника legendary
|
||||||
- [ ] Добавить запуск и скачивание игр из EGS
|
- [X] Добавить запуск игр из EGS
|
||||||
|
- [ ] Добавить скачивание игр из EGS
|
||||||
|
- [ ] Добавить поддержку запуска сторонних игр из EGS
|
||||||
|
- [ ] Добавить поддержку запуска игр с EOS
|
||||||
- [ ] Добавить авторизацию в EGS через WebView вместо ручного ввода
|
- [ ] Добавить авторизацию в EGS через WebView вместо ручного ввода
|
||||||
- [X] Получать описания для игр из EGS через их [API](https://store-content.ak.epicgames.com/api)
|
- [X] Получать описания для игр из EGS через их [API](https://store-content.ak.epicgames.com/api)
|
||||||
- [X] Получать slug через GraphQL [запрос](https://launcher.store.epicgames.com/graphql)
|
- [X] Получать slug через GraphQL [запрос](https://launcher.store.epicgames.com/graphql)
|
||||||
@@ -68,6 +71,7 @@
|
|||||||
- [X] Скопировать логику управления с D-pad на стрелки с клавиатуры
|
- [X] Скопировать логику управления с D-pad на стрелки с клавиатуры
|
||||||
- [ ] Доделать светлую тему
|
- [ ] Доделать светлую тему
|
||||||
- [ ] Добавить подсказки к управлению с геймпада
|
- [ ] Добавить подсказки к управлению с геймпада
|
||||||
|
- [ ] Добавить загрузку звуков в темы например для добавления звука запуска в тему и тд
|
||||||
|
|
||||||
### Установка (devel)
|
### Установка (devel)
|
||||||
|
|
||||||
|
@@ -28,19 +28,19 @@ BuildRequires: git
|
|||||||
%package -n python3-%{pypi_name}-git
|
%package -n python3-%{pypi_name}-git
|
||||||
Summary: %{summary}
|
Summary: %{summary}
|
||||||
%{?python_provide:%python_provide python3-%{pypi_name}}
|
%{?python_provide:%python_provide python3-%{pypi_name}}
|
||||||
Requires: python3dist(babel)
|
Requires: python3-babel
|
||||||
Requires: python3dist(evdev)
|
Requires: python3-evdev
|
||||||
Requires: python3dist(icoextract)
|
Requires: python3-icoextract
|
||||||
Requires: python3dist(numpy)
|
Requires: python3-numpy
|
||||||
Requires: python3dist(orjson)
|
Requires: python3-orjson
|
||||||
Requires: python3dist(psutil)
|
Requires: python3-psutil
|
||||||
Requires: python3dist(pyside6)
|
Requires: python3-pyside6
|
||||||
Requires: python3dist(pyudev)
|
Requires: python3-pyudev
|
||||||
Requires: python3dist(requests)
|
Requires: python3-requests
|
||||||
Requires: python3dist(tqdm)
|
Requires: python3-tqdm
|
||||||
Requires: python3dist(vdf)
|
Requires: python3-vdf
|
||||||
Requires: python3dist(pefile)
|
Requires: python3-pefile
|
||||||
Requires: python3dist(pillow)
|
Requires: python3-pillow
|
||||||
Requires: perl-Image-ExifTool
|
Requires: perl-Image-ExifTool
|
||||||
Requires: xdg-utils
|
Requires: xdg-utils
|
||||||
|
|
||||||
|
@@ -25,19 +25,19 @@ BuildRequires: git
|
|||||||
%package -n python3-%{pypi_name}
|
%package -n python3-%{pypi_name}
|
||||||
Summary: %{summary}
|
Summary: %{summary}
|
||||||
%{?python_provide:%python_provide python3-%{pypi_name}}
|
%{?python_provide:%python_provide python3-%{pypi_name}}
|
||||||
Requires: python3dist(babel)
|
Requires: python3-babel
|
||||||
Requires: python3dist(evdev)
|
Requires: python3-evdev
|
||||||
Requires: python3dist(icoextract)
|
Requires: python3-icoextract
|
||||||
Requires: python3dist(numpy)
|
Requires: python3-numpy
|
||||||
Requires: python3dist(orjson)
|
Requires: python3-orjson
|
||||||
Requires: python3dist(psutil)
|
Requires: python3-psutil
|
||||||
Requires: python3dist(pyside6)
|
Requires: python3-pyside6
|
||||||
Requires: python3dist(pyudev)
|
Requires: python3-pyudev
|
||||||
Requires: python3dist(requests)
|
Requires: python3-requests
|
||||||
Requires: python3dist(tqdm)
|
Requires: python3-tqdm
|
||||||
Requires: python3dist(vdf)
|
Requires: python3-vdf
|
||||||
Requires: python3dist(pefile)
|
Requires: python3-pefile
|
||||||
Requires: python3dist(pillow)
|
Requires: python3-pillow
|
||||||
Requires: perl-Image-ExifTool
|
Requires: perl-Image-ExifTool
|
||||||
Requires: xdg-utils
|
Requires: xdg-utils
|
||||||
|
|
||||||
|
8
config.js
Normal file
8
config.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
"endpoint": "https://git.linux-gaming.ru/api/v1",
|
||||||
|
"gitAuthor": "Renovate Bot <noreply@linux-gaming.ru>",
|
||||||
|
"platform": "gitea",
|
||||||
|
"onboardingConfigFileName": "renovate.json",
|
||||||
|
"autodiscover": true,
|
||||||
|
"optimizeForDisabled": true,
|
||||||
|
};
|
@@ -1,4 +1,6 @@
|
|||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
from PySide6.QtCore import QLocale, QTranslator, QLibraryInfo
|
from PySide6.QtCore import QLocale, QTranslator, QLibraryInfo
|
||||||
from PySide6.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
from PySide6.QtGui import QIcon
|
from PySide6.QtGui import QIcon
|
||||||
@@ -33,6 +35,13 @@ def main():
|
|||||||
|
|
||||||
window = MainWindow()
|
window = MainWindow()
|
||||||
|
|
||||||
|
if args.session:
|
||||||
|
gamescope_cmd = os.getenv("GAMESCOPE_CMD", "gamescope -f --xwayland-count 2")
|
||||||
|
cmd = f"{gamescope_cmd} -- portprotonqt"
|
||||||
|
logger.info(f"Executing: {cmd}")
|
||||||
|
subprocess.Popen(cmd, shell=True)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
if args.fullscreen:
|
if args.fullscreen:
|
||||||
logger.info("Launching in fullscreen mode due to --fullscreen flag")
|
logger.info("Launching in fullscreen mode due to --fullscreen flag")
|
||||||
save_fullscreen_config(True)
|
save_fullscreen_config(True)
|
||||||
|
@@ -13,4 +13,9 @@ def parse_args():
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Запустить приложение в полноэкранном режиме и сохранить эту настройку"
|
help="Запустить приложение в полноэкранном режиме и сохранить эту настройку"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--session",
|
||||||
|
action="store_true",
|
||||||
|
help="Запустить приложение с использованием gamescope"
|
||||||
|
)
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
@@ -25,6 +25,8 @@ class GameCard(QFrame):
|
|||||||
addToSteamRequested = Signal(str, str, str) # name, exec_line, cover_path
|
addToSteamRequested = Signal(str, str, str) # name, exec_line, cover_path
|
||||||
removeFromSteamRequested = Signal(str, str) # name, exec_line
|
removeFromSteamRequested = Signal(str, str) # name, exec_line
|
||||||
openGameFolderRequested = Signal(str, str) # name, exec_line
|
openGameFolderRequested = Signal(str, str) # name, exec_line
|
||||||
|
hoverChanged = Signal(str, bool)
|
||||||
|
focusChanged = Signal(str, bool)
|
||||||
|
|
||||||
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, game_source,
|
last_launch, formatted_playtime, protondb_tier, anticheat_status, last_launch_ts, playtime_seconds, game_source,
|
||||||
@@ -66,14 +68,14 @@ class GameCard(QFrame):
|
|||||||
self.setStyleSheet(self.theme.GAME_CARD_WINDOW_STYLE)
|
self.setStyleSheet(self.theme.GAME_CARD_WINDOW_STYLE)
|
||||||
|
|
||||||
# Параметры анимации обводки
|
# Параметры анимации обводки
|
||||||
self._borderWidth = 2
|
self._borderWidth = self.theme.GAME_CARD_ANIMATION["default_border_width"]
|
||||||
self._gradientAngle = 0.0
|
self._gradientAngle = self.theme.GAME_CARD_ANIMATION["gradient_start_angle"]
|
||||||
self._hovered = False
|
self._hovered = False
|
||||||
self._focused = False
|
self._focused = False
|
||||||
|
|
||||||
# Анимации
|
# Анимации
|
||||||
self.thickness_anim = QPropertyAnimation(self, QByteArray(b"borderWidth"))
|
self.thickness_anim = QPropertyAnimation(self, QByteArray(b"borderWidth"))
|
||||||
self.thickness_anim.setDuration(300)
|
self.thickness_anim.setDuration(self.theme.GAME_CARD_ANIMATION["thickness_anim_duration"])
|
||||||
self.gradient_anim = None
|
self.gradient_anim = None
|
||||||
self.pulse_anim = None
|
self.pulse_anim = None
|
||||||
|
|
||||||
@@ -447,10 +449,8 @@ class GameCard(QFrame):
|
|||||||
if self._hovered or self._focused:
|
if self._hovered or self._focused:
|
||||||
center = self.rect().center()
|
center = self.rect().center()
|
||||||
gradient = QConicalGradient(center, self._gradientAngle)
|
gradient = QConicalGradient(center, self._gradientAngle)
|
||||||
gradient.setColorAt(0, QColor("#00fff5"))
|
for stop in self.theme.GAME_CARD_ANIMATION["gradient_colors"]:
|
||||||
gradient.setColorAt(0.33, QColor("#FF5733"))
|
gradient.setColorAt(stop["position"], QColor(stop["color"]))
|
||||||
gradient.setColorAt(0.66, QColor("#9B59B6"))
|
|
||||||
gradient.setColorAt(1, QColor("#00fff5"))
|
|
||||||
pen.setBrush(QBrush(gradient))
|
pen.setBrush(QBrush(gradient))
|
||||||
else:
|
else:
|
||||||
pen.setColor(QColor(0, 0, 0, 0))
|
pen.setColor(QColor(0, 0, 0, 0))
|
||||||
@@ -467,22 +467,25 @@ class GameCard(QFrame):
|
|||||||
if self.pulse_anim:
|
if self.pulse_anim:
|
||||||
self.pulse_anim.stop()
|
self.pulse_anim.stop()
|
||||||
self.pulse_anim = QPropertyAnimation(self, QByteArray(b"borderWidth"))
|
self.pulse_anim = QPropertyAnimation(self, QByteArray(b"borderWidth"))
|
||||||
self.pulse_anim.setDuration(800)
|
self.pulse_anim.setDuration(self.theme.GAME_CARD_ANIMATION["pulse_anim_duration"])
|
||||||
self.pulse_anim.setLoopCount(0)
|
self.pulse_anim.setLoopCount(0)
|
||||||
self.pulse_anim.setKeyValueAt(0, 8)
|
self.pulse_anim.setKeyValueAt(0, self.theme.GAME_CARD_ANIMATION["pulse_min_border_width"])
|
||||||
self.pulse_anim.setKeyValueAt(0.5, 10)
|
self.pulse_anim.setKeyValueAt(0.5, self.theme.GAME_CARD_ANIMATION["pulse_max_border_width"])
|
||||||
self.pulse_anim.setKeyValueAt(1, 8)
|
self.pulse_anim.setKeyValueAt(1, self.theme.GAME_CARD_ANIMATION["pulse_min_border_width"])
|
||||||
self.pulse_anim.start()
|
self.pulse_anim.start()
|
||||||
|
|
||||||
def enterEvent(self, event):
|
def enterEvent(self, event):
|
||||||
self._hovered = True
|
self._hovered = True
|
||||||
|
self.hoverChanged.emit(self.name, True)
|
||||||
|
self.setFocus(Qt.FocusReason.MouseFocusReason)
|
||||||
|
|
||||||
self.thickness_anim.stop()
|
self.thickness_anim.stop()
|
||||||
if self._isPulseAnimationConnected:
|
if self._isPulseAnimationConnected:
|
||||||
self.thickness_anim.finished.disconnect(self.startPulseAnimation)
|
self.thickness_anim.finished.disconnect(self.startPulseAnimation)
|
||||||
self._isPulseAnimationConnected = False
|
self._isPulseAnimationConnected = False
|
||||||
self.thickness_anim.setEasingCurve(QEasingCurve(QEasingCurve.Type.OutBack))
|
self.thickness_anim.setEasingCurve(QEasingCurve(QEasingCurve.Type[self.theme.GAME_CARD_ANIMATION["thickness_easing_curve"]]))
|
||||||
self.thickness_anim.setStartValue(self._borderWidth)
|
self.thickness_anim.setStartValue(self._borderWidth)
|
||||||
self.thickness_anim.setEndValue(8)
|
self.thickness_anim.setEndValue(self.theme.GAME_CARD_ANIMATION["hover_border_width"])
|
||||||
self.thickness_anim.finished.connect(self.startPulseAnimation)
|
self.thickness_anim.finished.connect(self.startPulseAnimation)
|
||||||
self._isPulseAnimationConnected = True
|
self._isPulseAnimationConnected = True
|
||||||
self.thickness_anim.start()
|
self.thickness_anim.start()
|
||||||
@@ -490,9 +493,9 @@ class GameCard(QFrame):
|
|||||||
if self.gradient_anim:
|
if self.gradient_anim:
|
||||||
self.gradient_anim.stop()
|
self.gradient_anim.stop()
|
||||||
self.gradient_anim = QPropertyAnimation(self, QByteArray(b"gradientAngle"))
|
self.gradient_anim = QPropertyAnimation(self, QByteArray(b"gradientAngle"))
|
||||||
self.gradient_anim.setDuration(3000)
|
self.gradient_anim.setDuration(self.theme.GAME_CARD_ANIMATION["gradient_anim_duration"])
|
||||||
self.gradient_anim.setStartValue(360)
|
self.gradient_anim.setStartValue(self.theme.GAME_CARD_ANIMATION["gradient_start_angle"])
|
||||||
self.gradient_anim.setEndValue(0)
|
self.gradient_anim.setEndValue(self.theme.GAME_CARD_ANIMATION["gradient_end_angle"])
|
||||||
self.gradient_anim.setLoopCount(-1)
|
self.gradient_anim.setLoopCount(-1)
|
||||||
self.gradient_anim.start()
|
self.gradient_anim.start()
|
||||||
|
|
||||||
@@ -500,33 +503,37 @@ class GameCard(QFrame):
|
|||||||
|
|
||||||
def leaveEvent(self, event):
|
def leaveEvent(self, event):
|
||||||
self._hovered = False
|
self._hovered = False
|
||||||
if not self._focused: # Сохраняем анимацию, если есть фокус
|
self.hoverChanged.emit(self.name, False)
|
||||||
|
if not self._focused:
|
||||||
if self.gradient_anim:
|
if self.gradient_anim:
|
||||||
self.gradient_anim.stop()
|
self.gradient_anim.stop()
|
||||||
self.gradient_anim = None
|
self.gradient_anim = None
|
||||||
self.thickness_anim.stop()
|
|
||||||
if self._isPulseAnimationConnected:
|
|
||||||
self.thickness_anim.finished.disconnect(self.startPulseAnimation)
|
|
||||||
self._isPulseAnimationConnected = False
|
|
||||||
if self.pulse_anim:
|
if self.pulse_anim:
|
||||||
self.pulse_anim.stop()
|
self.pulse_anim.stop()
|
||||||
self.pulse_anim = None
|
self.pulse_anim = None
|
||||||
self.thickness_anim.setEasingCurve(QEasingCurve(QEasingCurve.Type.InBack))
|
if self.thickness_anim:
|
||||||
self.thickness_anim.setStartValue(self._borderWidth)
|
|
||||||
self.thickness_anim.setEndValue(2)
|
|
||||||
self.thickness_anim.start()
|
|
||||||
|
|
||||||
super().leaveEvent(event)
|
|
||||||
|
|
||||||
def focusInEvent(self, event):
|
|
||||||
self._focused = True
|
|
||||||
self.thickness_anim.stop()
|
self.thickness_anim.stop()
|
||||||
if self._isPulseAnimationConnected:
|
if self._isPulseAnimationConnected:
|
||||||
self.thickness_anim.finished.disconnect(self.startPulseAnimation)
|
self.thickness_anim.finished.disconnect(self.startPulseAnimation)
|
||||||
self._isPulseAnimationConnected = False
|
self._isPulseAnimationConnected = False
|
||||||
self.thickness_anim.setEasingCurve(QEasingCurve(QEasingCurve.Type.OutBack))
|
self.thickness_anim.setEasingCurve(QEasingCurve(QEasingCurve.Type[self.theme.GAME_CARD_ANIMATION["thickness_easing_curve_out"]]))
|
||||||
self.thickness_anim.setStartValue(self._borderWidth)
|
self.thickness_anim.setStartValue(self._borderWidth)
|
||||||
self.thickness_anim.setEndValue(12)
|
self.thickness_anim.setEndValue(self.theme.GAME_CARD_ANIMATION["default_border_width"])
|
||||||
|
self.thickness_anim.start()
|
||||||
|
super().leaveEvent(event)
|
||||||
|
|
||||||
|
def focusInEvent(self, event):
|
||||||
|
if not self._hovered:
|
||||||
|
self._focused = True
|
||||||
|
self.focusChanged.emit(self.name, True)
|
||||||
|
|
||||||
|
self.thickness_anim.stop()
|
||||||
|
if self._isPulseAnimationConnected:
|
||||||
|
self.thickness_anim.finished.disconnect(self.startPulseAnimation)
|
||||||
|
self._isPulseAnimationConnected = False
|
||||||
|
self.thickness_anim.setEasingCurve(QEasingCurve(QEasingCurve.Type[self.theme.GAME_CARD_ANIMATION["thickness_easing_curve"]]))
|
||||||
|
self.thickness_anim.setStartValue(self._borderWidth)
|
||||||
|
self.thickness_anim.setEndValue(self.theme.GAME_CARD_ANIMATION["focus_border_width"])
|
||||||
self.thickness_anim.finished.connect(self.startPulseAnimation)
|
self.thickness_anim.finished.connect(self.startPulseAnimation)
|
||||||
self._isPulseAnimationConnected = True
|
self._isPulseAnimationConnected = True
|
||||||
self.thickness_anim.start()
|
self.thickness_anim.start()
|
||||||
@@ -534,9 +541,9 @@ class GameCard(QFrame):
|
|||||||
if self.gradient_anim:
|
if self.gradient_anim:
|
||||||
self.gradient_anim.stop()
|
self.gradient_anim.stop()
|
||||||
self.gradient_anim = QPropertyAnimation(self, QByteArray(b"gradientAngle"))
|
self.gradient_anim = QPropertyAnimation(self, QByteArray(b"gradientAngle"))
|
||||||
self.gradient_anim.setDuration(3000)
|
self.gradient_anim.setDuration(self.theme.GAME_CARD_ANIMATION["gradient_anim_duration"])
|
||||||
self.gradient_anim.setStartValue(360)
|
self.gradient_anim.setStartValue(self.theme.GAME_CARD_ANIMATION["gradient_start_angle"])
|
||||||
self.gradient_anim.setEndValue(0)
|
self.gradient_anim.setEndValue(self.theme.GAME_CARD_ANIMATION["gradient_end_angle"])
|
||||||
self.gradient_anim.setLoopCount(-1)
|
self.gradient_anim.setLoopCount(-1)
|
||||||
self.gradient_anim.start()
|
self.gradient_anim.start()
|
||||||
|
|
||||||
@@ -544,22 +551,23 @@ class GameCard(QFrame):
|
|||||||
|
|
||||||
def focusOutEvent(self, event):
|
def focusOutEvent(self, event):
|
||||||
self._focused = False
|
self._focused = False
|
||||||
if not self._hovered: # Сохраняем анимацию, если есть наведение
|
self.focusChanged.emit(self.name, False)
|
||||||
|
if not self._hovered:
|
||||||
if self.gradient_anim:
|
if self.gradient_anim:
|
||||||
self.gradient_anim.stop()
|
self.gradient_anim.stop()
|
||||||
self.gradient_anim = None
|
self.gradient_anim = None
|
||||||
|
if self.pulse_anim:
|
||||||
|
self.pulse_anim.stop()
|
||||||
|
self.pulse_anim = None
|
||||||
|
if self.thickness_anim:
|
||||||
self.thickness_anim.stop()
|
self.thickness_anim.stop()
|
||||||
if self._isPulseAnimationConnected:
|
if self._isPulseAnimationConnected:
|
||||||
self.thickness_anim.finished.disconnect(self.startPulseAnimation)
|
self.thickness_anim.finished.disconnect(self.startPulseAnimation)
|
||||||
self._isPulseAnimationConnected = False
|
self._isPulseAnimationConnected = False
|
||||||
if self.pulse_anim:
|
self.thickness_anim.setEasingCurve(QEasingCurve(QEasingCurve.Type[self.theme.GAME_CARD_ANIMATION["thickness_easing_curve_out"]]))
|
||||||
self.pulse_anim.stop()
|
|
||||||
self.pulse_anim = None
|
|
||||||
self.thickness_anim.setEasingCurve(QEasingCurve(QEasingCurve.Type.InBack))
|
|
||||||
self.thickness_anim.setStartValue(self._borderWidth)
|
self.thickness_anim.setStartValue(self._borderWidth)
|
||||||
self.thickness_anim.setEndValue(2)
|
self.thickness_anim.setEndValue(self.theme.GAME_CARD_ANIMATION["default_border_width"])
|
||||||
self.thickness_anim.start()
|
self.thickness_anim.start()
|
||||||
|
|
||||||
super().focusOutEvent(event)
|
super().focusOutEvent(event)
|
||||||
|
|
||||||
def mousePressEvent(self, event):
|
def mousePressEvent(self, event):
|
||||||
|
@@ -52,10 +52,12 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
QApplication.setStyle("Fusion")
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
self.current_exec_line = None
|
self.current_exec_line = None
|
||||||
self.currentDetailPage = None
|
self.currentDetailPage = None
|
||||||
self.current_play_button = None
|
self.current_play_button = None
|
||||||
|
self.current_focused_card = None
|
||||||
self.pending_games = []
|
self.pending_games = []
|
||||||
self.game_card_cache = {}
|
self.game_card_cache = {}
|
||||||
self.pending_images = {}
|
self.pending_images = {}
|
||||||
@@ -65,6 +67,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.games_load_timer.timeout.connect(self.finalize_game_loading)
|
self.games_load_timer.timeout.connect(self.finalize_game_loading)
|
||||||
self.games_loaded.connect(self.on_games_loaded)
|
self.games_loaded.connect(self.on_games_loaded)
|
||||||
self.current_add_game_dialog = None
|
self.current_add_game_dialog = None
|
||||||
|
self.current_hovered_card = None
|
||||||
|
|
||||||
# Добавляем таймер для дебаунсинга сохранения настроек
|
# Добавляем таймер для дебаунсинга сохранения настроек
|
||||||
self.settingsDebounceTimer = QTimer(self)
|
self.settingsDebounceTimer = QTimer(self)
|
||||||
@@ -241,6 +244,65 @@ class MainWindow(QMainWindow):
|
|||||||
self.updateGameGrid()
|
self.updateGameGrid()
|
||||||
self.progress_bar.setVisible(False)
|
self.progress_bar.setVisible(False)
|
||||||
|
|
||||||
|
def _on_card_focused(self, game_name: str, is_focused: bool):
|
||||||
|
"""Обработчик сигнала focusChanged от GameCard."""
|
||||||
|
card_key = None
|
||||||
|
for key, card in self.game_card_cache.items():
|
||||||
|
if card.name == game_name:
|
||||||
|
card_key = key
|
||||||
|
break
|
||||||
|
|
||||||
|
if not card_key:
|
||||||
|
return
|
||||||
|
|
||||||
|
card = self.game_card_cache[card_key]
|
||||||
|
|
||||||
|
if is_focused:
|
||||||
|
# Если карточка получила фокус
|
||||||
|
if self.current_hovered_card and self.current_hovered_card != card:
|
||||||
|
# Сбрасываем текущую hovered карточку
|
||||||
|
self.current_hovered_card._hovered = False
|
||||||
|
self.current_hovered_card.leaveEvent(None)
|
||||||
|
self.current_hovered_card = None
|
||||||
|
if self.current_focused_card and self.current_focused_card != card:
|
||||||
|
# Сбрасываем текущую focused карточку
|
||||||
|
self.current_focused_card._focused = False
|
||||||
|
self.current_focused_card.clearFocus()
|
||||||
|
self.current_focused_card = card
|
||||||
|
else:
|
||||||
|
# Если карточка потеряла фокус
|
||||||
|
if self.current_focused_card == card:
|
||||||
|
self.current_focused_card = None
|
||||||
|
|
||||||
|
def _on_card_hovered(self, game_name: str, is_hovered: bool):
|
||||||
|
"""Обработчик сигнала hoverChanged от GameCard."""
|
||||||
|
card_key = None
|
||||||
|
for key, card in self.game_card_cache.items():
|
||||||
|
if card.name == game_name:
|
||||||
|
card_key = key
|
||||||
|
break
|
||||||
|
|
||||||
|
if not card_key:
|
||||||
|
return
|
||||||
|
|
||||||
|
card = self.game_card_cache[card_key]
|
||||||
|
|
||||||
|
if is_hovered:
|
||||||
|
# Если мышь наведена на карточку
|
||||||
|
if self.current_focused_card and self.current_focused_card != card:
|
||||||
|
# Сбрасываем текущую focused карточку
|
||||||
|
self.current_focused_card._focused = False
|
||||||
|
self.current_focused_card.clearFocus()
|
||||||
|
if self.current_hovered_card and self.current_hovered_card != card:
|
||||||
|
# Сбрасываем предыдущую hovered карточку
|
||||||
|
self.current_hovered_card._hovered = False
|
||||||
|
self.current_hovered_card.leaveEvent(None)
|
||||||
|
self.current_hovered_card = card
|
||||||
|
else:
|
||||||
|
# Если мышь покинула карточку
|
||||||
|
if self.current_hovered_card == card:
|
||||||
|
self.current_hovered_card = None
|
||||||
|
|
||||||
def loadGames(self):
|
def loadGames(self):
|
||||||
display_filter = read_display_filter()
|
display_filter = read_display_filter()
|
||||||
favorites = read_favorites()
|
favorites = read_favorites()
|
||||||
@@ -681,6 +743,8 @@ class MainWindow(QMainWindow):
|
|||||||
card_width=self.card_width,
|
card_width=self.card_width,
|
||||||
context_menu_manager=self.context_menu_manager
|
context_menu_manager=self.context_menu_manager
|
||||||
)
|
)
|
||||||
|
card.hoverChanged.connect(self._on_card_hovered)
|
||||||
|
card.focusChanged.connect(self._on_card_focused)
|
||||||
# Подключаем сигналы контекстного меню
|
# Подключаем сигналы контекстного меню
|
||||||
card.editShortcutRequested.connect(self.context_menu_manager.edit_game_shortcut)
|
card.editShortcutRequested.connect(self.context_menu_manager.edit_game_shortcut)
|
||||||
card.deleteGameRequested.connect(self.context_menu_manager.delete_game)
|
card.deleteGameRequested.connect(self.context_menu_manager.delete_game)
|
||||||
@@ -1853,7 +1917,6 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
"""Завершает все дочерние процессы и сохраняет настройки при закрытии окна."""
|
"""Завершает все дочерние процессы и сохраняет настройки при закрытии окна."""
|
||||||
# Завершаем все игровые процессы
|
|
||||||
for proc in self.game_processes:
|
for proc in self.game_processes:
|
||||||
try:
|
try:
|
||||||
parent = psutil.Process(proc.pid)
|
parent = psutil.Process(proc.pid)
|
||||||
@@ -1894,4 +1957,5 @@ class MainWindow(QMainWindow):
|
|||||||
self.checkProcessTimer.deleteLater()
|
self.checkProcessTimer.deleteLater()
|
||||||
self.checkProcessTimer = None
|
self.checkProcessTimer = None
|
||||||
|
|
||||||
|
QApplication.quit()
|
||||||
event.accept()
|
event.accept()
|
||||||
|
@@ -20,8 +20,12 @@ class SystemOverlay(QDialog):
|
|||||||
self.theme_manager = ThemeManager()
|
self.theme_manager = ThemeManager()
|
||||||
self.setStyleSheet(self.theme.OVERLAY_WINDOW_STYLE)
|
self.setStyleSheet(self.theme.OVERLAY_WINDOW_STYLE)
|
||||||
|
|
||||||
# Убираем рамку окна
|
# Make window stay on top and frameless
|
||||||
self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Dialog)
|
self.setWindowFlags(
|
||||||
|
Qt.WindowType.FramelessWindowHint |
|
||||||
|
Qt.WindowType.Dialog |
|
||||||
|
Qt.WindowType.WindowStaysOnTopHint
|
||||||
|
)
|
||||||
|
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
layout.setContentsMargins(20, 20, 20, 20)
|
layout.setContentsMargins(20, 20, 20, 20)
|
||||||
|
@@ -8,6 +8,76 @@ current_theme_name = read_theme_from_config()
|
|||||||
favoriteLabelSize = 48, 48
|
favoriteLabelSize = 48, 48
|
||||||
pixmapsScaledSize = 60, 60
|
pixmapsScaledSize = 60, 60
|
||||||
|
|
||||||
|
GAME_CARD_ANIMATION = {
|
||||||
|
# Ширина обводки карточки в состоянии покоя (без наведения или фокуса).
|
||||||
|
# Влияет на толщину рамки вокруг карточки, когда она не выделена.
|
||||||
|
# Значение в пикселях.
|
||||||
|
"default_border_width": 2,
|
||||||
|
|
||||||
|
# Ширина обводки при наведении курсора.
|
||||||
|
# Увеличивает толщину рамки, когда курсор находится над карточкой.
|
||||||
|
# Значение в пикселях.
|
||||||
|
"hover_border_width": 8,
|
||||||
|
|
||||||
|
# Ширина обводки при фокусе (например, при выборе с клавиатуры).
|
||||||
|
# Увеличивает толщину рамки, когда карточка в фокусе.
|
||||||
|
# Значение в пикселях.
|
||||||
|
"focus_border_width": 12,
|
||||||
|
|
||||||
|
# Минимальная ширина обводки во время пульсирующей анимации.
|
||||||
|
# Определяет минимальную толщину рамки при пульсации (анимация "дыхания").
|
||||||
|
# Значение в пикселях.
|
||||||
|
"pulse_min_border_width": 8,
|
||||||
|
|
||||||
|
# Максимальная ширина обводки во время пульсирующей анимации.
|
||||||
|
# Определяет максимальную толщину рамки при пульсации.
|
||||||
|
# Значение в пикселях.
|
||||||
|
"pulse_max_border_width": 10,
|
||||||
|
|
||||||
|
# Длительность анимации изменения толщины обводки (например, при наведении или фокусе).
|
||||||
|
# Влияет на скорость перехода от одной ширины обводки к другой.
|
||||||
|
# Значение в миллисекундах.
|
||||||
|
"thickness_anim_duration": 300,
|
||||||
|
|
||||||
|
# Длительность одного цикла пульсирующей анимации.
|
||||||
|
# Определяет, как быстро рамка "пульсирует" между min и max значениями.
|
||||||
|
# Значение в миллисекундах.
|
||||||
|
"pulse_anim_duration": 800,
|
||||||
|
|
||||||
|
# Длительность анимации вращения градиента.
|
||||||
|
# Влияет на скорость, с которой градиентная обводка вращается вокруг карточки.
|
||||||
|
# Значение в миллисекундах.
|
||||||
|
"gradient_anim_duration": 3000,
|
||||||
|
|
||||||
|
# Начальный угол градиента (в градусах).
|
||||||
|
# Определяет начальную точку вращения градиента при старте анимации.
|
||||||
|
"gradient_start_angle": 360,
|
||||||
|
|
||||||
|
# Конечный угол градиента (в градусах).
|
||||||
|
# Определяет конечную точку вращения градиента.
|
||||||
|
# Значение 0 означает полный поворот на 360 градусов.
|
||||||
|
"gradient_end_angle": 0,
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации увеличения обводки (при наведении/фокусе).
|
||||||
|
# Влияет на "чувство" анимации (например, плавное ускорение или замедление).
|
||||||
|
# Возможные значения: строки, соответствующие QEasingCurve.Type (например, "OutBack", "InOutQuad").
|
||||||
|
"thickness_easing_curve": "OutBack",
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации уменьшения обводки (при уходе курсора/потере фокуса).
|
||||||
|
# Влияет на "чувство" возврата к исходной ширине обводки.
|
||||||
|
"thickness_easing_curve_out": "InBack",
|
||||||
|
|
||||||
|
# Цвета градиента для анимированной обводки.
|
||||||
|
# Список словарей, где каждый словарь задает позицию (0.0–1.0) и цвет в формате hex.
|
||||||
|
# Влияет на внешний вид обводки при наведении или фокусе.
|
||||||
|
"gradient_colors": [
|
||||||
|
{"position": 0, "color": "#00fff5"}, # Начальный цвет (циан)
|
||||||
|
{"position": 0.33, "color": "#FF5733"}, # Цвет на 33% (оранжевый)
|
||||||
|
{"position": 0.66, "color": "#9B59B6"}, # Цвет на 66% (пурпурный)
|
||||||
|
{"position": 1, "color": "#00fff5"} # Конечный цвет (возвращение к циану)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
# СТИЛЬ ШАПКИ ГЛАВНОГО ОКНА
|
# СТИЛЬ ШАПКИ ГЛАВНОГО ОКНА
|
||||||
MAIN_WINDOW_HEADER_STYLE = """
|
MAIN_WINDOW_HEADER_STYLE = """
|
||||||
QFrame {
|
QFrame {
|
||||||
|
@@ -8,6 +8,76 @@ current_theme_name = read_theme_from_config()
|
|||||||
favoriteLabelSize = 48, 48
|
favoriteLabelSize = 48, 48
|
||||||
pixmapsScaledSize = 60, 60
|
pixmapsScaledSize = 60, 60
|
||||||
|
|
||||||
|
GAME_CARD_ANIMATION = {
|
||||||
|
# Ширина обводки карточки в состоянии покоя (без наведения или фокуса).
|
||||||
|
# Влияет на толщину рамки вокруг карточки, когда она не выделена.
|
||||||
|
# Значение в пикселях.
|
||||||
|
"default_border_width": 2,
|
||||||
|
|
||||||
|
# Ширина обводки при наведении курсора.
|
||||||
|
# Увеличивает толщину рамки, когда курсор находится над карточкой.
|
||||||
|
# Значение в пикселях.
|
||||||
|
"hover_border_width": 8,
|
||||||
|
|
||||||
|
# Ширина обводки при фокусе (например, при выборе с клавиатуры).
|
||||||
|
# Увеличивает толщину рамки, когда карточка в фокусе.
|
||||||
|
# Значение в пикселях.
|
||||||
|
"focus_border_width": 12,
|
||||||
|
|
||||||
|
# Минимальная ширина обводки во время пульсирующей анимации.
|
||||||
|
# Определяет минимальную толщину рамки при пульсации (анимация "дыхания").
|
||||||
|
# Значение в пикселях.
|
||||||
|
"pulse_min_border_width": 8,
|
||||||
|
|
||||||
|
# Максимальная ширина обводки во время пульсирующей анимации.
|
||||||
|
# Определяет максимальную толщину рамки при пульсации.
|
||||||
|
# Значение в пикселях.
|
||||||
|
"pulse_max_border_width": 10,
|
||||||
|
|
||||||
|
# Длительность анимации изменения толщины обводки (например, при наведении или фокусе).
|
||||||
|
# Влияет на скорость перехода от одной ширины обводки к другой.
|
||||||
|
# Значение в миллисекундах.
|
||||||
|
"thickness_anim_duration": 300,
|
||||||
|
|
||||||
|
# Длительность одного цикла пульсирующей анимации.
|
||||||
|
# Определяет, как быстро рамка "пульсирует" между min и max значениями.
|
||||||
|
# Значение в миллисекундах.
|
||||||
|
"pulse_anim_duration": 800,
|
||||||
|
|
||||||
|
# Длительность анимации вращения градиента.
|
||||||
|
# Влияет на скорость, с которой градиентная обводка вращается вокруг карточки.
|
||||||
|
# Значение в миллисекундах.
|
||||||
|
"gradient_anim_duration": 3000,
|
||||||
|
|
||||||
|
# Начальный угол градиента (в градусах).
|
||||||
|
# Определяет начальную точку вращения градиента при старте анимации.
|
||||||
|
"gradient_start_angle": 360,
|
||||||
|
|
||||||
|
# Конечный угол градиента (в градусах).
|
||||||
|
# Определяет конечную точку вращения градиента.
|
||||||
|
# Значение 0 означает полный поворот на 360 градусов.
|
||||||
|
"gradient_end_angle": 0,
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации увеличения обводки (при наведении/фокусе).
|
||||||
|
# Влияет на "чувство" анимации (например, плавное ускорение или замедление).
|
||||||
|
# Возможные значения: строки, соответствующие QEasingCurve.Type (например, "OutBack", "InOutQuad").
|
||||||
|
"thickness_easing_curve": "OutBack",
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации уменьшения обводки (при уходе курсора/потере фокуса).
|
||||||
|
# Влияет на "чувство" возврата к исходной ширине обводки.
|
||||||
|
"thickness_easing_curve_out": "InBack",
|
||||||
|
|
||||||
|
# Цвета градиента для анимированной обводки.
|
||||||
|
# Список словарей, где каждый словарь задает позицию (0.0–1.0) и цвет в формате hex.
|
||||||
|
# Влияет на внешний вид обводки при наведении или фокусе.
|
||||||
|
"gradient_colors": [
|
||||||
|
{"position": 0, "color": "#00fff5"}, # Начальный цвет (циан)
|
||||||
|
{"position": 0.33, "color": "#FF5733"}, # Цвет на 33% (оранжевый)
|
||||||
|
{"position": 0.66, "color": "#9B59B6"}, # Цвет на 66% (пурпурный)
|
||||||
|
{"position": 1, "color": "#00fff5"} # Конечный цвет (возвращение к циану)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
CONTEXT_MENU_STYLE = """
|
CONTEXT_MENU_STYLE = """
|
||||||
QMenu {
|
QMenu {
|
||||||
background: #282a33;;
|
background: #282a33;;
|
||||||
|
26
renovate.json
Normal file
26
renovate.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": ["config:best-practices"],
|
||||||
|
"rebaseWhen": "never",
|
||||||
|
"lockFileMaintenance": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"matchUpdateTypes": ["minor", "patch"],
|
||||||
|
"automerge": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"automerge": true,
|
||||||
|
"matchUpdateTypes": ["pin", "pinDigest"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enabled": false,
|
||||||
|
"matchFileNames": [".gitea/workflows/**.yaml", ".gitea/workflows/**.yml"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enabled": false,
|
||||||
|
"matchFileNames": [".python-version"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Reference in New Issue
Block a user