1
0
Fork 0
mirror of synced 2024-06-02 02:34:40 +12:00

Store: Exploratory changes to the store page

Important changes:
* Refactored QtRequests to accept parameters for `GET` operations
* Infer response data type from content-type header
* Support caching to disk, a manager with this set prefers the cache
* Support multiple handlers for a single request (unused, possibly pointeless)

* Subclass `ShopImageWidget` for all widgets used in the shop
* Request a resized image instead of the original one
* Fix the search and browse functions
This commit is contained in:
loathingKernel 2023-04-04 14:46:02 +03:00
parent 9817170999
commit 5bc27c948f
No known key found for this signature in database
GPG key ID: CE0C72D0B53821FD
21 changed files with 577 additions and 525 deletions

View file

@ -33,7 +33,7 @@ class About(QWidget, Ui_About):
self.open_browser.setVisible(False)
self.open_browser.setEnabled(False)
self.manager = QtRequestManager("json")
self.manager = QtRequestManager()
self.manager.get(
"https://api.github.com/repos/RareDevs/Rare/releases/latest",
self.update_available_finished,

View file

@ -25,12 +25,12 @@ class StoreTab(SideTabWidget):
)
self.shop = ShopWidget(cache_dir(), self.core, self.api_core, parent=self)
self.shop_index = self.addTab(self.shop, self.tr("Games"))
self.shop_index = self.addTab(self.shop, self.tr("Store"))
self.shop.show_game.connect(self.show_game)
self.shop.show_info.connect(self.show_search)
self.search = SearchResults(self.api_core, parent=self)
self.search_index = self.addTab(self.search, self.tr("Search"))
self.search_index = self.addTab(self.search, self.tr("Search"), self.tr("Results"))
self.search.show_info.connect(self.show_game)
# self.search.back_button.clicked.connect(lambda: self.setCurrentIndex(self.shop_index))
@ -40,11 +40,11 @@ class StoreTab(SideTabWidget):
self.api_core,
parent=self
)
self.info_index = self.addTab(self.info, self.tr("Information"))
self.info_index = self.addTab(self.info, self.tr("Information"), self.tr("Information"))
# self.info.back_button.clicked.connect(lambda: self.setCurrentIndex(self.previous_index))
self.wishlist = Wishlist(self.api_core, parent=self)
self.wishlist_index = self.addTab(self.wishlist, self.tr("Wishlist"))
self.wishlist_index = self.addTab(self.wishlist, self.tr("Wishlist"), self.tr("Wishlist"))
self.wishlist.update_wishlist_signal.connect(self.update_wishlist)
self.wishlist.show_game_info.connect(self.show_game)

View file

@ -27,9 +27,12 @@ if __name__ == "__main__":
import rare.resources.stylesheets.RareStyle
app = QApplication(sys.argv)
app.setApplicationName("Rare")
app.setOrganizationName("Rare")
set_style_sheet("RareStyle")
window = StoreWindow()
window.setWindowTitle(f"{app.applicationName()} - Store")
window.resize(QSize(1280, 800))
window.show()
app.exec()

View file

@ -33,7 +33,7 @@ class ShopGameInfo(QWidget, SideTabContents):
self.api_core = api_core
self.installed = installed_titles
self.ui.open_store_button.clicked.connect(self.button_clicked)
self.image = ShopImageWidget(self)
self.image = ShopImageWidget(api_core.cached_manager, self)
self.image.setFixedSize(ImageSize.Normal)
self.ui.left_layout.insertWidget(0, self.image, alignment=Qt.AlignTop)
@ -139,7 +139,7 @@ class ShopGameInfo(QWidget, SideTabContents):
"VaultClosed",
"ProductLogo",
]:
self.image.fetchPixmap(img["url"], self.id_str, self.title_str)
self.image.fetchPixmap(img["url"])
break
self.price.setText("")
self.discount_price.setText("")
@ -207,7 +207,7 @@ class ShopGameInfo(QWidget, SideTabContents):
img_url = self.game.image_urls.product_logo
else:
img_url = ""
self.image.fetchPixmap(img_url, self.game.id, self.game.title)
self.image.fetchPixmap(img_url)
# self.image_stack.setCurrentIndex(0)
try:

View file

@ -1,15 +1,13 @@
import logging
from PyQt5 import QtGui
from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtGui import QFont, QMouseEvent
from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import QPushButton
from rare.components.tabs.store.shop_models import ImageUrlModel
from rare.shared.image_manager import ImageSize
from rare.ui.components.tabs.store.wishlist_widget import Ui_WishlistWidget
from rare.utils.extra_widgets import ImageLabel
from rare.utils.misc import icon
from rare.utils.qt_requests import QtRequestManager
from .image_widget import ShopImageWidget
logger = logging.getLogger("GameWidgets")
@ -18,11 +16,10 @@ logger = logging.getLogger("GameWidgets")
class GameWidget(ShopImageWidget):
show_info = pyqtSignal(dict)
def __init__(self, path, json_info=None, parent=None):
super(GameWidget, self).__init__(parent=parent)
def __init__(self, manager: QtRequestManager, json_info=None, parent=None):
super(GameWidget, self).__init__(manager, parent=parent)
self.setFixedSize(ImageSize.Wide)
self.ui.setupUi(self)
self.path = path
self.json_info = json_info
if json_info:
self.init_ui(json_info)
@ -33,6 +30,13 @@ class GameWidget(ShopImageWidget):
return
self.ui.title_label.setText(json_info.get("title"))
for attr in json_info["customAttributes"]:
if attr["key"] == "developerName":
developer = attr["value"]
break
else:
developer = json_info["seller"]["name"]
self.ui.developer_label.setText(developer)
price = json_info["price"]["totalPrice"]["fmtPrice"]["originalPrice"]
discount_price = json_info["price"]["totalPrice"]["fmtPrice"]["discountPrice"]
self.ui.price_label.setText(f'{price if price != "0" else self.tr("Free")}')
@ -51,7 +55,7 @@ class GameWidget(ShopImageWidget):
if img["type"] in ["DieselStoreFrontWide", "OfferImageWide", "VaultClosed", "ProductLogo",]:
if img["type"] == "VaultClosed" and json_info["title"] != "Mystery Game":
continue
self.fetchPixmap(img["url"], json_info["id"], json_info["title"])
self.fetchPixmap(img["url"])
break
else:
logger.info(", ".join([img["type"] for img in json_info["keyImages"]]))
@ -62,52 +66,52 @@ class GameWidget(ShopImageWidget):
self.show_info.emit(self.json_info)
class WishlistWidget(QWidget, Ui_WishlistWidget):
class WishlistWidget(ShopImageWidget):
open_game = pyqtSignal(dict)
delete_from_wishlist = pyqtSignal(dict)
def __init__(self, game: dict):
super(WishlistWidget, self).__init__()
self.setupUi(self)
def __init__(self, manager: QtRequestManager, game: dict, parent=None):
super(WishlistWidget, self).__init__(manager, parent=parent)
self.setFixedSize(ImageSize.Wide)
self.ui.setupUi(self)
self.game = game
self.title_label.setText(game.get("title"))
for attr in game["customAttributes"]:
if attr["key"] == "developerName":
self.developer.setText(attr["value"])
developer = attr["value"]
break
else:
self.developer.setText(game["seller"]["name"])
developer = game["seller"]["name"]
original_price = game["price"]["totalPrice"]["fmtPrice"]["originalPrice"]
discount_price = game["price"]["totalPrice"]["fmtPrice"]["discountPrice"]
self.price.setText(original_price if original_price != "0" else self.tr("Free"))
# if discount
self.ui.title_label.setText(game.get("title"))
self.ui.developer_label.setText(developer)
self.ui.price_label.setText(f'{original_price if original_price != "0" else self.tr("Free")}')
if original_price != discount_price:
self.discount = True
font = QFont()
font = self.ui.price_label.font()
font.setStrikeOut(True)
self.price.setFont(font)
self.discount_price.setText(discount_price)
self.ui.price_label.setFont(font)
self.ui.discount_label.setText(f'{discount_price if discount_price != "0" else self.tr("Free")}')
else:
self.discount = False
self.discount_price.setVisible(False)
self.image = ImageLabel()
self.layout().insertWidget(0, self.image)
self.ui.discount_label.setVisible(False)
image_model = ImageUrlModel.from_json(game["keyImages"])
url = image_model.front_wide
if not url:
url = image_model.offer_image_wide
self.image.update_image(url, game.get("title"), (240, 135))
self.fetchPixmap(url)
self.delete_button = QPushButton(self)
self.delete_button.setIcon(icon("mdi.delete", color="white"))
self.delete_button.clicked.connect(
lambda: self.delete_from_wishlist.emit(self.game)
)
self.layout().insertWidget(0, self.delete_button, alignment=Qt.AlignRight)
def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
def mousePressEvent(self, a0: QMouseEvent) -> None:
# left button
if e.button() == 1:
if a0.button() == Qt.LeftButton:
a0.accept()
self.open_game.emit(self.game)
# right
elif e.button() == 2:
elif a0.button() == Qt.RightButton:
pass # self.showMenu(e)

