Compare commits
6 Commits
bcf319c024
...
647394ca92
Author | SHA1 | Date | |
---|---|---|---|
647394ca92
|
|||
14dc44d4f7
|
|||
34e70d05f3
|
|||
a21705da15
|
|||
1ea5fd710c
|
|||
4de4bdb99d
|
@@ -7,8 +7,6 @@
|
||||
|
||||
### Added
|
||||
- Кнопки сброса настроек и очистки кэша
|
||||
- Начальная интеграция с EGS с помощью [Legendary](https://github.com/derrod/legendary)
|
||||
- Бейдж EGS
|
||||
- Бейдж PortProton
|
||||
- Зависимость на `xdg-utils`
|
||||
- Интеграция статуса WeAntiCheatYet в карточку
|
||||
@@ -38,9 +36,12 @@
|
||||
- Установка ширины бейджа в две трети ширины карточки
|
||||
- Бейджи источников (`Steam`, `EGS`, `PortProton`) теперь отображаются только при активном фильтре `all` или `favorites`
|
||||
- Карточки теперь фокусируются в направлении движения стрелок или D-pad, например если нажать D-pad вниз то перейдёшь на карточку со следующей колонки, а не по порядку
|
||||
- Теперь D-pad можно зажимать для переключения карточек
|
||||
- D-pad больше не переключает вкладки только RB и LB
|
||||
- Кнопка добавления игры больше не фокусируется
|
||||
- Диалог добавления игры теперь открывается только в библиотеке
|
||||
- Аргумент --fullscreen для открытия приложения в режиме полноэкранного отображения
|
||||
- Оверлей на кнопку Xbox / PS для закрытия приложения, выключения, перезагрузки и ухода в сон
|
||||
|
||||
### Fixed
|
||||
- Обработка несуществующей темы с возвратом к “standart”
|
||||
|
@@ -20,9 +20,9 @@ Current translation status:
|
||||
|
||||
| Locale | Progress | Translated |
|
||||
| :----- | -------: | ---------: |
|
||||
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 of 154 |
|
||||
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 of 154 |
|
||||
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 154 of 154 |
|
||||
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 of 153 |
|
||||
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 of 153 |
|
||||
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 153 of 153 |
|
||||
|
||||
---
|
||||
|
||||
|
@@ -20,9 +20,9 @@
|
||||
|
||||
| Локаль | Прогресс | Переведено |
|
||||
| :----- | -------: | ---------: |
|
||||
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 из 154 |
|
||||
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 из 154 |
|
||||
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 154 из 154 |
|
||||
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 из 153 |
|
||||
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 из 153 |
|
||||
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 153 из 153 |
|
||||
|
||||
---
|
||||
|
||||
|
@@ -4,8 +4,9 @@ from PySide6.QtWidgets import QApplication
|
||||
from PySide6.QtGui import QIcon
|
||||
from portprotonqt.main_window import MainWindow
|
||||
from portprotonqt.tray import SystemTray
|
||||
from portprotonqt.config_utils import read_theme_from_config
|
||||
from portprotonqt.config_utils import read_theme_from_config, save_fullscreen_config
|
||||
from portprotonqt.logger import get_logger
|
||||
from portprotonqt.cli import parse_args
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -28,7 +29,17 @@ def main():
|
||||
else:
|
||||
logger.error(f"Qt translations for {system_locale.name()} not found in {translations_path}")
|
||||
|
||||
# Парсинг аргументов командной строки
|
||||
args = parse_args()
|
||||
|
||||
window = MainWindow()
|
||||
|
||||
# Обработка флага --fullscreen
|
||||
if args.fullscreen:
|
||||
logger.info("Запуск в полноэкранном режиме по флагу --fullscreen")
|
||||
save_fullscreen_config(True)
|
||||
window.showFullScreen()
|
||||
|
||||
current_theme_name = read_theme_from_config()
|
||||
tray = SystemTray(app, current_theme_name)
|
||||
tray.show_action.triggered.connect(window.show)
|
||||
@@ -43,7 +54,9 @@ def main():
|
||||
tray.hide_action.triggered.connect(window.hide)
|
||||
|
||||
window.settings_saved.connect(recreate_tray)
|
||||
|
||||
window.show()
|
||||
|
||||
sys.exit(app.exec())
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
16
portprotonqt/cli.py
Normal file
16
portprotonqt/cli.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import argparse
|
||||
from portprotonqt.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
def parse_args():
|
||||
"""
|
||||
Парсит аргументы командной строки.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description="PortProtonQT CLI")
|
||||
parser.add_argument(
|
||||
"--fullscreen",
|
||||
action="store_true",
|
||||
help="Запустить приложение в полноэкранном режиме и сохранить эту настройку"
|
||||
)
|
||||
return parser.parse_args()
|
@@ -4,7 +4,7 @@ from typing import Protocol, cast
|
||||
from evdev import InputDevice, ecodes, list_devices
|
||||
import pyudev
|
||||
from PySide6.QtWidgets import QWidget, QStackedWidget, QApplication, QScrollArea, QLineEdit, QDialog, QMenu, QComboBox, QListView
|
||||
from PySide6.QtCore import Qt, QObject, QEvent, QPoint, Signal, Slot
|
||||
from PySide6.QtCore import Qt, QObject, QEvent, QPoint, Signal, Slot, QTimer
|
||||
from PySide6.QtGui import QKeyEvent
|
||||
from portprotonqt.logger import get_logger
|
||||
from portprotonqt.image_utils import FullscreenDialog
|
||||
@@ -25,6 +25,8 @@ class MainWindowProtocol(Protocol):
|
||||
...
|
||||
def toggleGame(self, exec_line: str | None, button: QWidget | None = None) -> None:
|
||||
...
|
||||
def openSystemOverlay(self) -> None:
|
||||
...
|
||||
stackedWidget: QStackedWidget
|
||||
tabButtons: dict[int, QWidget]
|
||||
gamesListWidget: QWidget
|
||||
@@ -42,6 +44,7 @@ BUTTONS = {
|
||||
'confirm_stick': {ecodes.BTN_THUMBL, ecodes.BTN_THUMBR},
|
||||
'context_menu': {ecodes.BTN_START},
|
||||
'menu': {ecodes.BTN_SELECT},
|
||||
'guide': {ecodes.BTN_MODE},
|
||||
}
|
||||
|
||||
class InputManager(QObject):
|
||||
@@ -69,7 +72,6 @@ class InputManager(QObject):
|
||||
self._parent.currentDetailPage = getattr(self._parent, 'currentDetailPage', None)
|
||||
self._parent.current_exec_line = getattr(self._parent, 'current_exec_line', None)
|
||||
self._parent.current_add_game_dialog = getattr(self._parent, 'current_add_game_dialog', None)
|
||||
|
||||
self.axis_deadzone = axis_deadzone
|
||||
self.initial_axis_move_delay = initial_axis_move_delay
|
||||
self.repeat_axis_move_delay = repeat_axis_move_delay
|
||||
@@ -81,6 +83,12 @@ class InputManager(QObject):
|
||||
self.running = True
|
||||
self._is_fullscreen = read_fullscreen_config()
|
||||
|
||||
# Add variables for continuous D-pad movement
|
||||
self.dpad_timer = QTimer(self)
|
||||
self.dpad_timer.timeout.connect(self.handle_dpad_repeat)
|
||||
self.current_dpad_code = None # Tracks the current D-pad axis (e.g., ABS_HAT0X, ABS_HAT0Y)
|
||||
self.current_dpad_value = 0 # Tracks the current D-pad direction value (e.g., -1, 1)
|
||||
|
||||
# Connect signals to slots
|
||||
self.button_pressed.connect(self.handle_button_slot)
|
||||
self.dpad_moved.connect(self.handle_dpad_slot)
|
||||
@@ -131,6 +139,12 @@ class InputManager(QObject):
|
||||
focused = QApplication.focusWidget()
|
||||
popup = QApplication.activePopupWidget()
|
||||
|
||||
# Handle Guide button to open system overlay
|
||||
if button_code in BUTTONS['guide']:
|
||||
if not popup and not isinstance(active, QDialog):
|
||||
self._parent.openSystemOverlay()
|
||||
return
|
||||
|
||||
# Handle QMenu (context menu)
|
||||
if isinstance(popup, QMenu):
|
||||
if button_code in BUTTONS['confirm'] or button_code in BUTTONS['confirm_stick']:
|
||||
@@ -230,6 +244,15 @@ class InputManager(QObject):
|
||||
except Exception as e:
|
||||
logger.error(f"Error in handle_button_slot: {e}", exc_info=True)
|
||||
|
||||
def handle_dpad_repeat(self) -> None:
|
||||
"""Handle repeated D-pad input while the D-pad is held."""
|
||||
if self.current_dpad_code is not None and self.current_dpad_value != 0:
|
||||
now = time.time()
|
||||
if (now - self.last_move_time) >= self.current_axis_delay:
|
||||
self.handle_dpad_slot(self.current_dpad_code, self.current_dpad_value, now)
|
||||
self.last_move_time = now
|
||||
self.current_axis_delay = self.repeat_axis_move_delay
|
||||
|
||||
@Slot(int, int, float)
|
||||
def handle_dpad_slot(self, code: int, value: int, current_time: float) -> None:
|
||||
try:
|
||||
@@ -244,7 +267,24 @@ class InputManager(QObject):
|
||||
focused = QApplication.focusWidget()
|
||||
popup = QApplication.activePopupWidget()
|
||||
|
||||
# Handle AddGameDialog navigation with D-pad
|
||||
# Update D-pad state
|
||||
if value != 0:
|
||||
self.current_dpad_code = code
|
||||
self.current_dpad_value = value
|
||||
if not self.axis_moving:
|
||||
self.axis_moving = True
|
||||
self.last_move_time = current_time
|
||||
self.current_axis_delay = self.initial_axis_move_delay
|
||||
self.dpad_timer.start(int(self.repeat_axis_move_delay * 1000)) # Start timer (in milliseconds)
|
||||
else:
|
||||
self.current_dpad_code = None
|
||||
self.current_dpad_value = 0
|
||||
self.axis_moving = False
|
||||
self.current_axis_delay = self.initial_axis_move_delay
|
||||
self.dpad_timer.stop() # Stop timer when D-pad is released
|
||||
return
|
||||
|
||||
# Handle SystemOverlay or AddGameDialog navigation with D-pad
|
||||
if isinstance(active, QDialog) and code == ecodes.ABS_HAT0Y and value != 0:
|
||||
if not focused or not active.focusWidget():
|
||||
# If no widget is focused, focus the first focusable widget
|
||||
@@ -298,19 +338,6 @@ class InputManager(QObject):
|
||||
active.show_next()
|
||||
return
|
||||
|
||||
# Handle repeated D-pad movement
|
||||
if value != 0:
|
||||
if not self.axis_moving:
|
||||
self.axis_moving = True
|
||||
elif (current_time - self.last_move_time) < self.current_axis_delay:
|
||||
return
|
||||
self.last_move_time = current_time
|
||||
self.current_axis_delay = self.repeat_axis_move_delay
|
||||
else:
|
||||
self.axis_moving = False
|
||||
self.current_axis_delay = self.initial_axis_move_delay
|
||||
return
|
||||
|
||||
# Library tab navigation (index 0)
|
||||
if self._parent.stackedWidget.currentIndex() == 0 and code in (ecodes.ABS_HAT0X, ecodes.ABS_HAT0Y):
|
||||
focused = QApplication.focusWidget()
|
||||
@@ -774,6 +801,7 @@ class InputManager(QObject):
|
||||
def cleanup(self) -> None:
|
||||
try:
|
||||
self.running = False
|
||||
self.dpad_timer.stop()
|
||||
if self.gamepad_thread:
|
||||
self.gamepad_thread.join()
|
||||
if self.gamepad:
|
||||
|
Binary file not shown.
@@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2025-06-06 20:01+0500\n"
|
||||
"POT-Creation-Date: 2025-06-08 09:31+0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: de_DE\n"
|
||||
@@ -362,21 +362,6 @@ msgstr ""
|
||||
msgid "Auto Fullscreen on Gamepad connected:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open Legendary Login"
|
||||
msgstr ""
|
||||
|
||||
msgid "Legendary Authentication:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enter Legendary Authorization Code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Authorization Code:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Submit Code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Save Settings"
|
||||
msgstr ""
|
||||
|
||||
@@ -392,22 +377,6 @@ msgstr ""
|
||||
msgid "Failed to open Legendary login page"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please enter an authorization code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Successfully authenticated with Legendary"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Legendary authentication failed: {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Legendary executable not found"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unexpected error during authentication"
|
||||
msgstr ""
|
||||
|
||||
msgid "Confirm Reset"
|
||||
msgstr ""
|
||||
|
||||
@@ -505,6 +474,33 @@ msgstr ""
|
||||
msgid "Launching"
|
||||
msgstr ""
|
||||
|
||||
msgid "System Overlay"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reboot"
|
||||
msgstr ""
|
||||
|
||||
msgid "Shutdown"
|
||||
msgstr ""
|
||||
|
||||
msgid "Suspend"
|
||||
msgstr ""
|
||||
|
||||
msgid "Exit Application"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to reboot the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to shutdown the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to suspend the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "just now"
|
||||
msgstr ""
|
||||
|
||||
|
Binary file not shown.
@@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2025-06-06 20:01+0500\n"
|
||||
"POT-Creation-Date: 2025-06-08 09:31+0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: es_ES\n"
|
||||
@@ -362,21 +362,6 @@ msgstr ""
|
||||
msgid "Auto Fullscreen on Gamepad connected:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open Legendary Login"
|
||||
msgstr ""
|
||||
|
||||
msgid "Legendary Authentication:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enter Legendary Authorization Code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Authorization Code:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Submit Code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Save Settings"
|
||||
msgstr ""
|
||||
|
||||
@@ -392,22 +377,6 @@ msgstr ""
|
||||
msgid "Failed to open Legendary login page"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please enter an authorization code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Successfully authenticated with Legendary"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Legendary authentication failed: {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Legendary executable not found"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unexpected error during authentication"
|
||||
msgstr ""
|
||||
|
||||
msgid "Confirm Reset"
|
||||
msgstr ""
|
||||
|
||||
@@ -505,6 +474,33 @@ msgstr ""
|
||||
msgid "Launching"
|
||||
msgstr ""
|
||||
|
||||
msgid "System Overlay"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reboot"
|
||||
msgstr ""
|
||||
|
||||
msgid "Shutdown"
|
||||
msgstr ""
|
||||
|
||||
msgid "Suspend"
|
||||
msgstr ""
|
||||
|
||||
msgid "Exit Application"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to reboot the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to shutdown the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to suspend the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "just now"
|
||||
msgstr ""
|
||||
|
||||
|
@@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PortProtonQT 0.1.1\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2025-06-06 20:01+0500\n"
|
||||
"POT-Creation-Date: 2025-06-08 09:31+0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -360,21 +360,6 @@ msgstr ""
|
||||
msgid "Auto Fullscreen on Gamepad connected:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open Legendary Login"
|
||||
msgstr ""
|
||||
|
||||
msgid "Legendary Authentication:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enter Legendary Authorization Code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Authorization Code:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Submit Code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Save Settings"
|
||||
msgstr ""
|
||||
|
||||
@@ -390,22 +375,6 @@ msgstr ""
|
||||
msgid "Failed to open Legendary login page"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please enter an authorization code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Successfully authenticated with Legendary"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Legendary authentication failed: {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Legendary executable not found"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unexpected error during authentication"
|
||||
msgstr ""
|
||||
|
||||
msgid "Confirm Reset"
|
||||
msgstr ""
|
||||
|
||||
@@ -503,6 +472,33 @@ msgstr ""
|
||||
msgid "Launching"
|
||||
msgstr ""
|
||||
|
||||
msgid "System Overlay"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reboot"
|
||||
msgstr ""
|
||||
|
||||
msgid "Shutdown"
|
||||
msgstr ""
|
||||
|
||||
msgid "Suspend"
|
||||
msgstr ""
|
||||
|
||||
msgid "Exit Application"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to reboot the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to shutdown the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to suspend the system"
|
||||
msgstr ""
|
||||
|
||||
msgid "just now"
|
||||
msgstr ""
|
||||
|
||||
|
Binary file not shown.
@@ -9,8 +9,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2025-06-06 20:01+0500\n"
|
||||
"PO-Revision-Date: 2025-06-06 20:01+0500\n"
|
||||
"POT-Creation-Date: 2025-06-08 09:31+0500\n"
|
||||
"PO-Revision-Date: 2025-06-08 09:31+0500\n"
|
||||
"Last-Translator: \n"
|
||||
"Language: ru_RU\n"
|
||||
"Language-Team: ru_RU <LL@li.org>\n"
|
||||
@@ -369,21 +369,6 @@ msgstr "Режим полноэкранного отображения прил
|
||||
msgid "Auto Fullscreen on Gamepad connected:"
|
||||
msgstr "Режим полноэкранного отображения приложения при подключении геймпада:"
|
||||
|
||||
msgid "Open Legendary Login"
|
||||
msgstr "Открыть браузер для входа в Legendary"
|
||||
|
||||
msgid "Legendary Authentication:"
|
||||
msgstr "Авторизация в Legendary:"
|
||||
|
||||
msgid "Enter Legendary Authorization Code"
|
||||
msgstr "Введите код авторизации Legendary"
|
||||
|
||||
msgid "Authorization Code:"
|
||||
msgstr "Код авторизации:"
|
||||
|
||||
msgid "Submit Code"
|
||||
msgstr "Отправить код"
|
||||
|
||||
msgid "Save Settings"
|
||||
msgstr "Сохранить настройки"
|
||||
|
||||
@@ -399,22 +384,6 @@ msgstr "Открытие страницы входа в Legendary в брауз
|
||||
msgid "Failed to open Legendary login page"
|
||||
msgstr "Не удалось открыть страницу входа в Legendary"
|
||||
|
||||
msgid "Please enter an authorization code"
|
||||
msgstr "Пожалуйста, введите код авторизации"
|
||||
|
||||
msgid "Successfully authenticated with Legendary"
|
||||
msgstr "Успешная аутентификация с Legendary"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Legendary authentication failed: {0}"
|
||||
msgstr "Сбой аутентификации в Legendary: {0}"
|
||||
|
||||
msgid "Legendary executable not found"
|
||||
msgstr "Не найден исполняемый файл Legendary"
|
||||
|
||||
msgid "Unexpected error during authentication"
|
||||
msgstr "Неожиданная ошибка при аутентификации"
|
||||
|
||||
msgid "Confirm Reset"
|
||||
msgstr "Подтвердите удаление"
|
||||
|
||||
@@ -514,6 +483,33 @@ msgstr "Невозможно запустить игру пока запущен
|
||||
msgid "Launching"
|
||||
msgstr "Идёт запуск"
|
||||
|
||||
msgid "System Overlay"
|
||||
msgstr "Системный оверлей"
|
||||
|
||||
msgid "Reboot"
|
||||
msgstr "Перезагрузить"
|
||||
|
||||
msgid "Shutdown"
|
||||
msgstr "Выключить"
|
||||
|
||||
msgid "Suspend"
|
||||
msgstr "Перейти в ждущий режим"
|
||||
|
||||
msgid "Exit Application"
|
||||
msgstr "Выйти из приложения"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Отмена"
|
||||
|
||||
msgid "Failed to reboot the system"
|
||||
msgstr "Не удалось перезагрузить систему"
|
||||
|
||||
msgid "Failed to shutdown the system"
|
||||
msgstr "Не удалось завершить работу системы"
|
||||
|
||||
msgid "Failed to suspend the system"
|
||||
msgstr "Не удалось перейти в ждущий режим"
|
||||
|
||||
msgid "just now"
|
||||
msgstr "только что"
|
||||
|
||||
|
@@ -13,6 +13,7 @@ from portprotonqt.game_card import GameCard
|
||||
from portprotonqt.custom_widgets import FlowLayout, ClickableLabel, AutoSizeButton, NavLabel
|
||||
from portprotonqt.input_manager import InputManager
|
||||
from portprotonqt.context_menu_manager import ContextMenuManager
|
||||
from portprotonqt.system_overlay import SystemOverlay
|
||||
|
||||
from portprotonqt.image_utils import load_pixmap_async, round_corners, ImageCarousel
|
||||
from portprotonqt.steam_api import get_steam_game_info_async, get_full_steam_game_info_async, get_steam_installed_games
|
||||
@@ -259,25 +260,19 @@ class MainWindow(QMainWindow):
|
||||
self.update_status_message.emit
|
||||
)
|
||||
elif display_filter == "favorites":
|
||||
def on_all_games(portproton_games, steam_games, epic_games):
|
||||
games = [game for game in portproton_games + steam_games + epic_games if game[0] in favorites]
|
||||
def on_all_games(portproton_games, steam_games):
|
||||
games = [game for game in portproton_games + steam_games if game[0] in favorites]
|
||||
self.games_loaded.emit(games)
|
||||
self._load_portproton_games_async(
|
||||
lambda pg: self._load_steam_games_async(
|
||||
lambda sg: load_egs_games_async(
|
||||
self.legendary_path,
|
||||
lambda eg: on_all_games(pg, sg, eg),
|
||||
self.downloader,
|
||||
self.update_progress.emit,
|
||||
self.update_status_message.emit
|
||||
)
|
||||
lambda sg: on_all_games(pg, sg)
|
||||
)
|
||||
)
|
||||
else:
|
||||
def on_all_games(portproton_games, steam_games, epic_games):
|
||||
def on_all_games(portproton_games, steam_games):
|
||||
seen = set()
|
||||
games = []
|
||||
for game in portproton_games + steam_games + epic_games:
|
||||
for game in portproton_games + steam_games:
|
||||
name = game[0]
|
||||
if name not in seen:
|
||||
seen.add(name)
|
||||
@@ -285,13 +280,7 @@ class MainWindow(QMainWindow):
|
||||
self.games_loaded.emit(games)
|
||||
self._load_portproton_games_async(
|
||||
lambda pg: self._load_steam_games_async(
|
||||
lambda sg: load_egs_games_async(
|
||||
self.legendary_path,
|
||||
lambda eg: on_all_games(pg, sg, eg),
|
||||
self.downloader,
|
||||
self.update_progress.emit,
|
||||
self.update_status_message.emit
|
||||
)
|
||||
lambda sg: on_all_games(pg, sg)
|
||||
)
|
||||
)
|
||||
return []
|
||||
@@ -500,6 +489,11 @@ class MainWindow(QMainWindow):
|
||||
btn.setChecked(i == index)
|
||||
self.stackedWidget.setCurrentIndex(index)
|
||||
|
||||
def openSystemOverlay(self):
|
||||
"""Opens the system overlay dialog."""
|
||||
overlay = SystemOverlay(self, self.theme)
|
||||
overlay.exec()
|
||||
|
||||
def createSearchWidget(self) -> tuple[QWidget, QLineEdit]:
|
||||
self.container = QWidget()
|
||||
self.container.setStyleSheet(self.theme.CONTAINER_STYLE)
|
||||
@@ -909,7 +903,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# 3. Games display_filter
|
||||
self.filter_keys = ["all", "steam", "portproton", "favorites", "epic"]
|
||||
self.filter_labels = [_("all"), "steam", "portproton", _("favorites"), "epic games store"]
|
||||
self.filter_labels = [_("all"), "steam", "portproton", _("favorites")]
|
||||
self.gamesDisplayCombo = QComboBox()
|
||||
self.gamesDisplayCombo.addItems(self.filter_labels)
|
||||
self.gamesDisplayCombo.setStyleSheet(self.theme.SETTINGS_COMBO_STYLE)
|
||||
@@ -978,37 +972,6 @@ class MainWindow(QMainWindow):
|
||||
self.autoFullscreenGamepadCheckBox.setChecked(current_auto_fullscreen)
|
||||
formLayout.addRow(self.autoFullscreenGamepadTitle, self.autoFullscreenGamepadCheckBox)
|
||||
|
||||
# 7. Legendary Authentication
|
||||
self.legendaryAuthButton = AutoSizeButton(
|
||||
_("Open Legendary Login"),
|
||||
icon=self.theme_manager.get_icon("login")
|
||||
)
|
||||
self.legendaryAuthButton.setStyleSheet(self.theme.ACTION_BUTTON_STYLE)
|
||||
self.legendaryAuthButton.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
self.legendaryAuthButton.clicked.connect(self.openLegendaryLogin)
|
||||
self.legendaryAuthTitle = QLabel(_("Legendary Authentication:"))
|
||||
self.legendaryAuthTitle.setStyleSheet(self.theme.PARAMS_TITLE_STYLE)
|
||||
self.legendaryAuthTitle.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||
formLayout.addRow(self.legendaryAuthTitle, self.legendaryAuthButton)
|
||||
|
||||
self.legendaryCodeEdit = QLineEdit()
|
||||
self.legendaryCodeEdit.setPlaceholderText(_("Enter Legendary Authorization Code"))
|
||||
self.legendaryCodeEdit.setStyleSheet(self.theme.PROXY_INPUT_STYLE)
|
||||
self.legendaryCodeEdit.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
self.legendaryCodeTitle = QLabel(_("Authorization Code:"))
|
||||
self.legendaryCodeTitle.setStyleSheet(self.theme.PARAMS_TITLE_STYLE)
|
||||
self.legendaryCodeTitle.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||
formLayout.addRow(self.legendaryCodeTitle, self.legendaryCodeEdit)
|
||||
|
||||
self.submitCodeButton = AutoSizeButton(
|
||||
_("Submit Code"),
|
||||
icon=self.theme_manager.get_icon("save")
|
||||
)
|
||||
self.submitCodeButton.setStyleSheet(self.theme.ACTION_BUTTON_STYLE)
|
||||
self.submitCodeButton.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
self.submitCodeButton.clicked.connect(self.submitLegendaryCode)
|
||||
formLayout.addRow(QLabel(""), self.submitCodeButton)
|
||||
|
||||
layout.addLayout(formLayout)
|
||||
|
||||
# Кнопки
|
||||
@@ -1059,37 +1022,6 @@ class MainWindow(QMainWindow):
|
||||
logger.error(f"Failed to open Legendary login page: {e}")
|
||||
self.statusBar().showMessage(_("Failed to open Legendary login page"), 3000)
|
||||
|
||||
def submitLegendaryCode(self):
|
||||
"""Submits the Legendary authorization code using the legendary CLI."""
|
||||
auth_code = self.legendaryCodeEdit.text().strip()
|
||||
if not auth_code:
|
||||
QMessageBox.warning(self, _("Error"), _("Please enter an authorization code"))
|
||||
return
|
||||
|
||||
try:
|
||||
# Execute legendary auth command
|
||||
result = subprocess.run(
|
||||
[self.legendary_path, "auth", "--code", auth_code],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
logger.info("Legendary authentication successful: %s", result.stdout)
|
||||
self.statusBar().showMessage(_("Successfully authenticated with Legendary"), 3000)
|
||||
self.legendaryCodeEdit.clear()
|
||||
# Reload Epic Games Store games after successful authentication
|
||||
self.games = self.loadGames()
|
||||
self.updateGameGrid()
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error("Legendary authentication failed: %s", e.stderr)
|
||||
self.statusBar().showMessage(_("Legendary authentication failed: {0}").format(e.stderr), 5000)
|
||||
except FileNotFoundError:
|
||||
logger.error("Legendary executable not found at %s", self.legendary_path)
|
||||
self.statusBar().showMessage(_("Legendary executable not found"), 5000)
|
||||
except Exception as e:
|
||||
logger.error("Unexpected error during Legendary authentication: %s", str(e))
|
||||
self.statusBar().showMessage(_("Unexpected error during authentication"), 5000)
|
||||
|
||||
def resetSettings(self):
|
||||
"""Сбрасывает настройки и перезапускает приложение."""
|
||||
reply = QMessageBox.question(
|
||||
|
87
portprotonqt/system_overlay.py
Normal file
87
portprotonqt/system_overlay.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import subprocess
|
||||
from PySide6.QtWidgets import QDialog, QVBoxLayout, QPushButton, QMessageBox
|
||||
from PySide6.QtWidgets import QApplication
|
||||
from PySide6.QtCore import Qt
|
||||
from portprotonqt.logger import get_logger
|
||||
from portprotonqt.localization import _
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
class SystemOverlay(QDialog):
|
||||
"""Overlay dialog for system actions like reboot, sleep, shutdown, suspend, and exit."""
|
||||
def __init__(self, parent, theme):
|
||||
super().__init__(parent)
|
||||
self.theme = theme
|
||||
self.setWindowTitle(_("System Overlay"))
|
||||
self.setModal(True)
|
||||
self.setFixedSize(400, 300)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(20, 20, 20, 20)
|
||||
layout.setSpacing(10)
|
||||
|
||||
# Reboot button
|
||||
reboot_button = QPushButton(_("Reboot"))
|
||||
#reboot_button.setStyleSheet(self.theme.ACTION_BUTTON_STYLE)
|
||||
reboot_button.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
reboot_button.clicked.connect(self.reboot)
|
||||
layout.addWidget(reboot_button)
|
||||
|
||||
# Shutdown button
|
||||
shutdown_button = QPushButton(_("Shutdown"))
|
||||
#shutdown_button.setStyleSheet(self.theme.ACTION_BUTTON_STYLE)
|
||||
shutdown_button.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
shutdown_button.clicked.connect(self.shutdown)
|
||||
layout.addWidget(shutdown_button)
|
||||
|
||||
# Suspend button
|
||||
suspend_button = QPushButton(_("Suspend"))
|
||||
#suspend_button.setStyleSheet(self.theme.ACTION_BUTTON_STYLE)
|
||||
suspend_button.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
suspend_button.clicked.connect(self.suspend)
|
||||
layout.addWidget(suspend_button)
|
||||
|
||||
# Exit application button
|
||||
exit_button = QPushButton(_("Exit Application"))
|
||||
#exit_button.setStyleSheet(self.theme.ACTION_BUTTON_STYLE)
|
||||
exit_button.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
exit_button.clicked.connect(self.exit_application)
|
||||
layout.addWidget(exit_button)
|
||||
|
||||
# Cancel button
|
||||
cancel_button = QPushButton(_("Cancel"))
|
||||
#cancel_button.setStyleSheet(self.theme.ACTION_BUTTON_STYLE)
|
||||
cancel_button.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
cancel_button.clicked.connect(self.reject)
|
||||
layout.addWidget(cancel_button)
|
||||
|
||||
# Set focus to the first button
|
||||
reboot_button.setFocus()
|
||||
|
||||
def reboot(self):
|
||||
try:
|
||||
subprocess.run(["systemctl", "reboot"], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(f"Failed to reboot: {e}")
|
||||
QMessageBox.warning(self, _("Error"), _("Failed to reboot the system"))
|
||||
self.accept()
|
||||
|
||||
def shutdown(self):
|
||||
try:
|
||||
subprocess.run(["systemctl", "poweroff"], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(f"Failed to shutdown: {e}")
|
||||
QMessageBox.warning(self, _("Error"), _("Failed to shutdown the system"))
|
||||
self.accept()
|
||||
|
||||
def suspend(self):
|
||||
try:
|
||||
subprocess.run(["systemctl", "suspend"], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(f"Failed to suspend: {e}")
|
||||
QMessageBox.warning(self, _("Error"), _("Failed to suspend the system"))
|
||||
self.accept()
|
||||
|
||||
def exit_application(self):
|
||||
QApplication.quit()
|
||||
self.accept()
|
Reference in New Issue
Block a user