chore: clean all vulture 80% confidence dead code
All checks were successful
Code check / Check code (push) Successful in 1m45s
All checks were successful
Code check / Check code (push) Successful in 1m45s
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
@@ -77,22 +77,6 @@ def invalidate_config_cache(config_file: str = CONFIG_FILE):
|
|||||||
del _config_last_modified[config_file]
|
del _config_last_modified[config_file]
|
||||||
logger.debug(f"Config cache invalidated for {config_file}")
|
logger.debug(f"Config cache invalidated for {config_file}")
|
||||||
|
|
||||||
def read_config():
|
|
||||||
"""Reads the configuration file and returns a dictionary of parameters.
|
|
||||||
Example line in config (no sections):
|
|
||||||
detail_level = detailed
|
|
||||||
"""
|
|
||||||
config_dict = {}
|
|
||||||
if os.path.exists(CONFIG_FILE):
|
|
||||||
with open(CONFIG_FILE, encoding="utf-8") as f:
|
|
||||||
for line in f:
|
|
||||||
line = line.strip()
|
|
||||||
if not line or line.startswith("#"):
|
|
||||||
continue
|
|
||||||
key, sep, value = line.partition("=")
|
|
||||||
if sep:
|
|
||||||
config_dict[key.strip()] = value.strip()
|
|
||||||
return config_dict
|
|
||||||
|
|
||||||
def read_theme_from_config():
|
def read_theme_from_config():
|
||||||
"""Reads the theme from the [Appearance] section of the configuration file.
|
"""Reads the theme from the [Appearance] section of the configuration file.
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ContextMenuSignals(QObject):
|
|||||||
class ContextMenuManager:
|
class ContextMenuManager:
|
||||||
"""Manages context menu actions for game management in PortProtonQt."""
|
"""Manages context menu actions for game management in PortProtonQt."""
|
||||||
|
|
||||||
def __init__(self, parent, portproton_location, theme, load_games_callback, game_library_manager):
|
def __init__(self, parent, portproton_location, theme, game_library_manager):
|
||||||
"""
|
"""
|
||||||
Initialize the ContextMenuManager.
|
Initialize the ContextMenuManager.
|
||||||
|
|
||||||
@@ -44,7 +44,6 @@ class ContextMenuManager:
|
|||||||
self.portproton_location = portproton_location
|
self.portproton_location = portproton_location
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.theme_manager = ThemeManager()
|
self.theme_manager = ThemeManager()
|
||||||
self.load_games = load_games_callback
|
|
||||||
self.game_library_manager = game_library_manager
|
self.game_library_manager = game_library_manager
|
||||||
self.update_game_grid = game_library_manager.update_game_grid
|
self.update_game_grid = game_library_manager.update_game_grid
|
||||||
self.legendary_path = os.path.join(
|
self.legendary_path = os.path.join(
|
||||||
|
|||||||
@@ -853,7 +853,6 @@ class AddGameDialog(QDialog):
|
|||||||
from portprotonqt.context_menu_manager import CustomLineEdit # Локальный импорт
|
from portprotonqt.context_menu_manager import CustomLineEdit # Локальный импорт
|
||||||
self.theme = theme if theme else theme_manager.apply_theme(read_theme_from_config())
|
self.theme = theme if theme else theme_manager.apply_theme(read_theme_from_config())
|
||||||
self.edit_mode = edit_mode
|
self.edit_mode = edit_mode
|
||||||
self.original_name = game_name
|
|
||||||
self.last_exe_path = exe_path # Store last selected exe path
|
self.last_exe_path = exe_path # Store last selected exe path
|
||||||
self.last_cover_path = cover_path # Store last selected cover path
|
self.last_cover_path = cover_path # Store last selected cover path
|
||||||
self.downloader = Downloader(max_workers=4) # Initialize Downloader
|
self.downloader = Downloader(max_workers=4) # Initialize Downloader
|
||||||
|
|||||||
@@ -126,8 +126,6 @@ class Downloader(QObject):
|
|||||||
self._has_internet = True
|
self._has_internet = True
|
||||||
return self._has_internet
|
return self._has_internet
|
||||||
|
|
||||||
def reset_internet_check(self):
|
|
||||||
self._has_internet = None
|
|
||||||
|
|
||||||
def _get_url_lock(self, url):
|
def _get_url_lock(self, url):
|
||||||
with self._global_lock:
|
with self._global_lock:
|
||||||
@@ -247,9 +245,6 @@ class Downloader(QObject):
|
|||||||
with self._global_lock:
|
with self._global_lock:
|
||||||
self._cache.clear()
|
self._cache.clear()
|
||||||
|
|
||||||
def is_cached(self, url):
|
|
||||||
with self._global_lock:
|
|
||||||
return url in self._cache
|
|
||||||
|
|
||||||
def get_latest_legendary_release(self):
|
def get_latest_legendary_release(self):
|
||||||
"""Get the latest legendary release info from GitHub API."""
|
"""Get the latest legendary release info from GitHub API."""
|
||||||
|
|||||||
@@ -555,44 +555,6 @@ def get_egs_game_description_async(
|
|||||||
cleaned = re.sub(r'[^a-z0-9 ]', '', title.lower()).strip()
|
cleaned = re.sub(r'[^a-z0-9 ]', '', title.lower()).strip()
|
||||||
return re.sub(r'\s+', '-', cleaned)
|
return re.sub(r'\s+', '-', cleaned)
|
||||||
|
|
||||||
def get_product_slug(namespace: str) -> str:
|
|
||||||
"""Fetches the product slug using the namespace via GraphQL."""
|
|
||||||
search_query = {
|
|
||||||
"query": """
|
|
||||||
query {
|
|
||||||
Catalog {
|
|
||||||
catalogNs(namespace: $namespace) {
|
|
||||||
mappings(pageType: "productHome") {
|
|
||||||
pageSlug
|
|
||||||
pageType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""",
|
|
||||||
"variables": {"namespace": namespace}
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
response = requests.post(
|
|
||||||
"https://launcher.store.epicgames.com/graphql",
|
|
||||||
json=search_query,
|
|
||||||
headers=headers,
|
|
||||||
timeout=10
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
data = orjson.loads(response.content)
|
|
||||||
mappings = data.get("data", {}).get("Catalog", {}).get("catalogNs", {}).get("mappings", [])
|
|
||||||
for mapping in mappings:
|
|
||||||
if mapping.get("pageType") == "productHome":
|
|
||||||
return mapping.get("pageSlug", "")
|
|
||||||
logger.warning("No productHome slug found for namespace %s", namespace)
|
|
||||||
return ""
|
|
||||||
except requests.RequestException as e:
|
|
||||||
logger.warning("Failed to fetch product slug for namespace %s: %s", namespace, str(e))
|
|
||||||
return ""
|
|
||||||
except orjson.JSONDecodeError:
|
|
||||||
logger.warning("Invalid JSON response for namespace %s", namespace)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def fetch_legacy_description(url: str) -> str:
|
def fetch_legacy_description(url: str) -> str:
|
||||||
"""Fetches description from the legacy API, handling DNS failures."""
|
"""Fetches description from the legacy API, handling DNS failures."""
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ class MainWindowProtocol(Protocol):
|
|||||||
|
|
||||||
# Required attributes
|
# Required attributes
|
||||||
searchEdit: CustomLineEdit
|
searchEdit: CustomLineEdit
|
||||||
_last_card_width: int
|
|
||||||
card_width: int
|
card_width: int
|
||||||
current_hovered_card: GameCard | None
|
current_hovered_card: GameCard | None
|
||||||
current_focused_card: GameCard | None
|
current_focused_card: GameCard | None
|
||||||
@@ -134,7 +133,6 @@ class GameLibraryManager:
|
|||||||
self.sizeSlider.setToolTip(f"{self.card_width} px")
|
self.sizeSlider.setToolTip(f"{self.card_width} px")
|
||||||
save_card_size(self.card_width)
|
save_card_size(self.card_width)
|
||||||
self.main_window.card_width = self.card_width
|
self.main_window.card_width = self.card_width
|
||||||
self.main_window._last_card_width = self.card_width
|
|
||||||
for card in self.game_card_cache.values():
|
for card in self.game_card_cache.values():
|
||||||
card.update_card_size(self.card_width)
|
card.update_card_size(self.card_width)
|
||||||
self.update_game_grid()
|
self.update_game_grid()
|
||||||
@@ -266,7 +264,7 @@ class GameLibraryManager:
|
|||||||
if self.is_filtering:
|
if self.is_filtering:
|
||||||
# Filter mode: use the pre-computed filtered_games from optimized search
|
# Filter mode: use the pre-computed filtered_games from optimized search
|
||||||
# This means we already have the exact games to show
|
# This means we already have the exact games to show
|
||||||
self._update_search_results()
|
self._update_search_results(search_text)
|
||||||
else:
|
else:
|
||||||
# Full update: sorting, removal/addition, reorganization
|
# Full update: sorting, removal/addition, reorganization
|
||||||
games_list = self.filtered_games if self.filtered_games else self.games
|
games_list = self.filtered_games if self.filtered_games else self.games
|
||||||
@@ -385,13 +383,11 @@ class GameLibraryManager:
|
|||||||
if self.gamesListLayout is not None:
|
if self.gamesListLayout is not None:
|
||||||
self.gamesListLayout.update()
|
self.gamesListLayout.update()
|
||||||
self.gamesListWidget.updateGeometry()
|
self.gamesListWidget.updateGeometry()
|
||||||
self.main_window._last_card_width = self.card_width
|
|
||||||
|
|
||||||
self.force_update_cards_library()
|
self.force_update_cards_library()
|
||||||
|
|
||||||
self.is_filtering = False # Reset flag in any case
|
self.is_filtering = False # Reset flag in any case
|
||||||
|
|
||||||
def _update_search_results(self):
|
def _update_search_results(self, search_text: str = ""):
|
||||||
"""Update the grid with pre-computed search results."""
|
"""Update the grid with pre-computed search results."""
|
||||||
if self.gamesListLayout is None or self.gamesListWidget is None:
|
if self.gamesListLayout is None or self.gamesListWidget is None:
|
||||||
return
|
return
|
||||||
@@ -449,35 +445,12 @@ class GameLibraryManager:
|
|||||||
if self.gamesListLayout is not None:
|
if self.gamesListLayout is not None:
|
||||||
self.gamesListLayout.update()
|
self.gamesListLayout.update()
|
||||||
self.gamesListWidget.updateGeometry()
|
self.gamesListWidget.updateGeometry()
|
||||||
self.main_window._last_card_width = self.card_width
|
|
||||||
|
|
||||||
self.force_update_cards_library()
|
self.force_update_cards_library()
|
||||||
|
|
||||||
def _apply_filter_visibility(self, search_text: str):
|
|
||||||
"""Applies visibility to cards based on search, without changing the layout."""
|
|
||||||
# This method is used for simple substring matching
|
|
||||||
# For the new optimized search, we'll use a different approach in update_game_grid
|
|
||||||
# when is_filter=True
|
|
||||||
visible_count = 0
|
|
||||||
for game_key, card in self.game_card_cache.items():
|
|
||||||
game_name = card.name # Assume GameCard has 'name' attribute
|
|
||||||
should_be_visible = not search_text or search_text in game_name.lower()
|
|
||||||
if card.isVisible() != should_be_visible:
|
|
||||||
card.setVisible(should_be_visible)
|
|
||||||
if should_be_visible:
|
|
||||||
visible_count += 1
|
|
||||||
# Load image only for newly visible cards
|
|
||||||
if game_key in self.pending_images:
|
|
||||||
cover_path, width, height, callback = self.pending_images.pop(game_key)
|
|
||||||
load_pixmap_async(cover_path, width, height, callback)
|
|
||||||
|
|
||||||
# Force full relayout after visibility changes
|
|
||||||
if self.gamesListLayout is not None:
|
|
||||||
self.gamesListLayout.invalidate() # Принудительно инвалидируем для пересчёта
|
|
||||||
self.gamesListLayout.update()
|
self.gamesListLayout.update()
|
||||||
if self.gamesListWidget is not None:
|
if self.gamesListWidget is not None:
|
||||||
self.gamesListWidget.updateGeometry()
|
self.gamesListWidget.updateGeometry()
|
||||||
self.main_window._last_card_width = self.card_width
|
|
||||||
|
|
||||||
# If search is empty, load images for visible ones
|
# If search is empty, load images for visible ones
|
||||||
if not search_text:
|
if not search_text:
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ class MainWindow(QMainWindow):
|
|||||||
def __init__(self, app_name: str, version: str):
|
def __init__(self, app_name: str, version: str):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.theme_manager = ThemeManager()
|
self.theme_manager = ThemeManager()
|
||||||
self.is_exiting = False
|
|
||||||
selected_theme = read_theme_from_config()
|
selected_theme = read_theme_from_config()
|
||||||
self.current_theme_name = selected_theme
|
self.current_theme_name = selected_theme
|
||||||
# Apply theme but defer heavy font loading
|
# Apply theme but defer heavy font loading
|
||||||
@@ -65,7 +64,6 @@ class MainWindow(QMainWindow):
|
|||||||
self.tray_manager = TrayManager(self, app_name, self.current_theme_name)
|
self.tray_manager = TrayManager(self, app_name, self.current_theme_name)
|
||||||
self.card_width = read_card_size()
|
self.card_width = read_card_size()
|
||||||
self.auto_card_width = read_auto_card_size()
|
self.auto_card_width = read_auto_card_size()
|
||||||
self._last_card_width = self.card_width
|
|
||||||
self.setWindowTitle(f"{app_name} {version}")
|
self.setWindowTitle(f"{app_name} {version}")
|
||||||
self.setMinimumSize(800, 600)
|
self.setMinimumSize(800, 600)
|
||||||
|
|
||||||
@@ -85,7 +83,6 @@ class MainWindow(QMainWindow):
|
|||||||
self,
|
self,
|
||||||
self.portproton_location,
|
self.portproton_location,
|
||||||
self.theme,
|
self.theme,
|
||||||
self.loadGames,
|
|
||||||
self.game_library_manager
|
self.game_library_manager
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -144,7 +141,6 @@ class MainWindow(QMainWindow):
|
|||||||
QApplication.processEvents() # Process to show progress bar immediately
|
QApplication.processEvents() # Process to show progress bar immediately
|
||||||
|
|
||||||
self.installing = False
|
self.installing = False
|
||||||
self.current_install_script = None
|
|
||||||
self.install_process = None
|
self.install_process = None
|
||||||
self.install_monitor_timer = None
|
self.install_monitor_timer = None
|
||||||
|
|
||||||
@@ -647,7 +643,6 @@ class MainWindow(QMainWindow):
|
|||||||
QMessageBox.warning(self, _("Warning"), _("Installation already in progress."))
|
QMessageBox.warning(self, _("Warning"), _("Installation already in progress."))
|
||||||
return
|
return
|
||||||
self.installing = True
|
self.installing = True
|
||||||
self.current_install_script = script_name
|
|
||||||
self.seen_progress = False
|
self.seen_progress = False
|
||||||
self.current_percent = 0.0
|
self.current_percent = 0.0
|
||||||
start_sh = self.start_sh
|
start_sh = self.start_sh
|
||||||
@@ -735,7 +730,6 @@ class MainWindow(QMainWindow):
|
|||||||
QMessageBox.warning(self, _("Error"), f"Installation failed (code: {exit_code}).")
|
QMessageBox.warning(self, _("Error"), f"Installation failed (code: {exit_code}).")
|
||||||
|
|
||||||
self.progress_bar.setVisible(False)
|
self.progress_bar.setVisible(False)
|
||||||
self.current_install_script = None
|
|
||||||
if self.install_process:
|
if self.install_process:
|
||||||
self.install_process.deleteLater()
|
self.install_process.deleteLater()
|
||||||
self.install_process = None
|
self.install_process = None
|
||||||
@@ -1165,7 +1159,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.searchEdit = CustomLineEdit(self, theme=self.theme)
|
self.searchEdit = CustomLineEdit(self, theme=self.theme)
|
||||||
icon: QIcon = cast(QIcon, self.theme_manager.get_icon("search"))
|
icon: QIcon = cast(QIcon, self.theme_manager.get_icon("search"))
|
||||||
action_pos = cast(QLineEdit.ActionPosition, QLineEdit.ActionPosition.LeadingPosition)
|
action_pos = cast(QLineEdit.ActionPosition, QLineEdit.ActionPosition.LeadingPosition)
|
||||||
self.search_action = self.searchEdit.addAction(icon, action_pos)
|
self.searchEdit.addAction(icon, action_pos)
|
||||||
self.searchEdit.setMaximumWidth(200)
|
self.searchEdit.setMaximumWidth(200)
|
||||||
self.searchEdit.setPlaceholderText(_("Find Games ..."))
|
self.searchEdit.setPlaceholderText(_("Find Games ..."))
|
||||||
self.searchEdit.setClearButtonEnabled(True)
|
self.searchEdit.setClearButtonEnabled(True)
|
||||||
@@ -1452,7 +1446,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.autoInstallSearchLineEdit = CustomLineEdit(self, theme=self.theme)
|
self.autoInstallSearchLineEdit = CustomLineEdit(self, theme=self.theme)
|
||||||
icon: QIcon = cast(QIcon, self.theme_manager.get_icon("search"))
|
icon: QIcon = cast(QIcon, self.theme_manager.get_icon("search"))
|
||||||
action_pos = QLineEdit.ActionPosition.LeadingPosition
|
action_pos = QLineEdit.ActionPosition.LeadingPosition
|
||||||
self.search_action = self.autoInstallSearchLineEdit.addAction(icon, action_pos)
|
self.autoInstallSearchLineEdit.addAction(icon, action_pos)
|
||||||
self.autoInstallSearchLineEdit.setMaximumWidth(200)
|
self.autoInstallSearchLineEdit.setMaximumWidth(200)
|
||||||
self.autoInstallSearchLineEdit.setPlaceholderText(_("Find Games ..."))
|
self.autoInstallSearchLineEdit.setPlaceholderText(_("Find Games ..."))
|
||||||
self.autoInstallSearchLineEdit.setClearButtonEnabled(True)
|
self.autoInstallSearchLineEdit.setClearButtonEnabled(True)
|
||||||
@@ -1627,12 +1621,10 @@ class MainWindow(QMainWindow):
|
|||||||
def filterAutoInstallGames(self):
|
def filterAutoInstallGames(self):
|
||||||
"""Filter auto install game cards based on search text."""
|
"""Filter auto install game cards based on search text."""
|
||||||
search_text = self.autoInstallSearchLineEdit.text().lower().strip()
|
search_text = self.autoInstallSearchLineEdit.text().lower().strip()
|
||||||
visible_count = 0
|
|
||||||
|
|
||||||
for card in self.allAutoInstallCards:
|
for card in self.allAutoInstallCards:
|
||||||
if search_text in card.name.lower():
|
if search_text in card.name.lower():
|
||||||
card.setVisible(True)
|
card.setVisible(True)
|
||||||
visible_count += 1
|
|
||||||
else:
|
else:
|
||||||
card.setVisible(False)
|
card.setVisible(False)
|
||||||
|
|
||||||
@@ -1781,7 +1773,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.update_status_message.emit(_("Launching tool..."), 0)
|
self.update_status_message.emit(_("Launching tool..."), 0)
|
||||||
|
|
||||||
proc = QProcess(self)
|
proc = QProcess(self)
|
||||||
proc.finished.connect(lambda exitCode, exitStatus: self._on_wine_tool_finished(exitCode, cli_arg))
|
proc.finished.connect(lambda exitCode: self._on_wine_tool_finished(exitCode, cli_arg))
|
||||||
proc.errorOccurred.connect(lambda error: self._on_wine_tool_error(error, cli_arg))
|
proc.errorOccurred.connect(lambda error: self._on_wine_tool_error(error, cli_arg))
|
||||||
proc.start(cmd[0], cmd[1:])
|
proc.start(cmd[0], cmd[1:])
|
||||||
|
|
||||||
@@ -1878,7 +1870,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.update_status_message.emit(_("Clearing prefix..."), 0)
|
self.update_status_message.emit(_("Clearing prefix..."), 0)
|
||||||
|
|
||||||
self.clear_process = QProcess(self)
|
self.clear_process = QProcess(self)
|
||||||
self.clear_process.finished.connect(lambda exitCode, exitStatus: self._on_clear_prefix_finished(exitCode))
|
self.clear_process.finished.connect(lambda exitCode: self._on_clear_prefix_finished(exitCode))
|
||||||
self.clear_process.errorOccurred.connect(lambda error: self._on_clear_prefix_error(error))
|
self.clear_process.errorOccurred.connect(lambda error: self._on_clear_prefix_error(error))
|
||||||
cmd = start_sh + ["cli", "--clear_pfx", selected_wine, selected_prefix]
|
cmd = start_sh + ["cli", "--clear_pfx", selected_wine, selected_prefix]
|
||||||
self.clear_process.start(cmd[0], cmd[1:])
|
self.clear_process.start(cmd[0], cmd[1:])
|
||||||
@@ -1916,7 +1908,7 @@ class MainWindow(QMainWindow):
|
|||||||
return
|
return
|
||||||
start_sh = self.start_sh
|
start_sh = self.start_sh
|
||||||
self.backup_process = QProcess(self)
|
self.backup_process = QProcess(self)
|
||||||
self.backup_process.finished.connect(lambda exitCode, exitStatus: self._on_backup_finished(exitCode))
|
self.backup_process.finished.connect(lambda exitCode: self._on_backup_finished(exitCode))
|
||||||
cmd = start_sh + ["--backup-prefix", prefix_name, backup_dir]
|
cmd = start_sh + ["--backup-prefix", prefix_name, backup_dir]
|
||||||
self.backup_process.start(cmd[0], cmd[1:])
|
self.backup_process.start(cmd[0], cmd[1:])
|
||||||
if not self.backup_process.waitForStarted():
|
if not self.backup_process.waitForStarted():
|
||||||
@@ -1934,7 +1926,7 @@ class MainWindow(QMainWindow):
|
|||||||
return
|
return
|
||||||
start_sh = self.start_sh
|
start_sh = self.start_sh
|
||||||
self.restore_process = QProcess(self)
|
self.restore_process = QProcess(self)
|
||||||
self.restore_process.finished.connect(lambda exitCode, exitStatus: self._on_restore_finished(exitCode))
|
self.restore_process.finished.connect(lambda exitCode: self._on_restore_finished(exitCode))
|
||||||
cmd = start_sh + ["--restore-prefix", file_path]
|
cmd = start_sh + ["--restore-prefix", file_path]
|
||||||
self.restore_process.start(cmd[0], cmd[1:])
|
self.restore_process.start(cmd[0], cmd[1:])
|
||||||
if not self.restore_process.waitForStarted():
|
if not self.restore_process.waitForStarted():
|
||||||
@@ -2684,7 +2676,6 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
if target_running:
|
if target_running:
|
||||||
# Игра стартовала – устанавливаем флаг, обновляем кнопку на "Stop"
|
# Игра стартовала – устанавливаем флаг, обновляем кнопку на "Stop"
|
||||||
self._gameLaunched = True
|
|
||||||
if self.current_running_button is not None:
|
if self.current_running_button is not None:
|
||||||
try:
|
try:
|
||||||
self.current_running_button.setText(_("Stop"))
|
self.current_running_button.setText(_("Stop"))
|
||||||
@@ -2693,7 +2684,6 @@ class MainWindow(QMainWindow):
|
|||||||
#self._inhibit_screensaver()
|
#self._inhibit_screensaver()
|
||||||
elif not child_running:
|
elif not child_running:
|
||||||
# Игра завершилась – сбрасываем флаг, сбрасываем кнопку и останавливаем таймер
|
# Игра завершилась – сбрасываем флаг, сбрасываем кнопку и останавливаем таймер
|
||||||
self._gameLaunched = False
|
|
||||||
self.resetPlayButton()
|
self.resetPlayButton()
|
||||||
#self._uninhibit_screensaver()
|
#self._uninhibit_screensaver()
|
||||||
if hasattr(self, 'checkProcessTimer') and self.checkProcessTimer is not None:
|
if hasattr(self, 'checkProcessTimer') and self.checkProcessTimer is not None:
|
||||||
@@ -2786,7 +2776,6 @@ class MainWindow(QMainWindow):
|
|||||||
self.checkProcessTimer = None
|
self.checkProcessTimer = None
|
||||||
self.current_running_button = None
|
self.current_running_button = None
|
||||||
self.target_exe = None
|
self.target_exe = None
|
||||||
self._gameLaunched = False
|
|
||||||
else:
|
else:
|
||||||
# Запускаем игру через PortProton
|
# Запускаем игру через PortProton
|
||||||
env_vars = os.environ.copy()
|
env_vars = os.environ.copy()
|
||||||
@@ -2883,7 +2872,6 @@ class MainWindow(QMainWindow):
|
|||||||
self.checkProcessTimer = None
|
self.checkProcessTimer = None
|
||||||
self.current_running_button = None
|
self.current_running_button = None
|
||||||
self.target_exe = None
|
self.target_exe = None
|
||||||
self._gameLaunched = False
|
|
||||||
#self._uninhibit_screensaver()
|
#self._uninhibit_screensaver()
|
||||||
else:
|
else:
|
||||||
# Сохраняем ссылку на кнопку для сброса после завершения игры
|
# Сохраняем ссылку на кнопку для сброса после завершения игры
|
||||||
@@ -2929,7 +2917,6 @@ class MainWindow(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Полное закрытие приложения
|
# Полное закрытие приложения
|
||||||
self.is_exiting = True
|
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
# Скрываем и удаляем иконку трея
|
# Скрываем и удаляем иконку трея
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
"""
|
"""
|
||||||
Utility module for search optimizations including Trie, hash tables, and fuzzy matching.
|
Utility module for search optimizations including Trie, hash tables, and fuzzy matching.
|
||||||
"""
|
"""
|
||||||
import concurrent.futures
|
|
||||||
import threading
|
|
||||||
from collections.abc import Callable
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from rapidfuzz import fuzz
|
from rapidfuzz import fuzz
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from portprotonqt.logger import get_logger
|
from portprotonqt.logger import get_logger
|
||||||
from PySide6.QtCore import QThread, QRunnable, Signal, QObject, QTimer
|
from PySide6.QtCore import QThread, Signal, QObject
|
||||||
import requests
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
@@ -139,99 +135,12 @@ class SearchOptimizer:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
class RequestRunnable(QRunnable):
|
|
||||||
"""Runnable for executing HTTP requests in a thread."""
|
|
||||||
|
|
||||||
def __init__(self, method: str, url: str, on_success=None, on_error=None, **kwargs):
|
|
||||||
super().__init__()
|
|
||||||
self.method = method
|
|
||||||
self.url = url
|
|
||||||
self.kwargs = kwargs
|
|
||||||
self.result = None
|
|
||||||
self.error = None
|
|
||||||
self.on_success: Callable | None = on_success
|
|
||||||
self.on_error: Callable | None = on_error
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
try:
|
|
||||||
if self.method.lower() == 'get':
|
|
||||||
self.result = requests.get(self.url, **self.kwargs)
|
|
||||||
elif self.method.lower() == 'post':
|
|
||||||
self.result = requests.post(self.url, **self.kwargs)
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Unsupported HTTP method: {self.method}")
|
|
||||||
|
|
||||||
# Execute success callback if provided
|
|
||||||
if self.on_success is not None:
|
|
||||||
success_callback = self.on_success # Capture the callback
|
|
||||||
def success_handler():
|
|
||||||
if success_callback is not None: # Re-check to satisfy Pyright
|
|
||||||
success_callback(self.result)
|
|
||||||
QTimer.singleShot(0, success_handler)
|
|
||||||
except Exception as e:
|
|
||||||
self.error = e
|
|
||||||
# Execute error callback if provided
|
|
||||||
if self.on_error is not None:
|
|
||||||
error_callback = self.on_error # Capture the callback
|
|
||||||
captured_error = e # Capture the exception
|
|
||||||
def error_handler():
|
|
||||||
error_callback(captured_error)
|
|
||||||
QTimer.singleShot(0, error_handler)
|
|
||||||
|
|
||||||
|
|
||||||
def run_request_in_thread(method: str, url: str, on_success: Callable | None = None, on_error: Callable | None = None, **kwargs):
|
|
||||||
"""Run HTTP request in a separate thread using Qt's thread system."""
|
|
||||||
runnable = RequestRunnable(method, url, on_success=on_success, on_error=on_error, **kwargs)
|
|
||||||
|
|
||||||
# Use QThreadPool to execute the runnable
|
|
||||||
from PySide6.QtCore import QThreadPool
|
|
||||||
thread_pool = QThreadPool.globalInstance()
|
|
||||||
thread_pool.start(runnable)
|
|
||||||
|
|
||||||
return runnable # Return the runnable to allow for potential cancellation if needed
|
|
||||||
|
|
||||||
|
|
||||||
def run_function_in_thread(func, *args, on_success: Callable | None = None, on_error: Callable | None = None, **kwargs):
|
|
||||||
"""Run a function in a separate thread."""
|
|
||||||
def execute():
|
|
||||||
try:
|
|
||||||
result = func(*args, **kwargs)
|
|
||||||
if on_success:
|
|
||||||
on_success(result)
|
|
||||||
except Exception as e:
|
|
||||||
if on_error:
|
|
||||||
on_error(e)
|
|
||||||
|
|
||||||
thread = threading.Thread(target=execute)
|
|
||||||
thread.daemon = True
|
|
||||||
thread.start()
|
|
||||||
return thread
|
|
||||||
|
|
||||||
|
|
||||||
def run_in_thread(func, *args, **kwargs):
|
|
||||||
"""Run a function in a separate thread."""
|
|
||||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
||||||
future = executor.submit(func, *args, **kwargs)
|
|
||||||
return future.result()
|
|
||||||
|
|
||||||
|
|
||||||
def run_in_thread_async(func, *args, callback: Callable | None = None, **kwargs):
|
|
||||||
"""Run a function in a separate thread asynchronously."""
|
|
||||||
import threading
|
|
||||||
def target():
|
|
||||||
try:
|
|
||||||
result = func(*args, **kwargs)
|
|
||||||
if callback:
|
|
||||||
callback(result)
|
|
||||||
except Exception as e:
|
|
||||||
if callback:
|
|
||||||
callback(None) # or handle error in callback
|
|
||||||
logger.error(f"Error in threaded operation: {e}")
|
|
||||||
|
|
||||||
thread = threading.Thread(target=target)
|
|
||||||
thread.daemon = True
|
|
||||||
thread.start()
|
|
||||||
return thread
|
|
||||||
|
|
||||||
|
|
||||||
# Threaded search implementation using QThread for performance optimization
|
# Threaded search implementation using QThread for performance optimization
|
||||||
@@ -320,11 +229,6 @@ class ThreadedSearch(QThread):
|
|||||||
self.worker.search_finished.connect(self.search_finished)
|
self.worker.search_finished.connect(self.search_finished)
|
||||||
self.worker.search_error.connect(self.search_error)
|
self.worker.search_error.connect(self.search_error)
|
||||||
|
|
||||||
def set_search_params(self, search_text: str, games_data: list, search_type: str = "auto"):
|
|
||||||
"""Set parameters for the search operation."""
|
|
||||||
self.search_text = search_text
|
|
||||||
self.games_data = games_data
|
|
||||||
self.search_type = search_type
|
|
||||||
|
|
||||||
def set_games_data(self, games_data: list):
|
def set_games_data(self, games_data: list):
|
||||||
"""Set the games data to be searched."""
|
"""Set the games data to be searched."""
|
||||||
@@ -334,46 +238,3 @@ class ThreadedSearch(QThread):
|
|||||||
def run(self):
|
def run(self):
|
||||||
"""Run the search operation in the thread."""
|
"""Run the search operation in the thread."""
|
||||||
self.worker.execute_search(self.search_text, self.search_type)
|
self.worker.execute_search(self.search_text, self.search_type)
|
||||||
|
|
||||||
|
|
||||||
class SearchThreadPool:
|
|
||||||
"""
|
|
||||||
A simple thread pool for managing multiple search operations.
|
|
||||||
"""
|
|
||||||
def __init__(self, max_threads: int = 3):
|
|
||||||
self.max_threads = max_threads
|
|
||||||
self.active_threads = []
|
|
||||||
self.thread_queue = []
|
|
||||||
|
|
||||||
def submit_search(self, search_text: str, games_data: list, search_type: str = "auto",
|
|
||||||
on_start: Callable | None = None, on_finish: Callable | None = None, on_error: Callable | None = None):
|
|
||||||
"""
|
|
||||||
Submit a search operation to the pool.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
search_text: Text to search for
|
|
||||||
games_data: List of game data tuples to search in
|
|
||||||
search_type: Type of search ("exact", "prefix", "fuzzy", "auto")
|
|
||||||
on_start: Callback when search starts
|
|
||||||
on_finish: Callback when search finishes (receives results)
|
|
||||||
on_error: Callback when search errors (receives error message)
|
|
||||||
"""
|
|
||||||
search_thread = ThreadedSearch()
|
|
||||||
search_thread.set_search_params(search_text, games_data, search_type)
|
|
||||||
|
|
||||||
# Connect callbacks if provided
|
|
||||||
if on_start:
|
|
||||||
search_thread.search_started.connect(on_start)
|
|
||||||
if on_finish:
|
|
||||||
search_thread.search_finished.connect(on_finish)
|
|
||||||
if on_error:
|
|
||||||
search_thread.search_error.connect(on_error)
|
|
||||||
|
|
||||||
# Start the thread
|
|
||||||
search_thread.start()
|
|
||||||
self.active_threads.append(search_thread)
|
|
||||||
|
|
||||||
# Clean up finished threads
|
|
||||||
self.active_threads = [thread for thread in self.active_threads if thread.isRunning()]
|
|
||||||
|
|
||||||
return search_thread
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ current_theme_name = read_theme_from_config()
|
|||||||
|
|
||||||
# КОНСТАНТЫ
|
# КОНСТАНТЫ
|
||||||
favoriteLabelSize = 48, 48
|
favoriteLabelSize = 48, 48
|
||||||
pixmapsScaledSize = 60, 60
|
|
||||||
|
|
||||||
# VARS
|
# VARS
|
||||||
font_family = "Play"
|
font_family = "Play"
|
||||||
@@ -652,26 +651,6 @@ PLAY_BUTTON_STYLE = f"""
|
|||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# СТИЛЬ КНОПКИ "ОБЗОР..." В ДИАЛОГЕ "ДОБАВИТЬ ИГРУ"
|
|
||||||
DIALOG_BROWSE_BUTTON_STYLE = f"""
|
|
||||||
QPushButton {{
|
|
||||||
background: rgba(20, 20, 20, 0.40);
|
|
||||||
border: {border_a} rgba(255, 255, 255, 0.20);
|
|
||||||
border-radius: {border_radius_b};
|
|
||||||
color: {color_f};
|
|
||||||
font-size: {font_size_a};
|
|
||||||
padding: 5px 10px;
|
|
||||||
}}
|
|
||||||
QPushButton:hover {{
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
||||||
stop:0 rgba(0,122,255,0.20),
|
|
||||||
stop:1 rgba(0,122,255,0.15));
|
|
||||||
}}
|
|
||||||
QPushButton:pressed {{
|
|
||||||
background: rgba(20, 20, 20, 0.60);
|
|
||||||
border: {border_a} rgba(255, 255, 255, 0.25);
|
|
||||||
}}
|
|
||||||
"""
|
|
||||||
|
|
||||||
ADDGAME_INPUT_STYLE = f"""
|
ADDGAME_INPUT_STYLE = f"""
|
||||||
QLineEdit {{
|
QLineEdit {{
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ class TrayManager:
|
|||||||
self.tray_icon.setContextMenu(self.tray_menu)
|
self.tray_icon.setContextMenu(self.tray_menu)
|
||||||
self.tray_icon.show()
|
self.tray_icon.show()
|
||||||
|
|
||||||
self.main_window.is_exiting = False
|
|
||||||
|
|
||||||
self.click_count = 0
|
self.click_count = 0
|
||||||
self.click_timer = QTimer()
|
self.click_timer = QTimer()
|
||||||
self.click_timer.setSingleShot(True)
|
self.click_timer.setSingleShot(True)
|
||||||
@@ -231,7 +229,6 @@ class TrayManager:
|
|||||||
executable = sys.executable
|
executable = sys.executable
|
||||||
args = sys.argv
|
args = sys.argv
|
||||||
|
|
||||||
self.main_window.is_exiting = True
|
|
||||||
QApplication.quit()
|
QApplication.quit()
|
||||||
|
|
||||||
subprocess.Popen([executable] + args)
|
subprocess.Popen([executable] + args)
|
||||||
@@ -241,11 +238,9 @@ class TrayManager:
|
|||||||
save_theme_to_config("standart")
|
save_theme_to_config("standart")
|
||||||
executable = sys.executable
|
executable = sys.executable
|
||||||
args = sys.argv
|
args = sys.argv
|
||||||
self.main_window.is_exiting = True
|
|
||||||
QApplication.quit()
|
QApplication.quit()
|
||||||
subprocess.Popen([executable] + args)
|
subprocess.Popen([executable] + args)
|
||||||
|
|
||||||
def force_exit(self):
|
def force_exit(self):
|
||||||
self.main_window.is_exiting = True
|
|
||||||
self.main_window.close()
|
self.main_window.close()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user