View file

@ -1,10 +1,10 @@
from typing import Dict
from PyQt5.QtCore import QRect
from PyQt5.QtCore import QEvent, QObject
from PyQt5.QtCore import Qt
from PyQt5.QtGui import (
QPixmap,
QImage, QMovie,
QImage,
QMovie,
QShowEvent,
)
from PyQt5.QtWidgets import (
QWidget,
@ -24,19 +24,43 @@ class WaitingSpinner(QLabel):
super(WaitingSpinner, self).__init__(parent=parent)
self.setObjectName(type(self).__name__)
self.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.movie = QMovie(":/images/loader.gif")
self.movie = QMovie(":/images/loader.gif", parent=self)
self.setFixedSize(128, 128)
self.setMovie(self.movie)
if self.parent() is not None:
self.parent().installEventFilter(self)
if autostart:
self.movie.start()
def setGeometry(self, a0: QRect) -> None:
self.rect().moveCenter(self.parent().rect().center())
super(WaitingSpinner, self).setGeometry(self.rect())
def __center_on_parent(self):
rect = self.rect()
rect.moveCenter(self.parent().contentsRect().center())
self.setGeometry(rect)
def event(self, e: QEvent) -> bool:
if e.type() == QEvent.ParentAboutToChange:
if self.parent() is not None:
self.parent().removeEventFilter(self)
if e.type() == QEvent.ParentChange:
if self.parent() is not None:
self.parent().installEventFilter(self)
return super().event(e)
def showEvent(self, a0: QShowEvent) -> None:
self.__center_on_parent()
def eventFilter(self, a0: QObject, a1: QEvent) -> bool:
if a0 is self.parent() and a1.type() == QEvent.Resize:
self.__center_on_parent()
return a0.event(a1)
return False
def start(self):
self.setVisible(True)
self.movie.start()
def stop(self):
self.setVisible(False)
self.movie.stop()
@ -44,6 +68,7 @@ class IconWidget(object):
def __init__(self):
self.mini_widget: QWidget = None
self.title_label: QLabel = None
self.developer_label: QLabel = None
self.price_label: QLabel = None
self.discount_label: QLabel = None
@ -57,19 +82,24 @@ class IconWidget(object):
self.title_label = QLabel(parent=self.mini_widget)
self.title_label.setObjectName(f"{type(self).__name__}TitleLabel")
self.title_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.title_label.setAlignment(Qt.AlignVCenter)
self.title_label.setAlignment(Qt.AlignTop)
self.title_label.setAutoFillBackground(False)
self.title_label.setWordWrap(True)
# information below title
self.developer_label = QLabel(parent=self.mini_widget)
self.developer_label.setObjectName(f"{type(self).__name__}TooltipLabel")
self.developer_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
self.developer_label.setAutoFillBackground(False)
self.price_label = QLabel(parent=self.mini_widget)
self.price_label.setObjectName(f"{type(self).__name__}TooltipLabel")
self.price_label.setAlignment(Qt.AlignRight)
self.price_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
self.price_label.setAutoFillBackground(False)
self.discount_label = QLabel(parent=self.mini_widget)
self.discount_label.setObjectName(f"{type(self).__name__}TooltipLabel")
self.discount_label.setAlignment(Qt.AlignRight)
self.discount_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
self.discount_label.setAutoFillBackground(False)
# Create layouts
@ -88,7 +118,8 @@ class IconWidget(object):
# Layout the widgets
# (from inner to outer)
row_layout.addWidget(self.price_label, stretch=2)
row_layout.addWidget(self.developer_label, stretch=2)
row_layout.addWidget(self.price_label)
row_layout.addWidget(self.discount_label)
mini_layout.addWidget(self.title_label)
mini_layout.addLayout(row_layout)
@ -100,45 +131,29 @@ class IconWidget(object):
class ShopImageWidget(ImageWidget):
__image_cache: Dict[str, Dict[str, QPixmap]] = {}
def __init__(self, parent=None):
def __init__(self, manager: QtRequestManager, parent=None):
super(ShopImageWidget, self).__init__(parent=parent)
self.ui = IconWidget()
self.spinner = WaitingSpinner(parent=self)
self.spinner.setVisible(False)
self.manager = QtRequestManager("bytes")
self.app_id = ""
self.orientation = ""
self.manager = manager
def fetchPixmap(self, url, app_id: str, title: str = ""):
def fetchPixmap(self, url):
self.setPixmap(QPixmap())
self.app_id = app_id
if self._image_size.size.width() > self._image_size.size.height():
self.orientation = "wide"
else:
self.orientation = "tall"
if ShopImageWidget.__image_cache.get(self.app_id, None) is not None:
if pixmap := ShopImageWidget.__image_cache[self.app_id].get(self.orientation, None):
self.setPixmap(pixmap)
return
self.spinner.setFixedSize(self._image_size.size)
self.spinner.setVisible(True)
self.spinner.start()
self.manager.get(
url, self.__on_image_ready, payload={
"resize": 1, "w": self._image_size.size.width(), "h": self._image_size.size.height()
}
)
self.manager.get(url, self.__on_image_ready, params={
"resize": 1,
"w": self._image_size.base.size.width(),
"h": self._image_size.base.size.height(),
})
def __on_image_ready(self, data):
cover = QImage()
cover.loadFromData(data)
cover = cover.scaled(self._image_size.size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
# cover = cover.scaled(self._image_size.size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
cover.setDevicePixelRatio(self._image_size.base.pixel_ratio)
cover = cover.convertToFormat(QImage.Format_ARGB32_Premultiplied)
cover = QPixmap(cover)
ShopImageWidget.__image_cache.update({self.app_id: {self.orientation: cover}})
super(ShopImageWidget, self).setPixmap(cover)
self.setPixmap(cover)
self.spinner.stop()
self.spinner.setVisible(False)

View file

@ -2,36 +2,36 @@ from PyQt5.QtCore import Qt
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import (
QFrame,
QWidget,
QVBoxLayout,
QSizePolicy,
QLabel,
QLabel, QScrollArea,
)
from rare.shared.image_manager import ImageSize
from rare.utils.qt_requests import QtRequestManager
from rare.widgets.flow_layout import FlowLayout
from rare.widgets.side_tab import SideTabContents
from .image_widget import ShopImageWidget
class SearchResults(QWidget):
class SearchResults(QScrollArea, SideTabContents):
show_info = pyqtSignal(dict)
def __init__(self, api_core, parent=None):
super(SearchResults, self).__init__(parent=parent)
self.implements_scrollarea = True
self.api_core = api_core
self.results_frame = QFrame(self)
self.results_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.results_frame.setFrameStyle(QFrame.StyledPanel)
self.results_layout = FlowLayout(self.results_frame)
self.results_frame.setLayout(self.results_layout)
self.results_container = QWidget(self)
self.results_container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.results_layout = FlowLayout(self.results_container)
self.setWidget(self.results_container)
self.setWidgetResizable(True)
self.main_layout = QVBoxLayout()
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.addWidget(self.results_frame)
# self.main_layout = QVBoxLayout(self)
# self.main_layout.setContentsMargins(0, 0, 0, 0)
# self.main_layout.addWidget(self.results_scrollarea)
self.setLayout(self.main_layout)
self.setEnabled(False)
def load_results(self, text: str):
@ -40,10 +40,10 @@ class SearchResults(QWidget):
self.api_core.search_game(text, self.show_results)
def show_results(self, results: dict):
for w in self.results_frame.findChildren(QLabel, options=Qt.FindDirectChildrenOnly):
for w in self.results_container.findChildren(QLabel, options=Qt.FindDirectChildrenOnly):
self.results_layout.removeWidget(w)
w.deleteLater()
for w in self.results_frame.findChildren(SearchResultItem, options=Qt.FindDirectChildrenOnly):
for w in self.results_container.findChildren(SearchResultItem, options=Qt.FindDirectChildrenOnly):
self.results_layout.removeWidget(w)
w.deleteLater()
@ -51,22 +51,23 @@ class SearchResults(QWidget):
self.results_layout.addWidget(QLabel(self.tr("No results found")))
else:
for res in results:
w = SearchResultItem(res, parent=self.results_frame)
w = SearchResultItem(self.api_core.cached_manager, res, parent=self.results_container)
w.show_info.connect(self.show_info.emit)
self.results_layout.addWidget(w)
self.results_layout.update()
self.setEnabled(True)
class SearchResultItem(ShopImageWidget):
show_info = pyqtSignal(dict)
def __init__(self, result: dict, parent=None):
super(SearchResultItem, self).__init__(parent=parent)
def __init__(self, manager: QtRequestManager, result: dict, parent=None):
super(SearchResultItem, self).__init__(manager, parent=parent)
self.setFixedSize(ImageSize.Normal)
self.ui.setupUi(self)
for img in result["keyImages"]:
if img["type"] in ["DieselStoreFrontTall", "OfferImageTall", "Thumbnail", "ProductLogo"]:
self.fetchPixmap(img["url"], result["id"], result["title"])
self.fetchPixmap(img["url"])
break
else:
print("No image found")

View file

@ -1,4 +1,3 @@
import urllib.parse
from logging import getLogger
from PyQt5.QtCore import pyqtSignal, QObject
@ -10,31 +9,37 @@ from rare.components.tabs.store.constants import (
remove_from_wishlist_query,
)
from rare.components.tabs.store.shop_models import BrowseModel
from rare.utils.paths import cache_dir
from rare.utils.qt_requests import QtRequestManager
logger = getLogger("ShopAPICore")
graphql_url = "https://www.epicgames.com/graphql"
graphql_url = "https://graphql.epicgames.com/graphql"
class ShopApiCore(QObject):
update_wishlist = pyqtSignal()
def __init__(self, auth_token, lc: str, cc: str):
def __init__(self, token, language: str, country: str):
super(ShopApiCore, self).__init__()
self.token = auth_token
self.language_code: str = lc
self.country_code: str = cc
self.token = token
self.language_code: str = language
self.country_code: str = country
self.locale = f"{self.language_code}-{self.country_code}"
self.manager = QtRequestManager()
self.auth_manager = QtRequestManager(authorization_token=auth_token)
self.manager = QtRequestManager(parent=self)
self.authed_manager = QtRequestManager(token=token, parent=self)
self.cached_manager = QtRequestManager(cache=str(cache_dir().joinpath("store")), parent=self)
self.browse_active = False
self.next_browse_request = tuple(())
def get_free_games(self, handle_func: callable):
url = f"https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale={self.language_code}&country={self.country_code}&allowCountries={self.country_code}"
self.manager.get(url, lambda data: self._handle_free_games(data, handle_func))
url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions"
params = {
"locale": self.locale,
"country": self.country_code,
"allowCountries": self.country_code,
}
self.manager.get(url, lambda data: self._handle_free_games(data, handle_func), params=params)
def _handle_free_games(self, data, handle_func):
try:
@ -50,16 +55,16 @@ class ShopApiCore(QObject):
handle_func(results)
def get_wishlist(self, handle_func):
self.auth_manager.post(
self.authed_manager.post(
graphql_url,
lambda data: self._handle_wishlist(data, handle_func),
{
"query": wishlist_query,
"variables": {
"country": self.country_code,
"locale": f"{self.language_code}-{self.country_code}",
"locale": self.locale,
},
},
lambda data: self._handle_wishlist(data, handle_func),
)
def _handle_wishlist(self, data, handle_func):
@ -94,9 +99,7 @@ class ShopApiCore(QObject):
},
}
self.manager.post(
graphql_url, payload, lambda data: self._handle_search(data, handle_func)
)
self.manager.post(graphql_url, lambda data: self._handle_search(data, handle_func), payload)
def _handle_search(self, data, handle_func):
try:
@ -114,37 +117,11 @@ class ShopApiCore(QObject):
self.next_browse_request = (browse_model, handle_func)
return
self.browse_active = True
url = "https://www.epicgames.com/graphql?operationName=searchStoreQuery&variables={}&extensions={}"
variables = urllib.parse.quote_plus(str(
dict(browse_model.__dict__))
)
extensions = urllib.parse.quote_plus(str(
dict(
persistedQuery=dict(
version=1,
sha256Hash="6e7c4dd0177150eb9a47d624be221929582df8648e7ec271c821838ff4ee148e"
)
)
)
)
for old, new in [
("%26", "&"),
("%27", "%22"),
("+", ""),
("%3A", ":"),
("%2C", ","),
("%5B", "["),
("%5D", "]"),
("True", "true"),
]:
variables = variables.replace(old, new)
extensions = extensions.replace(old, new)
url = url.format(variables, extensions)
self.auth_manager.get(
url, lambda data: self._handle_browse_games(data, handle_func)
)
payload = {
"query": search_query,
"variables": browse_model.__dict__
}
self.manager.post(graphql_url, lambda data: self._handle_browse_games(data, handle_func), payload)
def _handle_browse_games(self, data, handle_func):
self.browse_active = False
@ -188,11 +165,7 @@ class ShopApiCore(QObject):
},
"query": add_to_wishlist_query,
}
self.auth_manager.post(
graphql_url,
payload,
lambda data: self._handle_add_to_wishlist(data, handle_func),
)
self.authed_manager.post(graphql_url, lambda data: self._handle_add_to_wishlist(data, handle_func), payload)
def _handle_add_to_wishlist(self, data, handle_func):
try:
@ -215,11 +188,8 @@ class ShopApiCore(QObject):
},
"query": remove_from_wishlist_query,
}
self.auth_manager.post(
graphql_url,
payload,
lambda data: self._handle_remove_from_wishlist(data, handle_func),
)
self.authed_manager.post(graphql_url, lambda data: self._handle_remove_from_wishlist(data, handle_func),
payload)
def _handle_remove_from_wishlist(self, data, handle_func):
try:

