mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 01:14:15 +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)
|
- cli/tray: removed some unneeded API calls when listing updates [#234](https://github.com/vinifmor/bauh/issues/234)
|
||||||
|
|
||||||
- UI
|
- UI
|
||||||
|
- search: sorting packages by closest match instead of considering installed first
|
||||||
- upgrade summary dialog size
|
- upgrade summary dialog size
|
||||||
- displaying tips for some custom actions (on mouse hover)
|
- 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)
|
- 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)
|
type_=MessageType.ERROR)
|
||||||
return False
|
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):
|
def _can_work(self, man: SoftwareManager):
|
||||||
if self._available_cache is not None:
|
if self._available_cache is not None:
|
||||||
available = False
|
available = False
|
||||||
@@ -197,8 +176,8 @@ class GenericSoftwareManager(SoftwareManager):
|
|||||||
disk_loader.stop_working()
|
disk_loader.stop_working()
|
||||||
disk_loader.join()
|
disk_loader.join()
|
||||||
|
|
||||||
res.installed = self._sort(res.installed, norm_word)
|
# res.installed = self._sort(res.installed, norm_word)
|
||||||
res.new = self._sort(res.new, norm_word)
|
# res.new = self._sort(res.new, norm_word)
|
||||||
else:
|
else:
|
||||||
raise NoInternetException()
|
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
|
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()
|
hidden = not filters['name'] in pkg.model.name.lower()
|
||||||
|
|
||||||
return hidden
|
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 datetime import datetime, timedelta
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Type, Set, Tuple, Optional
|
from typing import List, Type, Set, Tuple, Optional, Iterable
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from PyQt5.QtCore import QThread, pyqtSignal, QObject
|
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 import timeshift
|
||||||
from bauh.view.core.config import CoreConfigManager
|
from bauh.view.core.config import CoreConfigManager
|
||||||
from bauh.view.qt import commons
|
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.qt.view_model import PackageView, PackageViewStatus
|
||||||
from bauh.view.util.translation import I18n
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
@@ -704,8 +705,7 @@ class SearchPackages(AsyncAction):
|
|||||||
if self.word:
|
if self.word:
|
||||||
try:
|
try:
|
||||||
res = self.manager.search(words=self.word, disk_loader=None, limit=-1, is_url=False)
|
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'] = sort_packages((*(res.installed or ()), *(res.new or ())), self.word)
|
||||||
search_res['pkgs_found'].extend(res.new)
|
|
||||||
except NoInternetException:
|
except NoInternetException:
|
||||||
search_res['error'] = 'internet.required'
|
search_res['error'] = 'internet.required'
|
||||||
finally:
|
finally:
|
||||||
@@ -951,48 +951,6 @@ class ApplyFilters(AsyncAction):
|
|||||||
def stop_waiting(self):
|
def stop_waiting(self):
|
||||||
self.wait_table_update = False
|
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):
|
def run(self):
|
||||||
if self.pkgs:
|
if self.pkgs:
|
||||||
pkgs_info = commons.new_pkgs_info()
|
pkgs_info = commons.new_pkgs_info()
|
||||||
@@ -1004,7 +962,7 @@ class ApplyFilters(AsyncAction):
|
|||||||
commons.apply_filters(pkgv, self.filters, pkgs_info, limit=not name_filtering)
|
commons.apply_filters(pkgv, self.filters, pkgs_info, limit=not name_filtering)
|
||||||
|
|
||||||
if name_filtering and pkgs_info['pkgs_displayed']:
|
if name_filtering and pkgs_info['pkgs_displayed']:
|
||||||
pkgs_info['pkgs_displayed'] = self._sort_by_word(word=self.filters['name'],
|
pkgs_info['pkgs_displayed'] = sort_packages(word=self.filters['name'],
|
||||||
pkgs=pkgs_info['pkgs_displayed'],
|
pkgs=pkgs_info['pkgs_displayed'],
|
||||||
limit=self.filters['display_limit'])
|
limit=self.filters['display_limit'])
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ class PackageView:
|
|||||||
self.update_checked = model.update
|
self.update_checked = model.update
|
||||||
self.status = PackageViewStatus.LOADING if model.status == PackageStatus.LOADING_DATA else PackageViewStatus.READY
|
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):
|
def __repr__(self):
|
||||||
return '{} ({})'.format(self.model.name, self.get_type_label())
|
return '{} ({})'.format(self.model.name, self.get_type_label())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user