mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-06 22:54:16 +02:00
[view] improvement: sorting packages by closest match instead of considering installed first (search)
This commit is contained in:
@@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- cli/tray: removed some unneeded API calls when listing updates [#234](https://github.com/vinifmor/bauh/issues/234)
|
||||
|
||||
- UI
|
||||
- search: sorting packages by closest match instead of considering installed first
|
||||
- upgrade summary dialog size
|
||||
- displaying tips for some custom actions (on mouse hover)
|
||||
- screenshots: displaying the current image index as a label in the button bar (e.g: 1/3)
|
||||
|
||||
@@ -115,27 +115,6 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
type_=MessageType.ERROR)
|
||||
return False
|
||||
|
||||
def _sort(self, apps: List[SoftwarePackage], word: str) -> List[SoftwarePackage]:
|
||||
|
||||
exact_name_matches, contains_name_matches, others = [], [], []
|
||||
|
||||
for app in apps:
|
||||
lower_name = app.name.lower()
|
||||
|
||||
if word == lower_name:
|
||||
exact_name_matches.append(app)
|
||||
elif word in lower_name:
|
||||
contains_name_matches.append(app)
|
||||
else:
|
||||
others.append(app)
|
||||
|
||||
res = []
|
||||
for app_list in (exact_name_matches, contains_name_matches, others):
|
||||
app_list.sort(key=lambda a: a.name.lower())
|
||||
res.extend(app_list)
|
||||
|
||||
return res
|
||||
|
||||
def _can_work(self, man: SoftwareManager):
|
||||
if self._available_cache is not None:
|
||||
available = False
|
||||
@@ -197,8 +176,8 @@ class GenericSoftwareManager(SoftwareManager):
|
||||
disk_loader.stop_working()
|
||||
disk_loader.join()
|
||||
|
||||
res.installed = self._sort(res.installed, norm_word)
|
||||
res.new = self._sort(res.new, norm_word)
|
||||
# res.installed = self._sort(res.installed, norm_word)
|
||||
# res.new = self._sort(res.new, norm_word)
|
||||
else:
|
||||
raise NoInternetException()
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
from typing import Iterable, List
|
||||
|
||||
from bauh.api.abstract.model import SoftwarePackage
|
||||
from bauh.view.qt.view_model import PackageView
|
||||
|
||||
|
||||
@@ -73,3 +76,33 @@ def is_package_hidden(pkg: PackageView, filters: dict) -> bool:
|
||||
hidden = not filters['name'] in pkg.model.name.lower()
|
||||
|
||||
return hidden
|
||||
|
||||
|
||||
def sort_packages(pkgs: Iterable[SoftwarePackage], word: str, limit: int = 0) -> List[SoftwarePackage]:
|
||||
exact, starts_with, contains, others = [], [], [], []
|
||||
|
||||
for p in pkgs:
|
||||
lower_name = p.name.lower()
|
||||
|
||||
if word == lower_name:
|
||||
exact.append(p)
|
||||
elif lower_name.startswith(word):
|
||||
starts_with.append(p)
|
||||
elif word in lower_name:
|
||||
contains.append(p)
|
||||
else:
|
||||
others.append(p)
|
||||
|
||||
res = []
|
||||
for app_list in (exact, starts_with, contains, others):
|
||||
if app_list:
|
||||
last = limit - len(res) if limit > 0 else None
|
||||
|
||||
if last is not None and last <= 0:
|
||||
break
|
||||
|
||||
to_add = app_list[0:last]
|
||||
to_add.sort(key=lambda a: a.name.lower())
|
||||
res.extend(to_add)
|
||||
|
||||
return res
|
||||
|
||||
@@ -5,7 +5,7 @@ import traceback
|
||||
from datetime import datetime, timedelta
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from typing import List, Type, Set, Tuple, Optional
|
||||
from typing import List, Type, Set, Tuple, Optional, Iterable
|
||||
|
||||
import requests
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, QObject
|
||||
@@ -27,6 +27,7 @@ from bauh.commons.system import get_human_size_str, ProcessHandler, SimpleProces
|
||||
from bauh.view.core import timeshift
|
||||
from bauh.view.core.config import CoreConfigManager
|
||||
from bauh.view.qt import commons
|
||||
from bauh.view.qt.commons import sort_packages
|
||||
from bauh.view.qt.view_model import PackageView, PackageViewStatus
|
||||
from bauh.view.util.translation import I18n
|
||||
|
||||
@@ -704,8 +705,7 @@ class SearchPackages(AsyncAction):
|
||||
if self.word:
|
||||
try:
|
||||
res = self.manager.search(words=self.word, disk_loader=None, limit=-1, is_url=False)
|
||||
search_res['pkgs_found'].extend(res.installed)
|
||||
search_res['pkgs_found'].extend(res.new)
|
||||
search_res['pkgs_found'] = sort_packages((*(res.installed or ()), *(res.new or ())), self.word)
|
||||
except NoInternetException:
|
||||
search_res['error'] = 'internet.required'
|
||||
finally:
|
||||
@@ -951,48 +951,6 @@ class ApplyFilters(AsyncAction):
|
||||
def stop_waiting(self):
|
||||
self.wait_table_update = False
|
||||
|
||||
def _sort_by_word(self, word: str, pkgs: List[PackageView], limit: int) -> List[PackageView]:
|
||||
norm_word = word.strip().lower()
|
||||
exact_installed, exact_not_installed = [], []
|
||||
starts_installed, starts_not_installed = [], []
|
||||
contains_installed, contains_not_installed = [], []
|
||||
|
||||
for p in pkgs:
|
||||
lower_name = p.model.name.lower()
|
||||
|
||||
if norm_word == lower_name:
|
||||
if p.model.installed:
|
||||
exact_installed.append(p)
|
||||
else:
|
||||
exact_not_installed.append(p)
|
||||
elif lower_name.startswith(norm_word):
|
||||
if p.model.installed:
|
||||
starts_installed.append(p)
|
||||
else:
|
||||
starts_not_installed.append(p)
|
||||
else:
|
||||
if p.model.installed:
|
||||
contains_installed.append(p)
|
||||
else:
|
||||
contains_not_installed.append(p)
|
||||
|
||||
res = []
|
||||
for matches in (exact_installed, exact_not_installed,
|
||||
starts_installed, starts_not_installed,
|
||||
contains_installed, contains_not_installed):
|
||||
if matches:
|
||||
matches.sort(key=lambda p: p.model.name.lower())
|
||||
|
||||
if limit:
|
||||
res.extend(matches[0:limit - len(res)])
|
||||
|
||||
if len(res) == limit:
|
||||
break
|
||||
else:
|
||||
res.extend(matches)
|
||||
|
||||
return res
|
||||
|
||||
def run(self):
|
||||
if self.pkgs:
|
||||
pkgs_info = commons.new_pkgs_info()
|
||||
@@ -1004,9 +962,9 @@ class ApplyFilters(AsyncAction):
|
||||
commons.apply_filters(pkgv, self.filters, pkgs_info, limit=not name_filtering)
|
||||
|
||||
if name_filtering and pkgs_info['pkgs_displayed']:
|
||||
pkgs_info['pkgs_displayed'] = self._sort_by_word(word=self.filters['name'],
|
||||
pkgs=pkgs_info['pkgs_displayed'],
|
||||
limit=self.filters['display_limit'])
|
||||
pkgs_info['pkgs_displayed'] = sort_packages(word=self.filters['name'],
|
||||
pkgs=pkgs_info['pkgs_displayed'],
|
||||
limit=self.filters['display_limit'])
|
||||
|
||||
self.wait_table_update = True
|
||||
self.signal_table.emit(pkgs_info)
|
||||
|
||||
@@ -32,6 +32,10 @@ class PackageView:
|
||||
self.update_checked = model.update
|
||||
self.status = PackageViewStatus.LOADING if model.status == PackageStatus.LOADING_DATA else PackageViewStatus.READY
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.model.name
|
||||
|
||||
def __repr__(self):
|
||||
return '{} ({})'.format(self.model.name, self.get_type_label())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user