View file

@ -1,6 +1,7 @@
import datetime
from dataclasses import dataclass
from typing import List, Dict
import epicstore_api.queries as egs_query
class ImageUrlModel:
@ -158,22 +159,26 @@ class BrowseModel:
price: str = ""
onSale: bool = False
def __post_init__(self):
self.locale = f"{self.language_code}-{self.country_code}"
@property
def __dict__(self):
payload = {
"allowCountries": self.country_code,
"category": self.category,
"count": self.count,
"country": self.country_code,
"keywords": self.keywords,
"locale": self.language_code,
"priceRange": self.price,
"releaseDate": self.date,
"category": self.category,
"allowCountries": self.country_code,
"namespace": "",
"sortBy": "releaseDate",
"sortDir": self.sortDir,
"start": self.start,
"keywords": self.keywords,
"tag": self.tag,
"priceRange": self.price,
"releaseDate": self.date,
"withPrice": self.withPrice,
"locale": self.locale,
"country": self.country_code,
}
if self.price == "free":
payload["freeGame"] = True
@ -187,5 +192,4 @@ class BrowseModel:
payload["effectiveDate"] = self.date
else:
payload.pop("priceRange")
return payload

View file

@ -9,15 +9,17 @@ from PyQt5.QtWidgets import (
QLabel,
QPushButton,
QHBoxLayout,
QWidget, QSizePolicy,
QWidget, QSizePolicy, QStackedLayout,
)
from legendary.core import LegendaryCore
from rare.ui.components.tabs.store.store import Ui_ShopWidget
from rare.utils.extra_widgets import WaitingSpinner, ButtonLineEdit
from rare.utils.extra_widgets import ButtonLineEdit
from rare.widgets.flow_layout import FlowLayout
from rare.widgets.side_tab import SideTabContents
from .constants import Constants
from .game_widgets import GameWidget
from .image_widget import WaitingSpinner
from .shop_api_core import ShopApiCore
from .shop_models import BrowseModel
@ -25,14 +27,16 @@ logger = logging.getLogger("Shop")
# noinspection PyAttributeOutsideInit,PyBroadException
class ShopWidget(QWidget, Ui_ShopWidget):
class ShopWidget(QWidget, SideTabContents):
show_info = pyqtSignal(str)
show_game = pyqtSignal(dict)
def __init__(self, path, core: LegendaryCore, shop_api: ShopApiCore, parent=None):
def __init__(self, cache_dir, core: LegendaryCore, shop_api: ShopApiCore, parent=None):
super(ShopWidget, self).__init__(parent=parent)
self.setupUi(self)
self.path = path
self.implements_scrollarea = True
self.ui = Ui_ShopWidget()
self.ui.setupUi(self)
self.cache_dir = cache_dir
self.core = core
self.api_core = shop_api
self.price = ""
@ -40,25 +44,39 @@ class ShopWidget(QWidget, Ui_ShopWidget):
self.types = []
self.update_games_allowed = True
self.free_scrollarea.setDisabled(True)
self.ui.free_scrollarea.setDisabled(True)
self.free_game_widgets = []
self.active_search_request = False
self.next_search = ""
self.wishlist: List = []
self.discount_widget.setLayout(FlowLayout(self.discount_widget))
self.discount_stack.addWidget(WaitingSpinner(self.discount_stack))
self.discount_stack.setCurrentIndex(1)
self.discounts_layout = QStackedLayout(self.ui.discounts_group)
self.discounts_spinner = WaitingSpinner(self.ui.discounts_group)
self.discounts_flow = QWidget(self.ui.discounts_group)
self.discounts_flow.setLayout(FlowLayout(self.discounts_flow))
self.discounts_flow.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.discounts_layout.addWidget(self.discounts_spinner)
self.discounts_layout.addWidget(self.discounts_flow)
self.game_widget.setLayout(FlowLayout(self.game_widget))
self.game_stack.addWidget(WaitingSpinner(self.game_stack))
self.game_stack.setCurrentIndex(1)
self.discounts_spinner.start()
self.discounts_layout.setCurrentWidget(self.discounts_spinner)
self.games_layout = QStackedLayout(self.ui.games_group)
self.games_spinner = WaitingSpinner(self.ui.games_group)
self.games_flow = QWidget(self.ui.games_group)
self.games_flow.setLayout(FlowLayout(self.games_flow))
self.games_flow.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.games_layout.addWidget(self.games_spinner)
self.games_layout.addWidget(self.games_flow)
self.games_spinner.start()
self.games_layout.setCurrentWidget(self.games_spinner)
self.search_bar = ButtonLineEdit(
"fa.search", placeholder_text=self.tr("Search Games")
)
self.left_layout.insertWidget(0, self.search_bar)
self.ui.left_layout.insertWidget(0, self.search_bar)
# self.search_bar.textChanged.connect(self.search_games)
@ -81,22 +99,21 @@ class ShopWidget(QWidget, Ui_ShopWidget):
self.api_core.get_wishlist(self.add_wishlist_items)
def add_wishlist_items(self, wishlist):
for i in range(self.discount_widget.layout().count()):
item = self.discount_widget.layout().itemAt(i)
if item:
item.widget().deleteLater()
for w in self.discounts_flow.findChildren(QGroupBox, options=Qt.FindDirectChildrenOnly):
self.discounts_flow.layout().removeWidget(w)
w.deleteLater()
if wishlist and wishlist[0] == "error":
self.discount_widget.layout().addWidget(
QLabel(self.tr("Failed to get wishlist: {}").format(wishlist[1]))
)
btn = QPushButton(self.tr("Reload"))
self.discount_widget.layout().addWidget(btn)
btn.clicked.connect(
lambda: self.api_core.get_wishlist(self.add_wishlist_items)
)
self.discount_stack.setCurrentIndex(0)
return
# if wishlist and wishlist[0] == "error":
# self.discounts_group.layout().addWidget(
# QLabel(self.tr("Failed to get wishlist: {}").format(wishlist[1]))
# )
# btn = QPushButton(self.tr("Reload"))
# self.discount_widget.layout().addWidget(btn)
# btn.clicked.connect(
# lambda: self.api_core.get_wishlist(self.add_wishlist_items)
# )
# self.discount_stack.setCurrentIndex(0)
# return
discounts = 0
for game in wishlist:
@ -104,48 +121,48 @@ class ShopWidget(QWidget, Ui_ShopWidget):
continue
try:
if game["offer"]["price"]["totalPrice"]["discount"] > 0:
w = GameWidget(self.path, game["offer"])
w = GameWidget(self.api_core.cached_manager, game["offer"])
w.show_info.connect(self.show_game)
self.discount_widget.layout().addWidget(w)
self.discounts_flow.layout().addWidget(w)
discounts += 1
except Exception as e:
logger.warning(f"{game} {e}")
continue
self.discounts_group.setVisible(discounts > 0)
self.discount_stack.setCurrentIndex(0)
# fix widget overlay
self.discount_widget.layout().update()
self.ui.discounts_group.setVisible(discounts > 0)
self.discounts_layout.setCurrentWidget(self.discounts_flow)
# FIXME: FlowLayout doesn't update on adding widget
self.discounts_flow.layout().update()
def add_free_games(self, free_games: list):
for w in self.free_container.layout().findChildren(QGroupBox, options=Qt.FindDirectChildrenOnly):
self.free_container.layout().removeWidget(w)
for w in self.ui.free_container.layout().findChildren(QGroupBox, options=Qt.FindDirectChildrenOnly):
self.ui.free_container.layout().removeWidget(w)
w.deleteLater()
if free_games and free_games[0] == "error":
self.free_container.layout().addWidget(
self.ui.free_container.layout().addWidget(
QLabel(self.tr("Failed to fetch free games: {}").format(free_games[1]))
)
btn = QPushButton(self.tr("Reload"))
self.free_container.layout().addWidget(btn)
self.ui.free_container.layout().addWidget(btn)
btn.clicked.connect(
lambda: self.api_core.get_free_games(self.add_free_games)
)
self.free_container.setEnabled(True)
self.ui.free_container.setEnabled(True)
return
self.free_games_now = QGroupBox(self.tr("Free now"), parent=self.free_container)
self.free_games_now = QGroupBox(self.tr("Free now"), parent=self.ui.free_container)
free_games_now_layout = QHBoxLayout(self.free_games_now)
# free_games_now_layout.setContentsMargins(0, 0, 0, 0)
self.free_games_now.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.free_games_now.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.free_games_now.setLayout(free_games_now_layout)
self.free_container.layout().addWidget(self.free_games_now)
self.ui.free_container.layout().addWidget(self.free_games_now)
self.free_games_next = QGroupBox(self.tr("Free next week"), parent=self.free_container)
self.free_games_next = QGroupBox(self.tr("Free next week"), parent=self.ui.free_container)
free_games_next_layout = QHBoxLayout(self.free_games_next)
# free_games_next_layout.setContentsMargins(0, 0, 0, 0)
self.free_games_next.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.free_games_next.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.free_games_next.setLayout(free_games_next_layout)
self.free_container.layout().addWidget(self.free_games_next)
self.ui.free_container.layout().addWidget(self.free_games_next)
date = datetime.datetime.now()
free_games_now = []
@ -196,7 +213,7 @@ class ShopWidget(QWidget, Ui_ShopWidget):
# free games now
now_free = 0
for free_game in free_games_now:
w = GameWidget(self.path, free_game)
w = GameWidget(self.api_core.cached_manager, free_game)
w.show_info.connect(self.show_game)
self.free_games_now.layout().addWidget(w)
self.free_game_widgets.append(w)
@ -208,64 +225,64 @@ class ShopWidget(QWidget, Ui_ShopWidget):
# free games next week
for free_game in coming_free_games:
w = GameWidget(self.path, free_game)
w = GameWidget(self.api_core.cached_manager, free_game)
if free_game["title"] != "Mystery Game":
w.show_info.connect(self.show_game)
self.free_games_next.layout().addWidget(w)
# self.coming_free_games.setFixedWidth(int(40 + len(coming_free_games) * 300))
self.free_scrollarea.setMinimumHeight(
self.ui.free_scrollarea.setMinimumHeight(
self.free_games_now.sizeHint().height()
+ self.free_container.layout().contentsMargins().top()
+ self.free_container.layout().contentsMargins().bottom()
+ self.free_scrollarea.horizontalScrollBar().sizeHint().height()
+ self.ui.free_container.layout().contentsMargins().top()
+ self.ui.free_container.layout().contentsMargins().bottom()
+ self.ui.free_scrollarea.horizontalScrollBar().sizeHint().height()
)
self.free_scrollarea.setEnabled(True)
self.ui.free_scrollarea.setEnabled(True)
def show_search_results(self):
if self.search_bar.text():
self.show_info.emit(self.search_bar.text())
def init_filter(self):
self.none_price.toggled.connect(
lambda: self.prepare_request("") if self.none_price.isChecked() else None
self.ui.none_price.toggled.connect(
lambda: self.prepare_request("") if self.ui.none_price.isChecked() else None
)
self.free_button.toggled.connect(
self.ui.free_button.toggled.connect(
lambda: self.prepare_request("free")
if self.free_button.isChecked()
if self.ui.free_button.isChecked()
else None
)
self.under10.toggled.connect(
self.ui.under10.toggled.connect(
lambda: self.prepare_request("<price>[0, 1000)")
if self.under10.isChecked()
if self.ui.under10.isChecked()
else None
)
self.under20.toggled.connect(
self.ui.under20.toggled.connect(
lambda: self.prepare_request("<price>[0, 2000)")
if self.under20.isChecked()
if self.ui.under20.isChecked()
else None
)
self.under30.toggled.connect(
self.ui.under30.toggled.connect(
lambda: self.prepare_request("<price>[0, 3000)")
if self.under30.isChecked()
if self.ui.under30.isChecked()
else None
)
self.above.toggled.connect(
self.ui.above.toggled.connect(
lambda: self.prepare_request("<price>[1499,]")
if self.above.isChecked()
if self.ui.above.isChecked()
else None
)
# self.on_discount.toggled.connect(lambda: self.prepare_request("sale") if self.on_discount.isChecked() else None)
self.on_discount.toggled.connect(lambda: self.prepare_request())
self.ui.on_discount.toggled.connect(lambda: self.prepare_request())
constants = Constants()
self.checkboxes = []
for groupbox, variables in [
(self.genre_group, constants.categories),
(self.platform_group, constants.platforms),
(self.others_group, constants.others),
(self.type_group, constants.types),
(self.ui.genre_group, constants.categories),
(self.ui.platform_group, constants.platforms),
(self.ui.others_group, constants.others),
(self.ui.type_group, constants.types),
]:
for text, tag in variables:
@ -276,26 +293,26 @@ class ShopWidget(QWidget, Ui_ShopWidget):
)
groupbox.layout().addWidget(checkbox)
self.checkboxes.append(checkbox)
self.reset_button.clicked.connect(self.reset_filters)
self.filter_scrollarea.setMinimumWidth(
self.filter_container.sizeHint().width()
+ self.filter_container.layout().contentsMargins().left()
+ self.filter_container.layout().contentsMargins().right()
+ self.filter_scrollarea.verticalScrollBar().sizeHint().width()
self.ui.reset_button.clicked.connect(self.reset_filters)
self.ui.filter_scrollarea.setMinimumWidth(
self.ui.filter_container.sizeHint().width()
+ self.ui.filter_container.layout().contentsMargins().left()
+ self.ui.filter_container.layout().contentsMargins().right()
+ self.ui.filter_scrollarea.verticalScrollBar().sizeHint().width()
)
def reset_filters(self):
self.update_games_allowed = False
for cb in self.checkboxes:
cb.setChecked(False)
self.none_price.setChecked(True)
self.ui.none_price.setChecked(True)
self.tags = []
self.types = []
self.update_games_allowed = True
self.prepare_request("")
self.on_discount.setChecked(False)
self.ui.on_discount.setChecked(False)
def prepare_request(
self,
@ -319,22 +336,22 @@ class ShopWidget(QWidget, Ui_ShopWidget):
self.types.append(added_type)
if removed_type and removed_type in self.types:
self.types.remove(removed_type)
if (self.types or self.price) or self.tags or self.on_discount.isChecked():
self.free_scrollarea.setVisible(False)
self.discounts_group.setVisible(False)
if (self.types or self.price) or self.tags or self.ui.on_discount.isChecked():
self.ui.free_scrollarea.setVisible(False)
self.ui.discounts_group.setVisible(False)
else:
self.free_scrollarea.setVisible(True)
if len(self.discounts_group.layout().children()) > 0:
self.discounts_group.setVisible(True)
self.ui.free_scrollarea.setVisible(True)
if len(self.ui.discounts_group.layout().children()) > 0:
self.ui.discounts_group.setVisible(True)
self.game_stack.setCurrentIndex(1)
self.games_layout.setCurrentWidget(self.games_spinner)
browse_model = BrowseModel(
language_code=self.core.language_code,
country_code=self.core.country_code,
count=20,
price=self.price,
onSale=self.on_discount.isChecked(),
onSale=self.ui.on_discount.isChecked(),
)
browse_model.tag = "|".join(self.tags)
@ -343,24 +360,22 @@ class ShopWidget(QWidget, Ui_ShopWidget):
self.api_core.browse_games(browse_model, self.show_games)
def show_games(self, data):
for item in (
self.game_widget.layout().itemAt(i)
for i in range(self.game_widget.layout().count())
):
item.widget().deleteLater()
for w in self.games_flow.layout().findChildren(GameWidget, options=Qt.FindDirectChildrenOnly):
self.games_flow.layout().removeWidget(w)
w.deleteLater()
if data:
for game in data:
w = GameWidget(self.path, game)
self.game_widget.layout().addWidget(w)
w = GameWidget(self.api_core.cached_manager, game)
w.show_info.connect(self.show_game.emit)
self.games_flow.layout().addWidget(w)
else:
self.game_widget.layout().addWidget(
self.games_flow.layout().addWidget(
QLabel(self.tr("Could not get games matching the filter"))
)
self.game_stack.setCurrentIndex(0)
self.game_widget.layout().update()
self.games_layout.setCurrentWidget(self.games_flow)
# FIXME: FlowLayout doesn't update on adding widget
self.games_flow.layout().update()
class CheckBox(QCheckBox):

View file

@ -1,9 +1,10 @@
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtWidgets import QMessageBox, QWidget
from rare.ui.components.tabs.store.wishlist import Ui_Wishlist
from rare.utils.misc import icon
from rare.widgets.side_tab import SideTabContents
from rare.widgets.flow_layout import FlowLayout
from .shop_api_core import ShopApiCore
from .game_widgets import WishlistWidget
@ -14,6 +15,7 @@ class Wishlist(QWidget, SideTabContents):
def __init__(self, api_core: ShopApiCore, parent=None):
super(Wishlist, self).__init__(parent=parent)
self.implements_scrollarea = True
self.api_core = api_core
self.ui = Ui_Wishlist()
self.ui.setupUi(self)
@ -21,20 +23,19 @@ class Wishlist(QWidget, SideTabContents):
self.wishlist = []
self.widgets = []
self.ui.sort_cb.currentIndexChanged.connect(
lambda i: self.set_wishlist(self.wishlist, i)
)
self.list_layout = FlowLayout(self.ui.list_container)
self.ui.sort_cb.currentIndexChanged.connect(self.sort_wishlist)
self.ui.filter_cb.currentIndexChanged.connect(self.set_filter)
self.ui.reload_button.clicked.connect(self.update_wishlist)
self.ui.reload_button.setIcon(icon("fa.refresh", color="white"))
self.ui.reverse.stateChanged.connect(
lambda: self.set_wishlist(sort=self.ui.sort_cb.currentIndex())
lambda: self.sort_wishlist(sort=self.ui.sort_cb.currentIndex())
)
def update_wishlist(self):
self.setEnabled(False)
self.set_title.emit("Wishlist")
self.api_core.get_wishlist(self.set_wishlist)
def delete_from_wishlist(self, game):
@ -66,6 +67,32 @@ class Wishlist(QWidget, SideTabContents):
else:
self.ui.no_games_label.setVisible(False)
def sort_wishlist(self, sort=0):
widgets = self.ui.list_container.findChildren(WishlistWidget, options=Qt.FindDirectChildrenOnly)
for w in widgets:
self.ui.list_container.layout().removeWidget(w)
if sort == 0:
func = lambda x: x.game["title"]
reverse = self.ui.reverse.isChecked()
elif sort == 1:
func = lambda x: x.game["price"]["totalPrice"]["fmtPrice"]["discountPrice"]
reverse = self.ui.reverse.isChecked()
elif sort == 2:
func = lambda x: x.game["seller"]["name"]
reverse = self.ui.reverse.isChecked()
elif sort == 3:
func = lambda x: 1 - (x.game["price"]["totalPrice"]["discountPrice"] / x.game["price"]["totalPrice"]["originalPrice"])
reverse = not self.ui.reverse.isChecked()
else:
func = lambda x: x.game["title"]
reverse = self.ui.reverse.isChecked()
widgets = sorted(widgets, key=func, reverse=reverse)
for w in widgets:
self.ui.list_container.layout().addWidget(w)
def set_wishlist(self, wishlist=None, sort=0):
if wishlist and wishlist[0] == "error":
return
@ -76,45 +103,18 @@ class Wishlist(QWidget, SideTabContents):
for i in self.widgets:
i.deleteLater()
if sort == 0:
sorted_list = sorted(self.wishlist, key=lambda x: x["offer"]["title"])
elif sort == 1:
sorted_list = sorted(
self.wishlist,
key=lambda x: x["offer"]["price"]["totalPrice"]["fmtPrice"][
"discountPrice"
],
)
elif sort == 2:
sorted_list = sorted(
self.wishlist, key=lambda x: x["offer"]["seller"]["name"]
)
elif sort == 3:
sorted_list = sorted(
self.wishlist,
reverse=True,
key=lambda x: 1
- (
x["offer"]["price"]["totalPrice"]["discountPrice"]
/ x["offer"]["price"]["totalPrice"]["originalPrice"]
),
)
else:
sorted_list = self.wishlist
self.widgets.clear()
if len(sorted_list) == 0:
if len(wishlist) == 0:
self.ui.no_games_label.setVisible(True)
else:
self.ui.no_games_label.setVisible(False)
if self.ui.reverse.isChecked():
sorted_list.reverse()
for game in sorted_list:
w = WishlistWidget(game["offer"])
self.widgets.append(w)
self.ui.list_layout.addWidget(w)
for game in wishlist:
w = WishlistWidget(self.api_core.cached_manager, game["offer"], self.ui.list_container)
w.open_game.connect(self.show_game_info.emit)
w.delete_from_wishlist.connect(self.delete_from_wishlist)
self.widgets.append(w)
self.list_layout.addWidget(w)
self.list_layout.update()
self.setEnabled(True)

View file

@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ShopInfo(object):
def setupUi(self, ShopInfo):
ShopInfo.setObjectName("ShopInfo")
ShopInfo.resize(434, 250)
ShopInfo.resize(747, 442)
ShopInfo.setWindowTitle("ShopGameInfo")
self.main_layout = QtWidgets.QHBoxLayout(ShopInfo)
self.main_layout.setObjectName("main_layout")

View file

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>434</width>
<height>250</height>
<width>747</width>
<height>442</height>
</rect>
</property>
<property name="windowTitle">

View file

@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ShopWidget(object):
def setupUi(self, ShopWidget):
ShopWidget.setObjectName("ShopWidget")
ShopWidget.resize(750, 588)
ShopWidget.resize(350, 382)
ShopWidget.setWindowTitle("Store")
self.shop_layout = QtWidgets.QHBoxLayout(ShopWidget)
self.shop_layout.setObjectName("shop_layout")
@ -27,7 +27,7 @@ class Ui_ShopWidget(object):
self.games_scrollarea.setWidgetResizable(True)
self.games_scrollarea.setObjectName("games_scrollarea")
self.games_container = QtWidgets.QWidget()
self.games_container.setGeometry(QtCore.QRect(0, 0, 583, 574))
self.games_container.setGeometry(QtCore.QRect(0, 0, 186, 368))
self.games_container.setObjectName("games_container")
self.games_container_layout = QtWidgets.QVBoxLayout(self.games_container)
self.games_container_layout.setContentsMargins(0, 0, 3, 0)
@ -44,7 +44,12 @@ class Ui_ShopWidget(object):
self.free_scrollarea.setWidgetResizable(True)
self.free_scrollarea.setObjectName("free_scrollarea")
self.free_container = QtWidgets.QWidget()
self.free_container.setGeometry(QtCore.QRect(0, 0, 580, 83))
self.free_container.setGeometry(QtCore.QRect(0, 0, 16, 16))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.free_container.sizePolicy().hasHeightForWidth())
self.free_container.setSizePolicy(sizePolicy)
self.free_container.setObjectName("free_container")
self.free_container_layout = QtWidgets.QHBoxLayout(self.free_container)
self.free_container_layout.setContentsMargins(0, 0, 0, 3)
@ -53,25 +58,9 @@ class Ui_ShopWidget(object):
self.games_container_layout.addWidget(self.free_scrollarea)
self.discounts_group = QtWidgets.QGroupBox(self.games_container)
self.discounts_group.setObjectName("discounts_group")
self.discounts_layout = QtWidgets.QVBoxLayout(self.discounts_group)
self.discounts_layout.setObjectName("discounts_layout")
self.discount_stack = QtWidgets.QStackedWidget(self.discounts_group)
self.discount_stack.setObjectName("discount_stack")
self.discount_widget = QtWidgets.QWidget()
self.discount_widget.setObjectName("discount_widget")
self.discount_stack.addWidget(self.discount_widget)
self.discounts_layout.addWidget(self.discount_stack)
self.games_container_layout.addWidget(self.discounts_group)
self.games_group = QtWidgets.QGroupBox(self.games_container)
self.games_group.setObjectName("games_group")
self.games_layout = QtWidgets.QVBoxLayout(self.games_group)
self.games_layout.setObjectName("games_layout")
self.game_stack = QtWidgets.QStackedWidget(self.games_group)
self.game_stack.setObjectName("game_stack")
self.game_widget = QtWidgets.QWidget()
self.game_widget.setObjectName("game_widget")
self.game_stack.addWidget(self.game_widget)
self.games_layout.addWidget(self.game_stack)
self.games_container_layout.addWidget(self.games_group)
self.games_scrollarea.setWidget(self.games_container)
self.left_layout.addWidget(self.games_scrollarea)
@ -94,7 +83,12 @@ class Ui_ShopWidget(object):
self.filter_scrollarea.setWidgetResizable(True)
self.filter_scrollarea.setObjectName("filter_scrollarea")
self.filter_container = QtWidgets.QWidget()
self.filter_container.setGeometry(QtCore.QRect(0, 0, 145, 542))
self.filter_container.setGeometry(QtCore.QRect(0, 0, 142, 390))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.filter_container.sizePolicy().hasHeightForWidth())
self.filter_container.setSizePolicy(sizePolicy)
self.filter_container.setObjectName("filter_container")
self.filter_container_layout = QtWidgets.QVBoxLayout(self.filter_container)
self.filter_container_layout.setContentsMargins(0, 0, 3, 0)

View file

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>750</width>
<height>588</height>
<width>679</width>
<height>329</height>
</rect>
</property>
<property name="windowTitle">
@ -35,8 +35,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>583</width>
<height>574</height>
<width>515</width>
<height>315</height>
</rect>
</property>
<layout class="QVBoxLayout" name="games_container_layout">
@ -77,10 +77,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>580</width>
<height>83</height>
<width>16</width>
<height>16</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="free_container_layout">
<property name="leftMargin">
<number>0</number>
@ -103,13 +109,6 @@
<property name="title">
<string>Discounts from your wishlist</string>
</property>
<layout class="QVBoxLayout" name="discounts_layout">
<item>
<widget class="QStackedWidget" name="discount_stack">
<widget class="QWidget" name="discount_widget"/>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@ -117,13 +116,6 @@
<property name="title">
<string>Games</string>
</property>
<layout class="QVBoxLayout" name="games_layout">
<item>
<widget class="QStackedWidget" name="game_stack">
<widget class="QWidget" name="game_widget"/>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
@ -169,10 +161,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>145</width>
<height>542</height>
<width>142</width>
<height>390</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="filter_container_layout">
<property name="leftMargin">
<number>0</number>

View file

@ -14,12 +14,12 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Wishlist(object):
def setupUi(self, Wishlist):
Wishlist.setObjectName("Wishlist")
Wishlist.resize(527, 328)
Wishlist.resize(423, 153)
Wishlist.setWindowTitle("Wishlist")
self.verticalLayout = QtWidgets.QVBoxLayout(Wishlist)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.tool_layout = QtWidgets.QHBoxLayout()
self.tool_layout.setObjectName("tool_layout")
self.sort_label = QtWidgets.QLabel(Wishlist)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
@ -27,29 +27,29 @@ class Ui_Wishlist(object):
sizePolicy.setHeightForWidth(self.sort_label.sizePolicy().hasHeightForWidth())
self.sort_label.setSizePolicy(sizePolicy)
self.sort_label.setObjectName("sort_label")
self.horizontalLayout.addWidget(self.sort_label)
self.tool_layout.addWidget(self.sort_label)
self.sort_cb = QtWidgets.QComboBox(Wishlist)
self.sort_cb.setObjectName("sort_cb")
self.sort_cb.addItem("")
self.sort_cb.addItem("")
self.sort_cb.addItem("")
self.sort_cb.addItem("")
self.horizontalLayout.addWidget(self.sort_cb)
self.tool_layout.addWidget(self.sort_cb)
self.reverse = QtWidgets.QCheckBox(Wishlist)
self.reverse.setObjectName("reverse")
self.horizontalLayout.addWidget(self.reverse)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.tool_layout.addWidget(self.reverse)
spacerItem = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.tool_layout.addItem(spacerItem)
self.filter_label = QtWidgets.QLabel(Wishlist)
self.filter_label.setObjectName("filter_label")
self.horizontalLayout.addWidget(self.filter_label)
self.tool_layout.addWidget(self.filter_label)
self.filter_cb = QtWidgets.QComboBox(Wishlist)
self.filter_cb.setObjectName("filter_cb")
self.filter_cb.addItem("")
self.filter_cb.addItem("")
self.horizontalLayout.addWidget(self.filter_cb)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.tool_layout.addWidget(self.filter_cb)
spacerItem1 = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.tool_layout.addItem(spacerItem1)
self.reload_button = QtWidgets.QPushButton(Wishlist)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@ -58,16 +58,19 @@ class Ui_Wishlist(object):
self.reload_button.setSizePolicy(sizePolicy)
self.reload_button.setText("")
self.reload_button.setObjectName("reload_button")
self.horizontalLayout.addWidget(self.reload_button)
self.verticalLayout.addLayout(self.horizontalLayout)
self.list_layout = QtWidgets.QVBoxLayout()
self.list_layout.setObjectName("list_layout")
self.verticalLayout.addLayout(self.list_layout)
self.tool_layout.addWidget(self.reload_button)
self.verticalLayout.addLayout(self.tool_layout)
self.no_games_label = QtWidgets.QLabel(Wishlist)
self.no_games_label.setObjectName("no_games_label")
self.verticalLayout.addWidget(self.no_games_label)
spacerItem2 = QtWidgets.QSpacerItem(379, 218, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem2)
self.list_scrollarea = QtWidgets.QScrollArea(Wishlist)
self.list_scrollarea.setWidgetResizable(True)
self.list_scrollarea.setObjectName("list_scrollarea")
self.list_container = QtWidgets.QWidget()
self.list_container.setGeometry(QtCore.QRect(0, 0, 407, 83))
self.list_container.setObjectName("list_container")
self.list_scrollarea.setWidget(self.list_container)
self.verticalLayout.addWidget(self.list_scrollarea)
self.retranslateUi(Wishlist)

View file

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>527</width>
<height>328</height>
<width>423</width>
<height>153</height>
</rect>
</property>
<property name="windowTitle">
@ -15,7 +15,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="tool_layout">
<item>
<widget class="QLabel" name="sort_label">
<property name="sizePolicy">
@ -61,14 +61,14 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<spacer name="tool_hspacer_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
@ -95,14 +95,14 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<spacer name="tool_hspacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
@ -122,9 +122,6 @@
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="list_layout"/>
</item>
<item>
<widget class="QLabel" name="no_games_label">
<property name="text">
@ -133,17 +130,21 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<widget class="QScrollArea" name="list_scrollarea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>379</width>
<height>218</height>
</size>
</property>
</spacer>
<widget class="QWidget" name="list_container">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>407</width>
<height>83</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/store/wishlist_widget.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@ -14,20 +14,26 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_WishlistWidget(object):
def setupUi(self, WishlistWidget):
WishlistWidget.setObjectName("WishlistWidget")
WishlistWidget.resize(523, 172)
WishlistWidget.resize(202, 94)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(WishlistWidget.sizePolicy().hasHeightForWidth())
WishlistWidget.setSizePolicy(sizePolicy)
WishlistWidget.setWindowTitle("WishlistWIdget")
self.horizontalLayout = QtWidgets.QHBoxLayout(WishlistWidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.widget = QtWidgets.QWidget(WishlistWidget)
self.main_layout = QtWidgets.QHBoxLayout(WishlistWidget)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.setObjectName("main_layout")
self.info_widget = QtWidgets.QWidget(WishlistWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
self.widget.setSizePolicy(sizePolicy)
self.widget.setObjectName("widget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget)
sizePolicy.setHeightForWidth(self.info_widget.sizePolicy().hasHeightForWidth())
self.info_widget.setSizePolicy(sizePolicy)
self.info_widget.setObjectName("info_widget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.info_widget)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.title_label = QtWidgets.QLabel(self.widget)
self.title_label = QtWidgets.QLabel(self.info_widget)
font = QtGui.QFont()
font.setPointSize(16)
self.title_label.setFont(font)
@ -35,16 +41,16 @@ class Ui_WishlistWidget(object):
self.title_label.setWordWrap(True)
self.title_label.setObjectName("title_label")
self.verticalLayout_2.addWidget(self.title_label)
self.developer = QtWidgets.QLabel(self.widget)
self.developer = QtWidgets.QLabel(self.info_widget)
font = QtGui.QFont()
font.setPointSize(12)
self.developer.setFont(font)
self.developer.setText("TextLabel")
self.developer.setObjectName("developer")
self.verticalLayout_2.addWidget(self.developer)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.discount_price = QtWidgets.QLabel(self.widget)
self.price_layout = QtWidgets.QHBoxLayout()
self.price_layout.setObjectName("price_layout")
self.discount_price = QtWidgets.QLabel(self.info_widget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@ -52,15 +58,13 @@ class Ui_WishlistWidget(object):
self.discount_price.setSizePolicy(sizePolicy)
self.discount_price.setText("TextLabel")
self.discount_price.setObjectName("discount_price")
self.horizontalLayout_2.addWidget(self.discount_price)
self.price = QtWidgets.QLabel(self.widget)
self.price_layout.addWidget(self.discount_price)
self.price = QtWidgets.QLabel(self.info_widget)
self.price.setText("TextLabel")
self.price.setObjectName("price")
self.horizontalLayout_2.addWidget(self.price)
self.verticalLayout_2.addLayout(self.horizontalLayout_2)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_2.addItem(spacerItem)
self.horizontalLayout.addWidget(self.widget)
self.price_layout.addWidget(self.price)
self.verticalLayout_2.addLayout(self.price_layout)
self.main_layout.addWidget(self.info_widget, 0, QtCore.Qt.AlignTop)
self.delete_button = QtWidgets.QPushButton(WishlistWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
@ -69,7 +73,7 @@ class Ui_WishlistWidget(object):
self.delete_button.setSizePolicy(sizePolicy)
self.delete_button.setText("")
self.delete_button.setObjectName("delete_button")
self.horizontalLayout.addWidget(self.delete_button)
self.main_layout.addWidget(self.delete_button)
self.retranslateUi(WishlistWidget)

View file

@ -6,16 +6,34 @@
<rect>
<x>0</x>
<y>0</y>
<width>523</width>
<height>172</height>
<width>202</width>
<height>94</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true">WishlistWIdget</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="main_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="info_widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
@ -51,7 +69,7 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="price_layout">
<item>
<widget class="QLabel" name="discount_price">
<property name="sizePolicy">
@ -74,19 +92,6 @@
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>

View file

@ -82,7 +82,7 @@ class ImageLabel(QLabel):
def __init__(self, parent=None):
super(ImageLabel, self).__init__(parent=parent)
self.path = tmp_dir()
self.manager = QtRequestManager("bytes")
self.manager = QtRequestManager()
def update_image(self, url, name="", size: tuple = (240, 320)):
self.setFixedSize(*size)

View file

@ -1,109 +1,144 @@
import json
from dataclasses import dataclass
from dataclasses import dataclass, field
from email.message import Message
from logging import getLogger
from typing import Callable
from typing import Callable, Dict, TypeVar, List, Tuple
from typing import Union
from PyQt5.QtCore import QObject, pyqtSignal, QUrl, QJsonParseError, QJsonDocument
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from PyQt5.QtCore import QObject, pyqtSignal, QUrl, QJsonParseError, QJsonDocument, QUrlQuery, pyqtSlot
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply, QNetworkDiskCache
logger = getLogger("QtRequests")
class QtRequestManager(QObject):
data_ready = pyqtSignal(object)
request = None
request_active = None
def __init__(self, doc_type: str = "json", authorization_token: str = None):
super(QtRequestManager, self).__init__()
self.manager = QNetworkAccessManager()
self.doc_type = doc_type
self.authorization_token = authorization_token
self.request_queue = []
def post(self, url: str, payload: dict, handle_func):
if not self.request_active:
request = QNetworkRequest(QUrl(url))
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
self.request_active = RequestQueueItem(handle_func=handle_func)
payload = json.dumps(payload).encode("utf-8")
request.setHeader(
QNetworkRequest.UserAgentHeader,
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
)
if self.authorization_token is not None:
request.setRawHeader(
b"Authorization", self.authorization_token.encode()
)
self.request = self.manager.post(request, payload)
self.request.finished.connect(self.prepare_data)
else:
self.request_queue.append(
RequestQueueItem(
method="post", url=url, payload=payload, handle_func=handle_func
)
)
def get(self, url: str, handle_func: Callable[[Union[dict, bytes]], None], payload: dict = None):
if not self.request_active:
request = QNetworkRequest(QUrl(url))
request.setHeader(
QNetworkRequest.UserAgentHeader,
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
)
self.request_active = RequestQueueItem(handle_func=handle_func)
self.request = self.manager.get(request)
self.request.finished.connect(self.prepare_data)
else:
self.request_queue.append(
RequestQueueItem(method="get", url=url, handle_func=handle_func, payload=payload)
)
def prepare_data(self):
# self.request_active = False
data = {} if self.doc_type == "json" else b""
if self.request:
try:
if self.request.error() == QNetworkReply.NoError:
if self.doc_type == "json":
error = QJsonParseError()
json_data = QJsonDocument.fromJson(
self.request.readAll().data(), error
)
if QJsonParseError.NoError == error.error:
data = json.loads(json_data.toJson().data().decode())
else:
logger.error(error.errorString())
else:
data = self.request.readAll().data()
except RuntimeError as e:
logger.error(str(e))
self.request_active.handle_func(data)
self.request.deleteLater()
self.request_active = None
if self.request_queue:
if self.request_queue[0].method == "post":
self.post(
self.request_queue[0].url,
self.request_queue[0].payload,
self.request_queue[0].handle_func,
)
else:
self.get(self.request_queue[0].url, self.request_queue[0].handle_func)
self.request_queue.pop(0)
REQUEST_LIMIT = 8
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36"
RequestHandler = TypeVar("RequestHandler", bound=Callable[[Union[Dict, bytes]], None])
@dataclass
class RequestQueueItem:
method: str = None
url: str = None
handle_func: Callable[[Union[dict, bytes]], None] = None
payload: dict = None
url: QUrl = None
payload: Dict = field(default_factory=dict)
params: Dict = field(default_factory=dict)
handlers: List[RequestHandler] = field(default_factory=list)
def __eq__(self, other):
return self.method == other.method and self.url == other.url
class QtRequestManager(QObject):
data_ready = pyqtSignal(object)
def __init__(self, cache: str = None, token: str = None, parent=None):
super(QtRequestManager, self).__init__(parent=parent)
self.manager = QNetworkAccessManager(self)
self.manager.finished.connect(self.__on_finished)
self.manager.finished.connect(self.__process_next)
self.cache = None
if cache is not None:
self.cache = QNetworkDiskCache(self)
self.cache.setCacheDirectory(cache)
self.manager.setCache(self.cache)
self.token = token
self.__pending_requests = []
self.__active_requests = {}
@staticmethod
def __prepare_query(url, params) -> QUrl:
url = QUrl(url)
query = QUrlQuery(url)
for k, v in params.items():
query.addQueryItem(str(k), str(v))
url.setQuery(query)
return url
def __prepare_request(self, item: RequestQueueItem) -> QNetworkRequest:
request = QNetworkRequest(item.url)
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json;charset=UTF-8")
request.setHeader(QNetworkRequest.UserAgentHeader, USER_AGENT)
request.setAttribute(QNetworkRequest.RedirectPolicyAttribute, QNetworkRequest.NoLessSafeRedirectPolicy)
if self.cache is not None:
request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.PreferCache)
if self.token is not None:
request.setRawHeader(b"Authorization", self.token.encode())
return request
def __post(self, item: RequestQueueItem):
request = self.__prepare_request(item)
payload = json.dumps(item.payload).encode("utf-8")
reply = self.manager.post(request, payload)
reply.errorOccurred.connect(self.__on_error)
self.__active_requests[reply] = item
def post(self, url: str, handler: RequestHandler, payload: dict):
item = RequestQueueItem(method="post", url=QUrl(url), payload=payload, handlers=[handler])
if len(self.__active_requests) < REQUEST_LIMIT:
self.__post(item)
else:
self.__pending_requests.append(item)
def __get(self, item: RequestQueueItem):
request = self.__prepare_request(item)
reply = self.manager.get(request)
reply.errorOccurred.connect(self.__on_error)
self.__active_requests[reply] = item
def get(self, url: str, handler: RequestHandler, payload: Dict = None, params: Dict = None):
url = self.__prepare_query(url, params) if params is not None else QUrl(url)
item = RequestQueueItem(method="get", url=url, payload=payload, handlers=[handler])
if len(self.__active_requests) < REQUEST_LIMIT:
self.__get(item)
else:
self.__pending_requests.append(item)
@staticmethod
def __on_error(error: QNetworkReply.NetworkError) -> None:
logger.error(error)
@staticmethod
def __parse_content_type(header) -> Tuple[str, str]:
# lk: this looks weird but `cgi` is deprecated, PEP 594 suggests this way of parsing MIME
m = Message()
m['content-type'] = header
return m.get_content_type(), m.get_content_charset()
def __process_next(self):
if self.__pending_requests:
item = self.__pending_requests.pop(0)
if item.method == "post":
self.__post(item)
elif item.method == "get":
self.__get(item)
else:
raise NotImplementedError
@pyqtSlot(QNetworkReply)
def __on_finished(self, reply: QNetworkReply):
item = self.__active_requests.pop(reply, None)
if item is None:
logger.error("QNetworkReply: {} without associated item", reply)
reply.deleteLater()
return
if reply.error():
logger.error(reply.errorString())
else:
mimetype, charset = self.__parse_content_type(reply.header(QNetworkRequest.ContentTypeHeader))
maintype, subtype = mimetype.split("/")
bin_data = reply.readAll().data()
if mimetype == "application/json":
error = QJsonParseError()
json_data = QJsonDocument.fromJson(bin_data, error)
if not error.error:
data = json.loads(json_data.toJson().data().decode())
else:
logger.error(error.errorString())
data = None
elif maintype == "image":
data = bin_data
else:
data = None
for handler in item.handlers:
handler(data)
reply.deleteLater()