feat: optimize search

Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
2025-10-02 16:29:18 +05:00
parent baec62d1cb
commit e99c71c1f8
2 changed files with 156 additions and 112 deletions

View File

@@ -51,8 +51,9 @@ class GameLibraryManager:
self.sizeSlider: QSlider | None = None
self._update_timer: QTimer | None = None
self._pending_update = False
self.pending_deletions = deque() # Queue for deferred widget deletion
self.dirty = False # Flag for when full resort is needed
self.pending_deletions = deque()
self.is_filtering = False
self.dirty = False
def create_games_library_widget(self):
"""Creates the games library widget with search, grid, and slider."""
@@ -201,10 +202,13 @@ class GameLibraryManager:
self._pending_update = False
self._update_game_grid_immediate()
def update_game_grid(self, games_list: list[tuple] | None = None):
def update_game_grid(self, games_list: list[tuple] | None = None, is_filter: bool = False):
"""Schedules a game grid update with debouncing."""
if not is_filter:
if games_list is not None:
self.filtered_games = games_list
self.dirty = True # Full rebuild only for non-filter
self.is_filtering = is_filter
self._pending_update = True
if self._update_timer is not None:
@@ -217,8 +221,14 @@ class GameLibraryManager:
if self.gamesListLayout is None or self.gamesListWidget is None:
return
games_list = self.filtered_games if self.filtered_games else self.games
search_text = self.main_window.searchEdit.text().strip().lower()
if self.is_filtering:
# Filter mode: do not change layout, only hide/show cards
self._apply_filter_visibility(search_text)
else:
# Full update: sorting, removal/addition, reorganization
games_list = self.filtered_games if self.filtered_games else self.games
favorites = read_favorites()
sort_method = read_sort_method()
@@ -335,6 +345,34 @@ class GameLibraryManager:
self.gamesListWidget.updateGeometry()
self.main_window._last_card_width = self.card_width
self.is_filtering = False # Reset flag in any case
def _apply_filter_visibility(self, search_text: str):
"""Applies visibility to cards based on search, without changing the layout."""
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 geometry update so FlowLayout accounts for hidden widgets
if self.gamesListLayout is not None:
self.gamesListLayout.update()
if self.gamesListWidget is not None:
self.gamesListWidget.updateGeometry()
self.main_window._last_card_width = self.card_width
# If search is empty, load images for visible ones
if not search_text:
self.load_visible_images()
def _create_game_card(self, game_data: tuple) -> GameCard:
"""Creates a new game card with all necessary connections."""
card = GameCard(
@@ -412,9 +450,4 @@ class GameLibraryManager:
def filter_games_delayed(self):
"""Filters games based on search text and updates the grid."""
text = self.main_window.searchEdit.text().strip().lower()
if text == "":
self.filtered_games = self.games
else:
self.filtered_games = [game for game in self.games if text in game[0].lower()]
self.update_game_grid(self.filtered_games)
self.update_game_grid(is_filter=True)

View File

@@ -747,11 +747,22 @@ class MainWindow(QMainWindow):
self.searchDebounceTimer = QTimer(self)
self.searchDebounceTimer.setSingleShot(True)
self.searchDebounceTimer.setInterval(300)
self.searchDebounceTimer.timeout.connect(self.game_library_manager.filter_games_delayed)
self.searchDebounceTimer.timeout.connect(self.on_search_changed)
layout.addWidget(self.searchEdit)
return self.container, self.searchEdit
def on_search_text_changed(self, text: str):
"""Search text change handler with debounce."""
self.searchDebounceTimer.stop()
self.searchDebounceTimer.start()
@Slot()
def on_search_changed(self):
"""Triggers filtering with delay."""
if hasattr(self, 'game_library_manager'):
self.game_library_manager.filter_games_delayed()
def startSearchDebounce(self, text):
self.searchDebounceTimer.start()