From 9ec349e2d1608fcfc63b6f1a2cdbf864e4f7d50d Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Mon, 12 Feb 2024 18:29:39 +0200
Subject: [PATCH] WIP
---
rare/components/tabs/store/__init__.py | 11 +-
.../tabs/store/api/graphql/schema.graphql | 4 +-
.../tabs/store/api/models/diesel.py | 12 +-
.../tabs/store/api/models/response.py | 225 +++++++++++-------
.../components/tabs/store/api/models/utils.py | 2 +-
rare/components/tabs/store/landing.py | 93 +++-----
rare/components/tabs/store/search.py | 20 +-
rare/components/tabs/store/store_api.py | 16 +-
rare/components/tabs/store/widgets/details.py | 83 +++----
rare/components/tabs/store/widgets/items.py | 24 +-
rare/components/tabs/store/wishlist.py | 4 +-
rare/ui/components/tabs/store/details.py | 8 +-
rare/ui/components/tabs/store/details.ui | 49 ++--
rare/utils/qt_requests.py | 2 +-
14 files changed, 270 insertions(+), 283 deletions(-)
diff --git a/rare/components/tabs/store/__init__.py b/rare/components/tabs/store/__init__.py
index 273d2293..c011ae45 100644
--- a/rare/components/tabs/store/__init__.py
+++ b/rare/components/tabs/store/__init__.py
@@ -28,21 +28,15 @@ class StoreTab(SideTabWidget):
self.landing = LandingPage(self.api, parent=self)
self.landing_index = self.addTab(self.landing, self.tr("Store"))
- self.search = SearchPage(self.core, self.api, parent=self)
+ self.search = SearchPage(self.api, parent=self)
self.search_index = self.addTab(self.search, self.tr("Search"))
self.wishlist = WishlistPage(self.api, parent=self)
self.wishlist_index = self.addTab(self.wishlist, self.tr("Wishlist"))
- self.api.update_wishlist.connect(self.update_wishlist)
-
- self.previous_index = self.landing_index
-
def showEvent(self, a0: QShowEvent) -> None:
if a0.spontaneous() or self.init:
return super().showEvent(a0)
- # self.landing.load()
- # self.wishlist.update_wishlist()
self.init = True
return super().showEvent(a0)
@@ -51,6 +45,3 @@ class StoreTab(SideTabWidget):
return super().hideEvent(a0)
# TODO: Implement store unloading
return super().hideEvent(a0)
-
- def update_wishlist(self):
- self.landing.update_wishlist()
diff --git a/rare/components/tabs/store/api/graphql/schema.graphql b/rare/components/tabs/store/api/graphql/schema.graphql
index 676fcfe5..6ccfe7a7 100644
--- a/rare/components/tabs/store/api/graphql/schema.graphql
+++ b/rare/components/tabs/store/api/graphql/schema.graphql
@@ -25,14 +25,14 @@ type DiscountSetting {
discountType: String
}
-type AppliedRuled {
+type AppliedRules {
id: ID
endDate: Date
discountSetting: DiscountSetting
}
type LineOfferRes {
- appliedRules: [AppliedRuled]
+ appliedRules: [AppliedRules]
}
type GetPriceRes {
diff --git a/rare/components/tabs/store/api/models/diesel.py b/rare/components/tabs/store/api/models/diesel.py
index b9629343..437c8b8c 100644
--- a/rare/components/tabs/store/api/models/diesel.py
+++ b/rare/components/tabs/store/api/models/diesel.py
@@ -33,7 +33,7 @@ class DieselSystemDetailItem:
class DieselSystemDetail:
p_type: Optional[str] = None
details: Optional[List[DieselSystemDetailItem]] = None
- system_type: Optional[str] = None
+ systemType: Optional[str] = None
unmapped: Dict[str, Any] = field(default_factory=dict)
@classmethod
@@ -47,7 +47,7 @@ class DieselSystemDetail:
tmp = cls(
p_type=d.pop("_type", ""),
details=details,
- system_type=d.pop("systemType", ""),
+ systemType=d.pop("systemType", ""),
)
tmp.unmapped = d
return tmp
@@ -107,7 +107,7 @@ class DieselProductDetail:
p_type: Optional[str] = None
about: Optional[DieselProductAbout] = None
requirements: Optional[DieselSystemDetails] = None
- social_links: Optional[DieselSocialLinks] = None
+ socialLinks: Optional[DieselSocialLinks] = None
unmapped: Dict[str, Any] = field(default_factory=dict)
@classmethod
@@ -119,7 +119,7 @@ class DieselProductDetail:
p_type=d.pop("_type", ""),
about=about,
requirements=requirements,
- social_links=d.pop("socialLinks", {}),
+ socialLinks=d.pop("socialLinks", {}),
)
tmp.unmapped = d
return tmp
@@ -136,7 +136,7 @@ class DieselProduct:
namespace: Optional[str] = None
pages: Optional[List["DieselProduct"]] = None
data: Optional[DieselProductDetail] = None
- product_name: Optional[str] = None
+ productName: Optional[str] = None
unmapped: Dict[str, Any] = field(default_factory=dict)
@classmethod
@@ -158,7 +158,7 @@ class DieselProduct:
namespace=d.pop("namespace", ""),
pages=pages,
data=data,
- product_name=d.pop("productName", ""),
+ productName=d.pop("productName", ""),
)
tmp.unmapped = d
return tmp
diff --git a/rare/components/tabs/store/api/models/response.py b/rare/components/tabs/store/api/models/response.py
index 6a7672f2..23332d51 100644
--- a/rare/components/tabs/store/api/models/response.py
+++ b/rare/components/tabs/store/api/models/response.py
@@ -1,7 +1,7 @@
import logging
from dataclasses import dataclass, field
from datetime import datetime
-from typing import List, Dict, Any, Type, Optional
+from typing import List, Dict, Any, Type, Optional, Tuple
from .utils import parse_date
@@ -17,7 +17,6 @@ ItemModel = Dict
SellerModel = Dict
PageSandboxModel = Dict
TagModel = Dict
-PromotionsModel = Dict
@dataclass
@@ -39,16 +38,15 @@ class ImageUrlModel:
d = src.copy()
type = d.pop("type", None)
url = d.pop("url", None)
- tmp = cls(
- type=type,
- url=url,
- )
+ tmp = cls(type=type, url=url)
return tmp
@dataclass
class KeyImagesModel:
key_images: Optional[List[ImageUrlModel]] = None
+ tall_types = ("DieselStoreFrontTall", "OfferImageTall", "Thumbnail", "ProductLogo", "DieselGameBoxLogo")
+ wide_types = ("DieselStoreFrontWide", "OfferImageWide", "VaultClosed", "ProductLogo")
def __getitem__(self, item):
return self.key_images[item]
@@ -76,21 +74,13 @@ class KeyImagesModel:
return tmp
def available_tall(self) -> List[ImageUrlModel]:
- tall_types = [
- "DieselStoreFrontTall",
- "OfferImageTall",
- "Thumbnail",
- "ProductLogo",
- "DieselGameBoxLogo",
- ]
- tall_images = filter(lambda img: img.type in tall_types, self.key_images)
- tall_images = sorted(tall_images, key=lambda x: tall_types.index(x.type))
+ tall_images = filter(lambda img: img.type in KeyImagesModel.tall_types, self.key_images)
+ tall_images = sorted(tall_images, key=lambda x: KeyImagesModel.tall_types.index(x.type))
return tall_images
def available_wide(self) -> List[ImageUrlModel]:
- wide_types = ["DieselStoreFrontWide", "OfferImageWide", "VaultClosed", "ProductLogo"]
- wide_images = filter(lambda img: img.type in wide_types, self.key_images)
- wide_images = sorted(wide_images, key=lambda x: wide_types.index(x.type))
+ wide_images = filter(lambda img: img.type in KeyImagesModel.wide_types, self.key_images)
+ wide_images = sorted(wide_images, key=lambda x: KeyImagesModel.wide_types.index(x.type))
return wide_images
def for_dimensions(self, w: int, h: int) -> ImageUrlModel:
@@ -107,55 +97,133 @@ class KeyImagesModel:
return model
-TotalPriceModel = Dict
-FmtPriceModel = Dict
+CurrencyModel = Dict
+FormattedPriceModel = Dict
LineOffersModel = Dict
@dataclass
-class GetPriceResModel:
- total_price: Optional[TotalPriceModel] = None
- fmt_price: Optional[FmtPriceModel] = None
- line_offers: Optional[LineOffersModel] = None
+class TotalPriceModel:
+ discountPrice: Optional[int] = None
+ originalPrice: Optional[int] = None
+ voucherDiscount: Optional[int] = None
+ discount: Optional[int] = None
+ currencyCode: Optional[str] = None
+ currencyInfo: Optional[CurrencyModel] = None
+ fmtPrice: Optional[FormattedPriceModel] = None
unmapped: Dict[str, Any] = field(default_factory=dict)
@classmethod
- def from_dict(cls: Type["GetPriceResModel"], src: Dict[str, Any]) -> "GetPriceResModel":
+ def from_dict(cls: Type["TotalPriceModel"], src: Dict[str, Any]) -> "TotalPriceModel":
d = src.copy()
tmp = cls(
- total_price=d.pop("totalPrice", {}),
- fmt_price=d.pop("fmtPrice", {}),
- line_offers=d.pop("lineOffers", {}),
+ discountPrice=d.pop("discountPrice", None),
+ originalPrice=d.pop("originalPrice", None),
+ voucherDiscount=d.pop("voucherDiscount", None),
+ discount=d.pop("discount", None),
+ currencyCode=d.pop("currencyCode", None),
+ currencyInfo=d.pop("currrencyInfo", {}),
+ fmtPrice=d.pop("fmtPrice", {}),
)
tmp.unmapped = d
return tmp
+@dataclass
+class GetPriceResModel:
+ totalPrice: Optional[TotalPriceModel] = None
+ lineOffers: Optional[LineOffersModel] = None
+ unmapped: Dict[str, Any] = field(default_factory=dict)
+
+ @classmethod
+ def from_dict(cls: Type["GetPriceResModel"], src: Dict[str, Any]) -> "GetPriceResModel":
+ d = src.copy()
+ total_price = TotalPriceModel.from_dict(x) if (x := d.pop("totalPrice", {})) else None
+ tmp = cls(totalPrice=total_price, lineOffers=d.pop("lineOffers", {}))
+ tmp.unmapped = d
+ return tmp
+
+
+DiscountSettingModel = Dict
+
+
+@dataclass
+class PromotionalOfferModel:
+ startDate: Optional[datetime] = None
+ endDate: Optional[datetime] = None
+ discountSetting: Optional[DiscountSettingModel] = None
+
+ @classmethod
+ def from_dict(cls: Type["PromotionalOfferModel"], src: Dict[str, Any]) -> "PromotionalOfferModel":
+ d = src.copy()
+ start_date = parse_date(x) if (x := d.pop("startDate", "")) else None
+ end_date = parse_date(x) if (x := d.pop("endDate", "")) else None
+ tmp = cls(startDate=start_date, endDate=end_date, discountSetting=d.pop("discountSetting", {}))
+ tmp.unmapped = d
+ return tmp
+
+
+@dataclass
+class PromotionalOffersModel:
+ promotionalOffers: Optional[Tuple[PromotionalOfferModel]] = None
+
+ @classmethod
+ def from_list(cls: Type["PromotionalOffersModel"], src: Dict[str, List]) -> "PromotionalOffersModel":
+ d = src.copy()
+ promotional_offers = (
+ tuple([PromotionalOfferModel.from_dict(y) for y in x]) if (x := d.pop("promotionalOffers", [])) else None
+ )
+ tmp = cls(promotionalOffers=promotional_offers)
+ tmp.unmapped = d
+ return tmp
+
+
+@dataclass
+class PromotionsModel:
+ promotionalOffers: Optional[Tuple[PromotionalOffersModel]] = None
+ upcomingPromotionalOffers: Optional[Tuple[PromotionalOffersModel]] = None
+
+ @classmethod
+ def from_dict(cls: Type["PromotionsModel"], src: Dict[str, Any]) -> "PromotionsModel":
+ d = src.copy()
+ promotional_offers = (
+ tuple([PromotionalOffersModel.from_list(y) for y in x]) if (x := d.pop("promotionalOffers", [])) else None
+ )
+ upcoming_promotional_offers = (
+ tuple([PromotionalOffersModel.from_list(y) for y in x])
+ if (x := d.pop("upcomingPromotionalOffers", []))
+ else None
+ )
+ tmp = cls(promotionalOffers=promotional_offers, upcomingPromotionalOffers=upcoming_promotional_offers)
+ tmp.unmapped = d
+ return tmp
+
+
@dataclass
class CatalogOfferModel:
- catalog_ns: Optional[CatalogNamespaceModel] = None
+ catalogNs: Optional[CatalogNamespaceModel] = None
categories: Optional[List[CategoryModel]] = None
- custom_attributes: Optional[List[CustomAttributeModel]] = None
+ customAttributes: Optional[List[CustomAttributeModel]] = None
description: Optional[str] = None
- effective_date: Optional[datetime] = None
- expiry_date: Optional[datetime] = None
+ effectiveDate: Optional[datetime] = None
+ expiryDate: Optional[datetime] = None
id: Optional[str] = None
- is_code_redemption_only: Optional[bool] = None
+ isCodeRedemptionOnly: Optional[bool] = None
items: Optional[List[ItemModel]] = None
- key_images: Optional[KeyImagesModel] = None
+ keyImages: Optional[KeyImagesModel] = None
namespace: Optional[str] = None
- offer_mappings: Optional[List[PageSandboxModel]] = None
- offer_type: Optional[str] = None
+ offerMappings: Optional[List[PageSandboxModel]] = None
+ offerType: Optional[str] = None
price: Optional[GetPriceResModel] = None
- product_slug: Optional[str] = None
+ productSlug: Optional[str] = None
promotions: Optional[PromotionsModel] = None
seller: Optional[SellerModel] = None
status: Optional[str] = None
tags: Optional[List[TagModel]] = None
title: Optional[str] = None
url: Optional[str] = None
- url_slug: Optional[str] = None
- viewable_date: Optional[datetime] = None
+ urlSlug: Optional[str] = None
+ viewableDate: Optional[datetime] = None
unmapped: Dict[str, Any] = field(default_factory=dict)
@classmethod
@@ -165,31 +233,32 @@ class CatalogOfferModel:
expiry_date = parse_date(x) if (x := d.pop("expiryDate", "")) else None
key_images = KeyImagesModel.from_list(d.pop("keyImages", []))
price = GetPriceResModel.from_dict(x) if (x := d.pop("price", {})) else None
+ promotions = PromotionsModel.from_dict(x) if (x := d.pop("promotions", {})) else None
viewable_date = parse_date(x) if (x := d.pop("viewableDate", "")) else None
tmp = cls(
- catalog_ns=d.pop("catalogNs", {}),
+ catalogNs=d.pop("catalogNs", {}),
categories=d.pop("categories", []),
- custom_attributes=d.pop("customAttributes", []),
+ customAttributes=d.pop("customAttributes", []),
description=d.pop("description", ""),
- effective_date=effective_date,
- expiry_date=expiry_date,
+ effectiveDate=effective_date,
+ expiryDate=expiry_date,
id=d.pop("id", ""),
- is_code_redemption_only=d.pop("isCodeRedemptionOnly", None),
+ isCodeRedemptionOnly=d.pop("isCodeRedemptionOnly", None),
items=d.pop("items", []),
- key_images=key_images,
+ keyImages=key_images,
namespace=d.pop("namespace", ""),
- offer_mappings=d.pop("offerMappings", []),
- offer_type=d.pop("offerType", ""),
+ offerMappings=d.pop("offerMappings", []),
+ offerType=d.pop("offerType", ""),
price=price,
- product_slug=d.pop("productSlug", ""),
- promotions=d.pop("promotions", {}),
+ productSlug=d.pop("productSlug", ""),
+ promotions=promotions,
seller=d.pop("seller", {}),
status=d.pop("status", ""),
tags=d.pop("tags", []),
title=d.pop("title", ""),
url=d.pop("url", ""),
- url_slug=d.pop("urlSlug", ""),
- viewable_date=viewable_date,
+ urlSlug=d.pop("urlSlug", ""),
+ viewableDate=viewable_date,
)
tmp.unmapped = d
return tmp
@@ -200,8 +269,8 @@ class WishlistItemModel:
created: Optional[datetime] = None
id: Optional[str] = None
namespace: Optional[str] = None
- is_first_time: Optional[bool] = None
- offer_id: Optional[str] = None
+ isFirstTime: Optional[bool] = None
+ offerId: Optional[str] = None
order: Optional[Any] = None
updated: Optional[datetime] = None
offer: Optional[CatalogOfferModel] = None
@@ -217,8 +286,8 @@ class WishlistItemModel:
created=created,
id=d.pop("id", ""),
namespace=d.pop("namespace", ""),
- is_first_time=d.pop("isFirstTime", None),
- offer_id=d.pop("offerId", ""),
+ isFirstTime=d.pop("isFirstTime", None),
+ offerId=d.pop("offerId", ""),
order=d.pop("order", ""),
updated=updated,
offer=offer,
@@ -238,10 +307,7 @@ class PagingModel:
d = src.copy()
count = d.pop("count", None)
total = d.pop("total", None)
- tmp = cls(
- count=count,
- total=total,
- )
+ tmp = cls(count=count, total=total)
tmp.unmapped = d
return tmp
@@ -261,26 +327,21 @@ class SearchStoreModel:
elem = CatalogOfferModel.from_dict(item)
elements.append(elem)
paging = PagingModel.from_dict(x) if (x := d.pop("paging", {})) else None
- tmp = cls(
- elements=elements,
- paging=paging,
- )
+ tmp = cls(elements=elements, paging=paging)
tmp.unmapped = d
return tmp
@dataclass
class CatalogModel:
- search_store: Optional[SearchStoreModel] = None
+ searchStore: Optional[SearchStoreModel] = None
unmapped: Dict[str, Any] = field(default_factory=dict)
@classmethod
def from_dict(cls: Type["CatalogModel"], src: Dict[str, Any]) -> "CatalogModel":
d = src.copy()
search_store = SearchStoreModel.from_dict(x) if (x := d.pop("searchStore", {})) else None
- tmp = cls(
- search_store=search_store,
- )
+ tmp = cls(searchStore=search_store)
tmp.unmapped = d
return tmp
@@ -300,10 +361,7 @@ class WishlistItemsModel:
elem = WishlistItemModel.from_dict(item)
elements.append(elem)
paging = PagingModel.from_dict(x) if (x := d.pop("paging", {})) else None
- tmp = cls(
- elements=elements,
- paging=paging,
- )
+ tmp = cls(elements=elements, paging=paging)
tmp.unmapped = d
return tmp
@@ -316,16 +374,14 @@ class RemoveFromWishlistModel:
@classmethod
def from_dict(cls: Type["RemoveFromWishlistModel"], src: Dict[str, Any]) -> "RemoveFromWishlistModel":
d = src.copy()
- tmp = cls(
- success=d.pop("success", None),
- )
+ tmp = cls(success=d.pop("success", None))
tmp.unmapped = d
return tmp
@dataclass
class AddToWishlistModel:
- wishlist_item: Optional[WishlistItemModel] = None
+ wishlistItem: Optional[WishlistItemModel] = None
success: Optional[bool] = None
unmapped: Dict[str, Any] = field(default_factory=dict)
@@ -333,33 +389,26 @@ class AddToWishlistModel:
def from_dict(cls: Type["AddToWishlistModel"], src: Dict[str, Any]) -> "AddToWishlistModel":
d = src.copy()
wishlist_item = WishlistItemModel.from_dict(x) if (x := d.pop("wishlistItem", {})) else None
- tmp = cls(
- wishlist_item=wishlist_item,
- success=d.pop("success", None),
- )
+ tmp = cls(wishlistItem=wishlist_item, success=d.pop("success", None))
tmp.unmapped = d
return tmp
@dataclass
class WishlistModel:
- wishlist_items: Optional[WishlistItemsModel] = None
- remove_from_wishlist: Optional[RemoveFromWishlistModel] = None
- add_to_wishlist: Optional[AddToWishlistModel] = None
+ wishlistItems: Optional[WishlistItemsModel] = None
+ removeFromWishlist: Optional[RemoveFromWishlistModel] = None
+ addToWishlist: Optional[AddToWishlistModel] = None
unmapped: Dict[str, Any] = field(default_factory=dict)
@classmethod
def from_dict(cls: Type["WishlistModel"], src: Dict[str, Any]) -> "WishlistModel":
d = src.copy()
wishlist_items = WishlistItemsModel.from_dict(x) if (x := d.pop("wishlistItems", {})) else None
- remove_from_wishlist = (
- RemoveFromWishlistModel.from_dict(x) if (x := d.pop("removeFromWishlist", {})) else None
- )
+ remove_from_wishlist = RemoveFromWishlistModel.from_dict(x) if (x := d.pop("removeFromWishlist", {})) else None
add_to_wishlist = AddToWishlistModel.from_dict(x) if (x := d.pop("addToWishlist", {})) else None
tmp = cls(
- wishlist_items=wishlist_items,
- remove_from_wishlist=remove_from_wishlist,
- add_to_wishlist=add_to_wishlist,
+ wishlistItems=wishlist_items, removeFromWishlist=remove_from_wishlist, addToWishlist=add_to_wishlist
)
tmp.unmapped = d
return tmp
diff --git a/rare/components/tabs/store/api/models/utils.py b/rare/components/tabs/store/api/models/utils.py
index 92c6ebf2..06f79c67 100644
--- a/rare/components/tabs/store/api/models/utils.py
+++ b/rare/components/tabs/store/api/models/utils.py
@@ -2,4 +2,4 @@ from datetime import datetime, timezone
def parse_date(date: str):
- return datetime.fromisoformat(date[:-1]).replace(tzinfo=timezone.utc)
\ No newline at end of file
+ return datetime.fromisoformat(date[:-1]).replace(tzinfo=timezone.utc)
diff --git a/rare/components/tabs/store/landing.py b/rare/components/tabs/store/landing.py
index a55e5124..a8582697 100644
--- a/rare/components/tabs/store/landing.py
+++ b/rare/components/tabs/store/landing.py
@@ -14,26 +14,25 @@ from PyQt5.QtWidgets import (
QFrame,
)
+from rare.components.tabs.store.api.models.response import CatalogOfferModel, WishlistItemModel
from rare.widgets.flow_layout import FlowLayout
from rare.widgets.side_tab import SideTabContents
from rare.widgets.sliding_stack import SlidingStackedWidget
-from rare.components.tabs.store.api.models.response import CatalogOfferModel, WishlistItemModel
-from .api.models.utils import parse_date
from .store_api import StoreAPI
from .widgets.details import DetailsWidget
-from .widgets.items import StoreItemWidget
from .widgets.groups import StoreGroup
+from .widgets.items import StoreItemWidget
logger = logging.getLogger("StoreLanding")
class LandingPage(SlidingStackedWidget, SideTabContents):
- def __init__(self, api: StoreAPI, parent=None):
+ def __init__(self, store_api: StoreAPI, parent=None):
super(LandingPage, self).__init__(parent=parent)
self.implements_scrollarea = True
- self.landing_widget = LandingWidget(api, parent=self)
+ self.landing_widget = LandingWidget(store_api, parent=self)
self.landing_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.landing_widget.set_title.connect(self.set_title)
self.landing_widget.show_details.connect(self.show_details)
@@ -43,7 +42,7 @@ class LandingPage(SlidingStackedWidget, SideTabContents):
self.landing_scroll.setFrameStyle(QFrame.NoFrame | QFrame.Plain)
self.landing_scroll.setWidget(self.landing_widget)
- self.details_widget = DetailsWidget([], api, parent=self)
+ self.details_widget = DetailsWidget([], store_api, parent=self)
self.details_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.details_widget.set_title.connect(self.set_title)
self.details_widget.back_clicked.connect(self.show_main)
@@ -83,7 +82,7 @@ class LandingWidget(QWidget, SideTabContents):
self.discounts_group = StoreGroup(self.tr("Wishlist discounts"), layout=FlowLayout, parent=self)
self.discounts_group.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
- self.games_group = StoreGroup(self.tr("Games"), FlowLayout, self)
+ self.games_group = StoreGroup(self.tr("Free to play"), FlowLayout, self)
self.games_group.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.games_group.loading(False)
self.games_group.setVisible(True)
@@ -97,8 +96,8 @@ class LandingWidget(QWidget, SideTabContents):
def showEvent(self, a0: QShowEvent) -> None:
if a0.spontaneous():
return super().showEvent(a0)
- self.api.get_free_games(self.__add_free)
- self.api.get_wishlist(self.__add_discounts)
+ self.api.get_free(self.__update_free_games)
+ self.api.get_wishlist(self.__update_wishlist_discounts)
return super().showEvent(a0)
def hideEvent(self, a0: QHideEvent) -> None:
@@ -107,28 +106,20 @@ class LandingWidget(QWidget, SideTabContents):
# TODO: Implement tab unloading
return super().hideEvent(a0)
- def __add_discounts(self, wishlist: List[WishlistItemModel]):
+ def __update_wishlist_discounts(self, wishlist: List[WishlistItemModel]):
for w in self.discounts_group.findChildren(StoreItemWidget, options=Qt.FindDirectChildrenOnly):
self.discounts_group.layout().removeWidget(w)
w.deleteLater()
- discounts = 0
- for game in wishlist:
- if not game:
- continue
- try:
- if game.offer.price.total_price["discount"] > 0:
- w = StoreItemWidget(self.api.cached_manager, game.offer)
- w.show_details.connect(self.show_details)
- self.discounts_group.layout().addWidget(w)
- discounts += 1
- except Exception as e:
- logger.warning(f"{game} {e}")
- continue
- # self.discounts_group.setVisible(discounts > 0)
+ for item in wishlist:
+ if item.offer.price.totalPrice.discount > 0:
+ w = StoreItemWidget(self.api.cached_manager, item.offer)
+ w.show_details.connect(self.show_details)
+ self.discounts_group.layout().addWidget(w)
+ self.discounts_group.setVisible(bool(wishlist))
self.discounts_group.loading(False)
- def __add_free(self, free_games: List[CatalogOfferModel]):
+ def __update_free_games(self, free_games: List[CatalogOfferModel]):
for w in self.free_games_now.findChildren(StoreItemWidget, options=Qt.FindDirectChildrenOnly):
self.free_games_now.layout().removeWidget(w)
w.deleteLater()
@@ -140,56 +131,38 @@ class LandingWidget(QWidget, SideTabContents):
date = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc)
free_now = []
free_next = []
- for game in free_games:
+ for item in free_games:
try:
- if (
- game.price.total_price["fmtPrice"]["discountPrice"] == "0"
- and game.price.total_price["fmtPrice"]["originalPrice"]
- != game.price.total_price["fmtPrice"]["discountPrice"]
- ):
- free_now.append(game)
+ if item.price.totalPrice.discountPrice == 0:
+ free_now.append(item)
continue
-
- if game.title == "Mystery Game":
- free_next.append(game)
+ if item.title == "Mystery Game":
+ free_next.append(item)
continue
except KeyError as e:
logger.warning(str(e))
- try:
- # parse datetime to check if game is next week or now
- try:
- start_date = parse_date(
- game.promotions["upcomingPromotionalOffers"][0]["promotionalOffers"][0]["startDate"]
- )
- except Exception:
- try:
- start_date = parse_date(
- game.promotions["promotionalOffers"][0]["promotionalOffers"][0]["startDate"]
- )
- except Exception as e:
- continue
-
- except TypeError:
- print("type error")
- continue
+ if not item.promotions.promotionalOffers:
+ start_date = item.promotions.upcomingPromotionalOffers[0].promotionalOffers[0].startDate
+ else:
+ start_date = item.promotions.promotionalOffers[0].promotionalOffers[0].startDate
if start_date > date:
- free_next.append(game)
+ free_next.append(item)
# free games now
- self.free_games_now.setVisible(bool(len(free_now)))
- for game in free_now:
- w = StoreItemWidget(self.api.cached_manager, game)
+ self.free_games_now.setVisible(bool(free_now))
+ for item in free_now:
+ w = StoreItemWidget(self.api.cached_manager, item)
w.show_details.connect(self.show_details)
self.free_games_now.layout().addWidget(w)
self.free_games_now.loading(False)
# free games next week
- self.free_games_next.setVisible(bool(len(free_next)))
- for game in free_next:
- w = StoreItemWidget(self.api.cached_manager, game)
- if game.title != "Mystery Game":
+ self.free_games_next.setVisible(bool(free_next))
+ for item in free_next:
+ w = StoreItemWidget(self.api.cached_manager, item)
+ if item.title != "Mystery Game":
w.show_details.connect(self.show_details)
self.free_games_next.layout().addWidget(w)
self.free_games_next.loading(False)
diff --git a/rare/components/tabs/store/search.py b/rare/components/tabs/store/search.py
index 7e5d6d8d..56456b30 100644
--- a/rare/components/tabs/store/search.py
+++ b/rare/components/tabs/store/search.py
@@ -26,16 +26,16 @@ logger = logging.getLogger("Shop")
class SearchPage(SlidingStackedWidget, SideTabContents):
- def __init__(self, core, api: StoreAPI, parent=None):
+ def __init__(self, store_api: StoreAPI, parent=None):
super(SearchPage, self).__init__(parent=parent)
self.implements_scrollarea = True
- self.search_widget = SearchWidget(core, api, parent=self)
+ self.search_widget = SearchWidget(store_api, parent=self)
self.search_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.search_widget.set_title.connect(self.set_title)
self.search_widget.show_details.connect(self.show_details)
- self.details_widget = DetailsWidget([], api, parent=self)
+ self.details_widget = DetailsWidget([], store_api, parent=self)
self.details_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.details_widget.set_title.connect(self.set_title)
self.details_widget.back_clicked.connect(self.show_main)
@@ -58,27 +58,25 @@ class SearchPage(SlidingStackedWidget, SideTabContents):
class SearchWidget(QWidget, SideTabContents):
show_details = pyqtSignal(CatalogOfferModel)
- def __init__(self, core: LegendaryCore, api: StoreAPI, parent=None):
+ def __init__(self, store_api: StoreAPI, parent=None):
super(SearchWidget, self).__init__(parent=parent)
self.implements_scrollarea = True
self.ui = Ui_SearchWidget()
self.ui.setupUi(self)
self.ui.main_layout.setContentsMargins(0, 0, 3, 0)
- self.core = core
- self.api_core = api
+ self.store_api = store_api
self.price = ""
self.tags = []
self.types = []
self.update_games_allowed = True
- self.free_game_widgets = []
self.active_search_request = False
self.next_search = ""
self.wishlist: List = []
self.search_bar = ButtonLineEdit("fa.search", placeholder_text=self.tr("Search Games"))
- self.results_scrollarea = ResultsWidget(self.api_core, self)
+ self.results_scrollarea = ResultsWidget(self.store_api, self)
self.results_scrollarea.show_details.connect(self.show_details)
self.ui.left_layout.addWidget(self.search_bar)
@@ -188,8 +186,8 @@ class SearchWidget(QWidget, SideTabContents):
self.games_group.loading(True)
browse_model = SearchStoreQuery(
- language=self.core.language_code,
- country=self.core.country_code,
+ language=self.store_api.language_code,
+ country=self.store_api.country_code,
count=20,
price_range=self.price,
on_sale=self.ui.on_discount.isChecked(),
@@ -198,7 +196,7 @@ class SearchWidget(QWidget, SideTabContents):
if self.types:
browse_model.category = "|".join(self.types)
- self.api_core.browse_games(browse_model, self.show_games)
+ self.store_api.browse_games(browse_model, self.show_games)
class CheckBox(QCheckBox):
diff --git a/rare/components/tabs/store/store_api.py b/rare/components/tabs/store/store_api.py
index 90ac2b7e..0f45d8e8 100644
--- a/rare/components/tabs/store/store_api.py
+++ b/rare/components/tabs/store/store_api.py
@@ -20,7 +20,7 @@ from .api.models.response import (
CatalogOfferModel,
)
-logger = getLogger("ShopAPICore")
+logger = getLogger("StoreAPI")
graphql_url = "https://graphql.epicgames.com/graphql"
@@ -46,7 +46,7 @@ class StoreAPI(QObject):
self.browse_active = False
self.next_browse_request = tuple(())
- def get_free_games(self, handle_func: callable):
+ def get_free(self, handle_func: callable):
url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions"
params = {
"locale": self.locale,
@@ -59,7 +59,7 @@ class StoreAPI(QObject):
def __handle_free_games(data, handle_func):
try:
response = ResponseModel.from_dict(data)
- results: List[CatalogOfferModel] = response.data.catalog.search_store.elements
+ results: List[CatalogOfferModel] = response.data.catalog.searchStore.elements
handle_func(results)
except KeyError as e:
if DEBUG():
@@ -94,7 +94,7 @@ class StoreAPI(QObject):
response = ResponseModel.from_dict(data)
if response.errors:
logger.error(response.errors)
- handle_func(response.data.wishlist.wishlist_items.elements)
+ handle_func(response.data.wishlist.wishlistItems.elements)
except KeyError as e:
if DEBUG():
raise e
@@ -132,7 +132,7 @@ class StoreAPI(QObject):
def __handle_search(data, handler):
try:
response = ResponseModel.from_dict(data)
- handler(response.data.catalog.search_store.elements)
+ handler(response.data.catalog.searchStore.elements)
except KeyError as e:
logger.error(str(e))
if DEBUG():
@@ -167,7 +167,7 @@ class StoreAPI(QObject):
if not self.next_browse_request:
try:
response = ResponseModel.from_dict(data)
- handle_func(response.data.catalog.search_store.elements)
+ handle_func(response.data.catalog.searchStore.elements)
except KeyError as e:
if DEBUG():
raise e
@@ -233,7 +233,7 @@ class StoreAPI(QObject):
# debug.exec()
try:
response = ResponseModel.from_dict(data)
- data = response.data.wishlist.add_to_wishlist
+ data = response.data.wishlist.addToWishlist
handle_func(data.success)
except Exception as e:
if DEBUG():
@@ -259,7 +259,7 @@ class StoreAPI(QObject):
# debug.exec()
try:
response = ResponseModel.from_dict(data)
- data = response.data.wishlist.remove_from_wishlist
+ data = response.data.wishlist.removeFromWishlist
handle_func(data.success)
except Exception as e:
if DEBUG():
diff --git a/rare/components/tabs/store/widgets/details.py b/rare/components/tabs/store/widgets/details.py
index 98f8eaf0..e0386bc7 100644
--- a/rare/components/tabs/store/widgets/details.py
+++ b/rare/components/tabs/store/widgets/details.py
@@ -1,5 +1,5 @@
import logging
-from typing import List
+from typing import List, Dict
from PyQt5.QtCore import Qt, QUrl, pyqtSignal
from PyQt5.QtGui import QFont, QDesktopServices, QKeyEvent
@@ -14,6 +14,7 @@ from PyQt5.QtWidgets import (
from rare.components.tabs.store.api.debug import DebugDialog
from rare.components.tabs.store.api.models.diesel import DieselProduct, DieselProductDetail, DieselSystemDetail
from rare.components.tabs.store.api.models.response import CatalogOfferModel
+from rare.components.tabs.store.store_api import StoreAPI
from rare.models.image import ImageSize
from rare.ui.components.tabs.store.details import Ui_DetailsWidget
from rare.utils.misc import icon
@@ -28,7 +29,7 @@ class DetailsWidget(QWidget, SideTabContents):
back_clicked: pyqtSignal = pyqtSignal()
# TODO Design
- def __init__(self, installed_titles: list, api_core, parent=None):
+ def __init__(self, installed: List, store_api: StoreAPI, parent=None):
super(DetailsWidget, self).__init__(parent=parent)
self.implements_scrollarea = True
@@ -36,13 +37,11 @@ class DetailsWidget(QWidget, SideTabContents):
self.ui.setupUi(self)
self.ui.main_layout.setContentsMargins(0, 0, 3, 0)
- # self.core = LegendaryCoreSingleton()
- self.api_core = api_core
- self.installed = installed_titles
- self.offer: CatalogOfferModel = None
- self.data: dict = {}
+ self.store_api = store_api
+ self.installed = installed
+ self.catalog_offer: CatalogOfferModel = None
- self.image = LoadingImageWidget(api_core.cached_manager, self)
+ self.image = LoadingImageWidget(store_api.cached_manager, self)
self.image.setFixedSize(ImageSize.Display)
self.ui.left_layout.insertWidget(0, self.image, alignment=Qt.AlignTop)
self.ui.left_layout.setAlignment(Qt.AlignTop)
@@ -53,7 +52,7 @@ class DetailsWidget(QWidget, SideTabContents):
self.in_wishlist = False
self.wishlist = []
- self.requirements_tabs: SideTabWidget = SideTabWidget(parent=self.ui.requirements_frame)
+ self.requirements_tabs = SideTabWidget(parent=self.ui.requirements_frame)
self.requirements_tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.ui.requirements_layout.addWidget(self.requirements_tabs)
@@ -78,15 +77,17 @@ class DetailsWidget(QWidget, SideTabContents):
self.ui.title.setText(offer.title)
self.title_str = offer.title
self.id_str = offer.id
- self.api_core.get_wishlist(self.handle_wishlist_update)
+ self.store_api.get_wishlist(self.handle_wishlist_update)
+
# lk: delete tabs in reverse order because indices are updated on deletion
while self.requirements_tabs.count():
self.requirements_tabs.widget(0).deleteLater()
self.requirements_tabs.removeTab(0)
self.requirements_tabs.clear()
- slug = offer.product_slug
+
+ slug = offer.productSlug
if not slug:
- for mapping in offer.offer_mappings:
+ for mapping in offer.offerMappings:
if mapping["pageType"] == "productHome":
slug = mapping["pageSlug"]
break
@@ -114,24 +115,24 @@ class DetailsWidget(QWidget, SideTabContents):
# init API request
if slug:
- self.api_core.get_game_config_cms(offer.product_slug, is_bundle, self.data_received)
+ self.store_api.get_game_config_cms(offer.productSlug, is_bundle, self.data_received)
# else:
# self.data_received({})
- self.offer = offer
+ self.catalog_offer = offer
def add_to_wishlist(self):
if not self.in_wishlist:
- self.api_core.add_to_wishlist(
- self.offer.namespace,
- self.offer.id,
+ self.store_api.add_to_wishlist(
+ self.catalog_offer.namespace,
+ self.catalog_offer.id,
lambda success: self.ui.wishlist_button.setText(self.tr("Remove from wishlist"))
if success
else self.ui.wishlist_button.setText("Something went wrong")
)
else:
- self.api_core.remove_from_wishlist(
- self.offer.namespace,
- self.offer.id,
+ self.store_api.remove_from_wishlist(
+ self.catalog_offer.namespace,
+ self.catalog_offer.id,
lambda success: self.ui.wishlist_button.setText(self.tr("Add to wishlist"))
if success
else self.ui.wishlist_button.setText("Something went wrong"),
@@ -146,34 +147,16 @@ class DetailsWidget(QWidget, SideTabContents):
except Exception as e:
raise e
logger.error(str(e))
- self.price.setText("Error")
- self.requirements_tabs.setEnabled(False)
- for img in self.data.get("keyImages"):
- if img["type"] in [
- "DieselStoreFrontWide",
- "OfferImageTall",
- "VaultClosed",
- "ProductLogo",
- ]:
- self.image.fetchPixmap(img["url"])
- break
- self.price.setText("")
- self.discount_price.setText("")
- self.social_group.setEnabled(False)
- self.tags.setText("")
- self.dev.setText(self.data.get("seller", {}).get("name", ""))
- return
- # self.title.setText(self.game.title)
- self.ui.price.setFont(QFont())
- price = self.offer.price.total_price["fmtPrice"]["originalPrice"]
- discount_price = self.offer.price.total_price["fmtPrice"]["discountPrice"]
+ self.ui.price.setFont(self.font())
+ price = self.catalog_offer.price.totalPrice.fmtPrice["originalPrice"]
+ discount_price = self.catalog_offer.price.totalPrice.fmtPrice["discountPrice"]
if price == "0" or price == 0:
self.ui.price.setText(self.tr("Free"))
else:
self.ui.price.setText(price)
if price != discount_price:
- font = QFont()
+ font = self.font()
font.setStrikeOut(True)
self.ui.price.setFont(font)
self.ui.discount_price.setText(
@@ -189,18 +172,11 @@ class DetailsWidget(QWidget, SideTabContents):
if requirements and requirements.systems:
for system in requirements.systems:
req_widget = RequirementsWidget(system, self.requirements_tabs)
- self.requirements_tabs.addTab(req_widget, system.system_type)
- # self.req_group_box.layout().addWidget(req_tabs)
- # self.req_group_box.layout().setAlignment(Qt.AlignTop)
- # else:
- # self.req_group_box.layout().addWidget(
- # QLabel(self.tr("Could not get requirements"))
- # )
- self.ui.requirements_frame.setVisible(True)
+ self.requirements_tabs.addTab(req_widget, system.systemType)
else:
self.ui.requirements_frame.setVisible(False)
- key_images = self.offer.key_images
+ key_images = self.catalog_offer.keyImages
img_url = key_images.for_dimensions(self.image.size().width(), self.image.size().height())
self.image.fetchPixmap(img_url.url)
@@ -223,7 +199,7 @@ class DetailsWidget(QWidget, SideTabContents):
self.ui.social_layout.removeWidget(b)
b.deleteLater()
- links = product_data.social_links
+ links = product_data.socialLinks
link_count = 0
for name, url in links.items():
if name == "_type":
@@ -252,8 +228,7 @@ class DetailsWidget(QWidget, SideTabContents):
# self.wishlist.append(game["offer"]["title"])
def button_clicked(self):
- return
- QDesktopServices.openUrl(QUrl(f"https://www.epicgames.com/store/{self.core.language_code}/p/{self.slug}"))
+ QDesktopServices.openUrl(QUrl(f"https://www.epicgames.com/store/{self.store_api.language_code}/p/{self.slug}"))
def keyPressEvent(self, a0: QKeyEvent):
if a0.key() == Qt.Key_Escape:
diff --git a/rare/components/tabs/store/widgets/items.py b/rare/components/tabs/store/widgets/items.py
index 02b6b500..3fc0363c 100644
--- a/rare/components/tabs/store/widgets/items.py
+++ b/rare/components/tabs/store/widgets/items.py
@@ -11,7 +11,7 @@ from rare.utils.misc import qta_icon
from rare.utils.qt_requests import QtRequests
from .image import LoadingImageWidget
-logger = logging.getLogger("GameWidgets")
+logger = logging.getLogger("StoreWidgets")
class ItemWidget(LoadingImageWidget):
@@ -46,15 +46,15 @@ class StoreItemWidget(ItemWidget):
return
self.ui.title_label.setText(game.title)
- for attr in game.custom_attributes:
+ for attr in game.customAttributes:
if attr["key"] == "developerName":
developer = attr["value"]
break
else:
developer = game.seller["name"]
self.ui.developer_label.setText(developer)
- price = game.price.total_price["fmtPrice"]["originalPrice"]
- discount_price = game.price.total_price["fmtPrice"]["discountPrice"]
+ price = game.price.totalPrice.fmtPrice["originalPrice"]
+ discount_price = game.price.totalPrice.fmtPrice["discountPrice"]
self.ui.price_label.setText(f'{price if price != "0" else self.tr("Free")}')
if price != discount_price:
font = self.ui.price_label.font()
@@ -64,7 +64,7 @@ class StoreItemWidget(ItemWidget):
else:
self.ui.discount_label.setVisible(False)
- key_images = game.key_images
+ key_images = game.keyImages
self.fetchPixmap(key_images.for_dimensions(self.width(), self.height()).url)
# for img in json_info["keyImages"]:
@@ -83,13 +83,13 @@ class ResultsItemWidget(ItemWidget):
self.setFixedSize(ImageSize.Display)
self.ui.setupUi(self)
- key_images = catalog_game.key_images
+ key_images = catalog_game.keyImages
self.fetchPixmap(key_images.for_dimensions(self.width(), self.height()).url)
self.ui.title_label.setText(catalog_game.title)
- price = catalog_game.price.total_price["fmtPrice"]["originalPrice"]
- discount_price = catalog_game.price.total_price["fmtPrice"]["discountPrice"]
+ price = catalog_game.price.totalPrice.fmtPrice["originalPrice"]
+ discount_price = catalog_game.price.totalPrice.fmtPrice["discountPrice"]
self.ui.price_label.setText(f'{price if price != "0" else self.tr("Free")}')
if price != discount_price:
font = self.ui.price_label.font()
@@ -108,14 +108,14 @@ class WishlistItemWidget(ItemWidget):
super(WishlistItemWidget, self).__init__(manager, catalog_game, parent=parent)
self.setFixedSize(ImageSize.DisplayWide)
self.ui.setupUi(self)
- for attr in catalog_game.custom_attributes:
+ for attr in catalog_game.customAttributes:
if attr["key"] == "developerName":
developer = attr["value"]
break
else:
developer = catalog_game.seller["name"]
- original_price = catalog_game.price.total_price["fmtPrice"]["originalPrice"]
- discount_price = catalog_game.price.total_price["fmtPrice"]["discountPrice"]
+ original_price = catalog_game.price.totalPrice.fmtPrice["originalPrice"]
+ discount_price = catalog_game.price.totalPrice.fmtPrice["discountPrice"]
self.ui.title_label.setText(catalog_game.title)
self.ui.developer_label.setText(developer)
@@ -127,7 +127,7 @@ class WishlistItemWidget(ItemWidget):
self.ui.discount_label.setText(f'{discount_price if discount_price != "0" else self.tr("Free")}')
else:
self.ui.discount_label.setVisible(False)
- key_images = catalog_game.key_images
+ key_images = catalog_game.keyImages
self.fetchPixmap(
key_images.for_dimensions(self.width(), self.height()).url
)
diff --git a/rare/components/tabs/store/wishlist.py b/rare/components/tabs/store/wishlist.py
index bedc2ca4..2eb173a9 100644
--- a/rare/components/tabs/store/wishlist.py
+++ b/rare/components/tabs/store/wishlist.py
@@ -116,13 +116,13 @@ class WishlistWidget(QWidget, SideTabContents):
func = lambda x: x.catalog_game.title
reverse = self.ui.reverse.isChecked()
elif sort == 1:
- func = lambda x: x.catalog_game.price.total_price["fmtPrice"]["discountPrice"]
+ func = lambda x: x.catalog_game.price.totalPrice["fmtPrice"]["discountPrice"]
reverse = self.ui.reverse.isChecked()
elif sort == 2:
func = lambda x: x.catalog_game.seller["name"]
reverse = self.ui.reverse.isChecked()
elif sort == 3:
- func = lambda x: 1 - (x.catalog_game.price.total_price["discountPrice"] / x.catalog_game.price.total_price["originalPrice"])
+ func = lambda x: 1 - (x.catalog_game.price.totalPrice["discountPrice"] / x.catalog_game.price.totalPrice["originalPrice"])
reverse = not self.ui.reverse.isChecked()
else:
func = lambda x: x.catalog_game.title
diff --git a/rare/ui/components/tabs/store/details.py b/rare/ui/components/tabs/store/details.py
index 5c570cb2..ccb87c86 100644
--- a/rare/ui/components/tabs/store/details.py
+++ b/rare/ui/components/tabs/store/details.py
@@ -18,6 +18,8 @@ class Ui_DetailsWidget(object):
DetailsWidget.setWindowTitle("DetailsWidget")
self.main_layout = QtWidgets.QHBoxLayout(DetailsWidget)
self.main_layout.setObjectName("main_layout")
+ self.left_layout = QtWidgets.QVBoxLayout()
+ self.left_layout.setObjectName("left_layout")
self.back_button = QtWidgets.QPushButton(DetailsWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
@@ -28,9 +30,7 @@ class Ui_DetailsWidget(object):
self.back_button.setIconSize(QtCore.QSize(32, 32))
self.back_button.setFlat(True)
self.back_button.setObjectName("back_button")
- self.main_layout.addWidget(self.back_button)
- self.left_layout = QtWidgets.QVBoxLayout()
- self.left_layout.setObjectName("left_layout")
+ self.left_layout.addWidget(self.back_button)
self.main_layout.addLayout(self.left_layout)
self.right_layout = QtWidgets.QVBoxLayout()
self.right_layout.setObjectName("right_layout")
@@ -176,7 +176,7 @@ class Ui_DetailsWidget(object):
self.description_label.setObjectName("description_label")
self.right_layout.addWidget(self.description_label)
self.main_layout.addLayout(self.right_layout)
- self.main_layout.setStretch(2, 1)
+ self.main_layout.setStretch(1, 1)
self.retranslateUi(DetailsWidget)
diff --git a/rare/ui/components/tabs/store/details.ui b/rare/ui/components/tabs/store/details.ui
index 20b21038..b78efa4c 100644
--- a/rare/ui/components/tabs/store/details.ui
+++ b/rare/ui/components/tabs/store/details.ui
@@ -13,31 +13,32 @@
DetailsWidget
-
+
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- 32
- 32
-
-
-
- true
-
-
-
- -
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ 32
+ 32
+
+
+
+ true
+
+
+
+
-
diff --git a/rare/utils/qt_requests.py b/rare/utils/qt_requests.py
index 2a7d8bbd..02a9c5a2 100644
--- a/rare/utils/qt_requests.py
+++ b/rare/utils/qt_requests.py
@@ -5,7 +5,7 @@ from typing import Callable, Dict, TypeVar, List, Tuple
from typing import Union
import orjson
-from PyQt5.QtCore import QObject, pyqtSignal, QUrl, QUrlQuery, pyqtSlot
+from PyQt5.QtCore import QObject, pyqtSignal, QUrl, QUrlQuery, pyqtSlot, QJsonDocument
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply, QNetworkDiskCache
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36"