diff --git a/CHANGELOG.md b/CHANGELOG.md index d497a218..51072d66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [0.7.0] ### Features - AppImage support ( see below ) -- **Screenshots** button +- **Screenshots** button and panel - **Categories** filter ### Improvements @@ -29,8 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### AppImage support - Search, install, uninstall, downgrade, launch and retrieve the applications history -- Supported sources: [AppImageHub](https://appimage.github.io). -- Applications with no releases published to GitHub are not available +- Supported sources: [AppImageHub](https://appimage.github.io) ( **applications with no releases published to GitHub are currently not available** ) - Adds desktop entries ( menu shortcuts ) for the installed applications ( **~/.local/share/applications **) ## [0.6.4] 2019-10-13 diff --git a/README.md b/README.md index 17ab7cb4..ad81613b 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ will be pre-downloaded faster ( it does **NOT** modify your **pacman** settings ### AppImage support ( appimage gem ) - The user is able to search, install, uninstall, downgrade, launch and retrieve the applications history -- Supported sources: [AppImageHub](https://appimage.github.io) ( **applications with no releases published to GitHub are not available yet** ) +- Supported sources: [AppImageHub](https://appimage.github.io) ( **applications with no releases published to GitHub are currently not available** ) - Faster downloads if **aria2c** is installed. Same behavior described in the **AUR support** section. - Installed applications are store at **~/.local/share/bauh/appimage/installed** - Desktop entries ( menu shortcuts ) of the installed applications are stored at **~/.local/share/applications** diff --git a/bauh/app.py b/bauh/app.py index 568bb67f..c6d90b1a 100755 --- a/bauh/app.py +++ b/bauh/app.py @@ -72,6 +72,7 @@ def main(): config=user_config, context=context, http_client=http_client, + logger=logger, notifications=bool(args.system_notifications)) if args.tray: diff --git a/bauh/gems/appimage/controller.py b/bauh/gems/appimage/controller.py index 59657a7c..ce5a78cc 100644 --- a/bauh/gems/appimage/controller.py +++ b/bauh/gems/appimage/controller.py @@ -130,6 +130,8 @@ class AppImageManager(SoftwareManager): app.url_download_latest_version = tup[3] break + except: + traceback.print_exc() finally: self._close_connection(DB_APPS_PATH, con) diff --git a/bauh/view/qt/screenshots.py b/bauh/view/qt/screenshots.py index 14408051..8151aab5 100644 --- a/bauh/view/qt/screenshots.py +++ b/bauh/view/qt/screenshots.py @@ -1,21 +1,32 @@ +import logging +from threading import Thread from typing import List +from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon, QPixmap from PyQt5.QtWidgets import QDialog, QLabel, QGridLayout, QPushButton from bauh.api.abstract.cache import MemoryCache +from bauh.api.http import HttpClient from bauh.view.qt import qt_utils from bauh.view.qt.view_model import PackageView class ScreenshotsDialog(QDialog): - def __init__(self, pkg: PackageView, icon_cache: MemoryCache, i18n: dict, screenshots: List[QPixmap]): + MAX_HEIGHT = 600 + MAX_WIDTH = 800 + + def __init__(self, pkg: PackageView, http_client: HttpClient, icon_cache: MemoryCache, i18n: dict, screenshots: List[QPixmap], logger: logging.Logger): super(ScreenshotsDialog, self).__init__() self.setWindowTitle(str(pkg)) self.screenshots = screenshots + self.logger = logger + self.loaded_imgs = [] + self.download_threads = [] self.resize(1280, 720) self.i18n = i18n + self.http_client = http_client icon_data = icon_cache.get(pkg.model.icon_url) @@ -36,30 +47,73 @@ class ScreenshotsDialog(QDialog): self.img = QLabel() self.layout().addWidget(self.img, 1, 1) + self.img_label = QLabel() + self.img_label.setStyleSheet('QLabel { font-weight: bold; text-align: center }') + self.layout().addWidget(self.img_label, 2, 1) + + self.img_idx = 0 + + for idx, s in enumerate(self.screenshots): + t = Thread(target=self._download_img, args=(idx, s)) + t.start() - self.idx = 0 self._load_img() def _load_img(self): - pixmap = self.screenshots[self.idx] - self.img.setPixmap(pixmap) + if len(self.loaded_imgs) > self.img_idx: + img = self.loaded_imgs[self.img_idx] + + if isinstance(img, QPixmap): + self.img_label.setText('') + self.img.setPixmap(img) + else: + self.img_label.setText(img) + self.img.setPixmap(QPixmap()) + else: + self.img.setPixmap(QPixmap()) + self.img_label.setText('...{}...'.format(self.i18n['screenshots,download.running'])) if len(self.screenshots) == 1: self.bt_back.setVisible(False) self.bt_next.setVisible(False) else: - self.bt_back.setVisible(self.idx != 0) - self.bt_next.setVisible(self.idx != len(self.screenshots) - 1) + self.bt_back.setEnabled(self.img_idx != 0) + self.bt_next.setEnabled(self.img_idx != len(self.screenshots) - 1) self.adjustSize() qt_utils.centralize(self) + def _download_img(self, idx: int, url: str): + self.logger.info('Downloading image [{}] from {}'.format(idx, url)) + res = self.http_client.get(url) + + if res: + if not res.content: + self.logger.warning("Image [{}] from {} has no content".format(idx, url)) + self.screenshots.append(self.i18n['screenshots.download.no_content']) + return + else: + self.logger.info('Image [{}] successfully downloaded'.format(idx)) + pixmap = QPixmap() + pixmap.loadFromData(res.content) + + if pixmap.size().height() > self.MAX_HEIGHT or pixmap.size().width() > self.MAX_WIDTH: + pixmap = pixmap.scaled(self.MAX_WIDTH, self.MAX_HEIGHT, Qt.KeepAspectRatio, Qt.SmoothTransformation) + + self.loaded_imgs.append(pixmap) + + if self.img_idx == idx: + self._load_img() + else: + self.logger.info("Could not retrieve image [{}] from {}".format(idx, url)) + self.screenshots.append(self.i18n['screenshots.download.no_response']) + def back(self): - self.idx -= 1 + self.img_idx -= 1 self._load_img() def next(self): - self.idx += 1 + self.img_idx += 1 self._load_img() diff --git a/bauh/view/qt/thread.py b/bauh/view/qt/thread.py index 5cf1526d..75a95e12 100644 --- a/bauh/view/qt/thread.py +++ b/bauh/view/qt/thread.py @@ -1,12 +1,10 @@ import re import time from datetime import datetime, timedelta -from threading import Thread from typing import List, Type, Set import requests -from PyQt5.QtCore import QThread, pyqtSignal, Qt -from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import QThread, pyqtSignal from bauh.api.abstract.cache import MemoryCache from bauh.api.abstract.controller import SoftwareManager @@ -486,42 +484,14 @@ class CustomAction(AsyncAction): class GetScreenshots(AsyncAction): - MAX_HEIGHT = 600 - MAX_WIDTH = 800 - def __init__(self, manager: SoftwareManager, http_client: HttpClient, pkg: PackageView = None): + def __init__(self, manager: SoftwareManager, pkg: PackageView = None): super(GetScreenshots, self).__init__() self.pkg = pkg self.manager = manager - self.http_client = http_client - - def _get_img(self, url: str, imgs: list): - res = self.http_client.get(url) - - if res and res.status_code == 200 and res.content: - pixmap = QPixmap() - pixmap.loadFromData(res.content) - - if pixmap.size().height() > self.MAX_HEIGHT or pixmap.size().width() > self.MAX_WIDTH: - pixmap = pixmap.scaled(self.MAX_WIDTH, self.MAX_HEIGHT, Qt.KeepAspectRatio, Qt.SmoothTransformation) - - imgs.append(pixmap) def run(self): if self.pkg: - imgs = [] - screenshots = self.manager.get_screenshots(self.pkg.model) - - if screenshots: - threads = [] - for url in screenshots: - t = Thread(target=self._get_img, args=(url, imgs)) - t.start() - threads.append(t) - - for t in threads: - t.join() - - self.notify_finished({'pkg': self.pkg, 'screenshots': imgs}) + self.notify_finished({'pkg': self.pkg, 'screenshots': self.manager.get_screenshots(self.pkg.model)}) self.pkg = None diff --git a/bauh/view/qt/window.py b/bauh/view/qt/window.py index c875c7d7..5eb590c3 100755 --- a/bauh/view/qt/window.py +++ b/bauh/view/qt/window.py @@ -1,3 +1,4 @@ +import logging import operator import time from functools import reduce @@ -51,9 +52,11 @@ class ManageWindow(QWidget): def __init__(self, i18n: dict, icon_cache: MemoryCache, manager: SoftwareManager, disk_cache: bool, download_icons: bool, screen_size, suggestions: bool, display_limit: int, config: Configuration, - context: ApplicationContext, notifications: bool, http_client: HttpClient, tray_icon=None): + context: ApplicationContext, notifications: bool, http_client: HttpClient, logger: logging.Logger, + tray_icon=None): super(ManageWindow, self).__init__() self.i18n = i18n + self.logger = logger self.manager = manager self.tray_icon = tray_icon self.working = False # restrict the number of threaded actions @@ -227,7 +230,7 @@ class ManageWindow(QWidget): self.thread_suggestions = self._bind_async_action(FindSuggestions(man=self.manager), finished_call=self._finish_search, only_finished=True) self.thread_run_app = self._bind_async_action(LaunchApp(self.manager), finished_call=self._finish_run_app, only_finished=False) self.thread_custom_action = self._bind_async_action(CustomAction(manager=self.manager), finished_call=self._finish_custom_action) - self.thread_screenshots = self._bind_async_action(GetScreenshots(self.manager, http_client), finished_call=self._finish_get_screenshots) + self.thread_screenshots = self._bind_async_action(GetScreenshots(self.manager), finished_call=self._finish_get_screenshots) self.thread_apply_filters = ApplyFilters() self.thread_apply_filters.signal_finished.connect(self._finish_apply_filters_async) @@ -868,7 +871,12 @@ class ManageWindow(QWidget): self.finish_action() if res.get('screenshots'): - diag = ScreenshotsDialog(pkg=res['pkg'], icon_cache=self.icon_cache, i18n=self.i18n, screenshots=res['screenshots']) + diag = ScreenshotsDialog(pkg=res['pkg'], + http_client=self.http_client, + icon_cache=self.icon_cache, + logger=self.logger, + i18n=self.i18n, + screenshots=res['screenshots']) diag.exec_() else: dialog.show_message(title=self.i18n['error'], diff --git a/bauh/view/resources/locale/en b/bauh/view/resources/locale/en index 666adf4e..d5a511b4 100644 --- a/bauh/view/resources/locale/en +++ b/bauh/view/resources/locale/en @@ -133,4 +133,7 @@ screenshots.bt_next.label=next screenshots.bt_back.label=previous instantmessaging=messaging 2dgraphics=2d graphics -vectorgraphics=vector graphics \ No newline at end of file +vectorgraphics=vector graphics +screenshots,download.running=downloading image +screenshots.download.no_content=No content to display +screenshots.download.no_response=Image not found \ No newline at end of file diff --git a/bauh/view/resources/locale/es b/bauh/view/resources/locale/es index c777972f..09edcc9e 100644 --- a/bauh/view/resources/locale/es +++ b/bauh/view/resources/locale/es @@ -170,4 +170,7 @@ screenshots.bt_next.label=próxima screenshots.bt_back.label=anterior instantmessaging=mensajens 2dgraphics=gŕaficos 2d -vectorgraphics=gráficos vectoriales \ No newline at end of file +vectorgraphics=gráficos vectoriales +screenshots,download.running=descargando imagen +screenshots.download.no_content=No hay contenido para mostrar +screenshots.download.no_response=Imagen no encontrada \ No newline at end of file diff --git a/bauh/view/resources/locale/pt b/bauh/view/resources/locale/pt index 7d963837..e3aa4860 100644 --- a/bauh/view/resources/locale/pt +++ b/bauh/view/resources/locale/pt @@ -172,4 +172,7 @@ screenshots.bt_next.label=próxima screenshots.bt_back.label=anterior instantmessaging=mensagens 2dgraphics=gŕaficos 2d -vectorgraphics=gráficos vetoriais \ No newline at end of file +vectorgraphics=gráficos vetoriais +screenshots,download.running=baixando imagem +screenshots.download.no_content=Sem conteúdo para exibir +screenshots.download.no_response=Imagem não encontrada \ No newline at end of file