diff --git a/rare/components/tabs/shop/search_results.py b/rare/components/tabs/shop/search_results.py index 9b2fb361..bfcad500 100644 --- a/rare/components/tabs/shop/search_results.py +++ b/rare/components/tabs/shop/search_results.py @@ -1,33 +1,43 @@ from PyQt5 import QtGui -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QScrollArea, QGroupBox +from PyQt5.QtCore import pyqtSignal, Qt +from PyQt5.QtGui import QFont +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QScrollArea, QGroupBox, QPushButton + +from rare.utils.extra_widgets import ImageLabel, FlowLayout -class SearchResults(QScrollArea): +class SearchResults(QWidget): show_info = pyqtSignal(dict) # TODO nice look def __init__(self): super(SearchResults, self).__init__() + self.main_layout = QVBoxLayout() + self.back_button = QPushButton() + self.main_layout.addWidget(self.back_button) + self.main_layout.addWidget(self.back_button) + self.result_area = QScrollArea() self.widget = QWidget() - self.layout = QVBoxLayout() + self.result_area.setWidgetResizable(True) + self.main_layout.addWidget(self.result_area) + self.result_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) + + self.result_area.setWidget(self.widget) + self.layout = FlowLayout() self.widget.setLayout(self.layout) - self.setWidget(self.widget) - self.setWidgetResizable(True) + + self.setLayout(self.main_layout) def show_results(self, results: list): QVBoxLayout().addWidget(self.widget) self.widget = QWidget() - self.layout = QVBoxLayout() - for i in range(self.layout.count()): - self.layout.removeItem(i) + self.layout = FlowLayout() for res in results: w = _SearchResultItem(res) w.show_info.connect(self.show_info.emit) self.layout.addWidget(w) - self.layout.addStretch(1) self.widget.setLayout(self.layout) - self.setWidget(self.widget) + self.result_area.setWidget(self.widget) class _SearchResultItem(QGroupBox): @@ -36,17 +46,41 @@ class _SearchResultItem(QGroupBox): def __init__(self, result: dict): super(_SearchResultItem, self).__init__() - self.layout = QHBoxLayout() + self.layout = QVBoxLayout() + self.image = ImageLabel() + for img in result["keyImages"]: + if img["type"] == "DieselStoreFrontTall": + width = 240 + self.image.update_image(img["url"], result["title"], (width, 360)) + break + else: + print("No image found") + self.layout.addWidget(self.image) self.res = result self.title = QLabel(self.res["title"]) + title_font = QFont() + title_font.setPixelSize(15) + self.title.setFont(title_font) + self.title.setWordWrap(True) self.layout.addWidget(self.title) - original_price = result['price']['totalPrice']['fmtPrice']['originalPrice'] - self.price = QLabel(f"{self.tr('Original price: ')}{original_price}") - self.layout.addWidget(self.price) + price = result['price']['totalPrice']['fmtPrice']['originalPrice'] + discount_price = result['price']['totalPrice']['fmtPrice']['discountPrice'] + price_layout = QHBoxLayout() + price = QLabel(price) + price_layout.addWidget(price) + if price != discount_price: + font = QFont() + font.setStrikeOut(True) + price.setFont(font) + price_layout.addWidget(QLabel(discount_price)) + # self.discount_price = QLabel(f"{self.tr('Discount price: ')}{discount_price}") + self.layout.addLayout(price_layout) self.setLayout(self.layout) + self.setFixedWidth(260) + def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None: if a0.button() == 1: self.show_info.emit(self.res) diff --git a/rare/components/tabs/shop/shop_info.py b/rare/components/tabs/shop/shop_info.py index ab9334ce..c3bb6f11 100644 --- a/rare/components/tabs/shop/shop_info.py +++ b/rare/components/tabs/shop/shop_info.py @@ -2,16 +2,15 @@ import json import logging import webbrowser -from PyQt5.QtCore import QLocale, QUrl, QJsonDocument, QJsonParseError, Qt +from PyQt5.QtCore import QUrl, QJsonDocument, QJsonParseError from PyQt5.QtGui import QPixmap, QFont from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from PyQt5.QtWidgets import QWidget, QLabel -from rare.utils.utils import get_lang - -from rare.utils.extra_widgets import WaitingSpinner from rare.components.tabs.shop.shop_models import ShopGame from rare.ui.components.tabs.store.shop_game_info import Ui_shop_info +from rare.utils.extra_widgets import WaitingSpinner, ImageLabel +from rare.utils.utils import get_lang logger = logging.getLogger("ShopInfo") @@ -25,6 +24,8 @@ class ShopGameInfo(QWidget, Ui_shop_info): super(ShopGameInfo, self).__init__() self.setupUi(self) self.open_store_button.clicked.connect(self.button_clicked) + self.image = ImageLabel() + self.image_stack.addWidget(self.image) self.image_stack.addWidget(WaitingSpinner()) self.manager = QNetworkAccessManager() @@ -48,7 +49,6 @@ class ShopGameInfo(QWidget, Ui_shop_info): # init API request locale = get_lang() - locale = "en" url = f"https://store-content.ak.epicgames.com/api/{locale}/content/{'products' if not is_bundle else 'bundles'}/{slug}" # game = api_utils.get_product(slug, locale) self.request = self.manager.get(QNetworkRequest(QUrl(url))) @@ -76,7 +76,11 @@ class ShopGameInfo(QWidget, Ui_shop_info): self.title.setText(self.game.title) self.price.setText(self.game.price) - self.discount_price.setText(self.game.discount_price) + if self.game.price != self.game.discount_price: + self.discount_price.setText(self.game.discount_price) + self.discount_price.setVisible(True) + else: + self.discount_price.setVisible(False) # print(self.game.reqs) bold_font = QFont() bold_font.setBold(True) @@ -88,16 +92,19 @@ class ShopGameInfo(QWidget, Ui_shop_info): self.req_group_box.layout().addWidget(rec_label, 0, 2) for i, (key, value) in enumerate(self.game.reqs["Windows"].items()): - self.req_group_box.layout().addWidget(QLabel(key), i+1, 0) + self.req_group_box.layout().addWidget(QLabel(key), i + 1, 0) min_label = QLabel(value[0]) min_label.setWordWrap(True) - self.req_group_box.layout().addWidget(min_label, i+1, 1) + self.req_group_box.layout().addWidget(min_label, i + 1, 1) rec_label = QLabel(value[1]) rec_label.setWordWrap(True) - self.req_group_box.layout().addWidget(rec_label, i+1, 2) + self.req_group_box.layout().addWidget(rec_label, i + 1, 2) - self.image_request = self.manager.get(QNetworkRequest(QUrl(self.game.image_urls.offer_image_tall))) - self.image_request.finished.connect(self.image_loaded) + self.image.update_image(self.game.image_urls.front_tall, self.game.title, (240, 320)) + + self.image_stack.setCurrentIndex(0) + # self.image_request = self.manager.get(QNetworkRequest(QUrl(self.game.image_urls.offer_image_tall))) + # self.image_request.finished.connect(self.image_loaded) try: if isinstance(self.game.developer, list): @@ -111,16 +118,5 @@ class ShopGameInfo(QWidget, Ui_shop_info): self.request.deleteLater() - def image_loaded(self): - if self.image_request and self.image_request.error() == QNetworkReply.NoError: - data = self.image_request.readAll().data() - pixmap = QPixmap() - pixmap.loadFromData(data) - self.image.setPixmap(pixmap.scaled(240, 320, transformMode=Qt.SmoothTransformation)) - self.image_stack.setCurrentIndex(0) - else: - logger.error("Load image failed") - def button_clicked(self): webbrowser.open("https://www.epicgames.com/store/de/p/" + self.slug) - diff --git a/rare/components/tabs/shop/shop_widget.py b/rare/components/tabs/shop/shop_widget.py index 3be1a464..86340e95 100644 --- a/rare/components/tabs/shop/shop_widget.py +++ b/rare/components/tabs/shop/shop_widget.py @@ -13,7 +13,7 @@ from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkRepl from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout, QCompleter from rare.ui.components.tabs.store.store import Ui_ShopWidget -from rare.utils.extra_widgets import WaitingSpinner +from rare.utils.extra_widgets import WaitingSpinner, ImageLabel from rare.utils.utils import get_lang @@ -55,7 +55,6 @@ class ShopWidget(QWidget, Ui_ShopWidget): if self.free_game_request.error() == QNetworkReply.NoError: try: free_games = json.loads(self.free_game_request.readAll().data().decode()) - print(free_games) except JSONDecodeError: return else: @@ -177,7 +176,15 @@ class GameWidget(QWidget): def __init__(self, json_info, path: str): super(GameWidget, self).__init__() self.layout = QVBoxLayout() - self.image = QLabel() + self.image = ImageLabel() + for img in json_info["keyImages"]: + if img["type"] in ["DieselStoreFrontWide", "VaultClosed"]: + width = 300 + self.image.update_image(img["url"], json_info["title"], (width, int(width * 9 / 16))) + break + else: + print("No image found") + self.slug = json_info["productSlug"] self.title = json_info["title"] if not os.path.exists(p := os.path.join(path, f"{json_info['title']}.png")): diff --git a/rare/ui/components/tabs/store/shop_game_info.py b/rare/ui/components/tabs/store/shop_game_info.py index ca03f6b5..f259a955 100644 --- a/rare/ui/components/tabs/store/shop_game_info.py +++ b/rare/ui/components/tabs/store/shop_game_info.py @@ -24,15 +24,6 @@ class Ui_shop_info(object): self.horizontalLayout.setObjectName("horizontalLayout") self.image_stack = QtWidgets.QStackedWidget(shop_info) self.image_stack.setObjectName("image_stack") - self.page = QtWidgets.QWidget() - self.page.setObjectName("page") - self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.page) - self.verticalLayout_3.setObjectName("verticalLayout_3") - self.image = QtWidgets.QLabel(self.page) - self.image.setMinimumSize(QtCore.QSize(240, 320)) - self.image.setObjectName("image") - self.verticalLayout_3.addWidget(self.image) - self.image_stack.addWidget(self.page) self.horizontalLayout.addWidget(self.image_stack) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") @@ -69,14 +60,13 @@ class Ui_shop_info(object): self.verticalLayout.addItem(spacerItem2) self.retranslateUi(shop_info) - self.image_stack.setCurrentIndex(0) + self.image_stack.setCurrentIndex(-1) QtCore.QMetaObject.connectSlotsByName(shop_info) def retranslateUi(self, shop_info): _translate = QtCore.QCoreApplication.translate shop_info.setWindowTitle(_translate("shop_info", "Form")) self.back_button.setText(_translate("shop_info", "Back")) - self.image.setText(_translate("shop_info", "TextLabel")) self.title.setText(_translate("shop_info", "Error")) self.dev.setText(_translate("shop_info", "TextLabel")) self.price.setText(_translate("shop_info", "TextLabel")) diff --git a/rare/ui/components/tabs/store/shop_game_info.ui b/rare/ui/components/tabs/store/shop_game_info.ui index 9bdfe083..17ebd5a8 100644 --- a/rare/ui/components/tabs/store/shop_game_info.ui +++ b/rare/ui/components/tabs/store/shop_game_info.ui @@ -26,25 +26,8 @@ - 0 + -1 - - - - - - - 240 - 320 - - - - TextLabel - - - - - diff --git a/rare/utils/extra_widgets.py b/rare/utils/extra_widgets.py index cfc66800..47c6f731 100644 --- a/rare/utils/extra_widgets.py +++ b/rare/utils/extra_widgets.py @@ -1,7 +1,8 @@ import os -from PyQt5.QtCore import Qt, QRect, QSize, QPoint, pyqtSignal -from PyQt5.QtGui import QMovie +from PyQt5.QtCore import Qt, QRect, QSize, QPoint, pyqtSignal, QUrl +from PyQt5.QtGui import QMovie, QPixmap +from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from PyQt5.QtWidgets import QLayout, QStyle, QSizePolicy, QLabel, QFileDialog, QHBoxLayout, QWidget, QPushButton, \ QStyleOptionTab, QStylePainter, QTabBar from qtawesome import icon @@ -250,3 +251,41 @@ class SelectViewWidget(QWidget): self.list_view.setIcon(icon("fa5s.list", color="orange")) self.icon_view = True self.toggled.emit() + + +class ImageLabel(QLabel): + + def __init__(self): + super(ImageLabel, self).__init__() + path = os.path.expanduser("~/.cache/rare/cache") + if p := os.environ.get("XDG_CACHE_HOME"): + path = p + self.path = path + self.manager = QNetworkAccessManager() + + def update_image(self, url, name, size: tuple = (240, 320)): + self.setFixedSize(*size) + self.img_size = size + self.name = name + for c in r'<>?":|\/* ': + self.name = self.name.replace(c, "") + if not os.path.exists(os.path.join(self.path, self.name+".png")): + self.request = self.manager.get(QNetworkRequest(QUrl(url))) + self.request.finished.connect(self.image_ready) + else: + self.show_image() + + def image_ready(self): + if self.request: + if self.request.error() == QNetworkReply.NoError: + with open(os.path.join(self.path, self.name + ".png"), "wb") as file: + file.write(self.request.readAll().data()) + file.close() + self.show_image() + else: + return + + def show_image(self): + self.image = QPixmap(os.path.join(self.path, self.name + ".png")).scaled(*self.img_size, + transformMode=Qt.SmoothTransformation) + self.setPixmap(self.image)