Add browse games function
This commit is contained in:
parent
0f6a4c5ae6
commit
c063e9a92a
|
@ -33,7 +33,7 @@ class TabWidget(QTabWidget):
|
|||
self.addTab(self.downloadTab, "Downloads" + (" (" + str(len(updates)) + ")" if len(updates) != 0 else ""))
|
||||
self.cloud_saves = SyncSaves(core, self)
|
||||
self.addTab(self.cloud_saves, "Cloud Saves")
|
||||
self.store = Shop()
|
||||
self.store = Shop(self.core)
|
||||
self.addTab(self.store, self.tr("Store (Beta)"))
|
||||
self.settings = SettingsTab(core, self)
|
||||
|
||||
|
|
|
@ -1,35 +1,54 @@
|
|||
from PyQt5.QtWidgets import QStackedWidget
|
||||
import os
|
||||
|
||||
from PyQt5.QtWidgets import QStackedWidget, QTabWidget
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
||||
from rare.components.tabs.shop.search_results import SearchResults
|
||||
from rare.components.tabs.shop.shop_info import ShopGameInfo
|
||||
from rare.components.tabs.shop.shop_widget import ShopWidget
|
||||
from rare.components.tabs.shop.browse_games import BrowseGames
|
||||
|
||||
|
||||
class Shop(QStackedWidget):
|
||||
init = False
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(Shop, self).__init__()
|
||||
self.core = core
|
||||
if p := os.getenv("XDG_CACHE_HOME"):
|
||||
self.path = p
|
||||
else:
|
||||
self.path = os.path.expanduser("~/.cache/rare/cache/")
|
||||
if not os.path.exists(self.path):
|
||||
os.makedirs(self.path)
|
||||
|
||||
self.shop = ShopWidget()
|
||||
self.addWidget(self.shop)
|
||||
self.shop = ShopWidget(self.path)
|
||||
self.browse_games = BrowseGames(self.path)
|
||||
|
||||
self.store_tabs = QTabWidget()
|
||||
self.store_tabs.addTab(self.shop, self.tr("Games"))
|
||||
self.store_tabs.addTab(self.browse_games, self.tr("Browse"))
|
||||
|
||||
self.addWidget(self.store_tabs)
|
||||
|
||||
self.search_results = SearchResults()
|
||||
self.addWidget(self.search_results)
|
||||
self.search_results.show_info.connect(self.show_game_info)
|
||||
|
||||
self.info = ShopGameInfo()
|
||||
self.info = ShopGameInfo([i.asset_info.namespace for i in self.core.get_game_list(True)])
|
||||
self.addWidget(self.info)
|
||||
self.info.back_button.clicked.connect(lambda: self.setCurrentIndex(0))
|
||||
|
||||
self.search_results.back_button.clicked.connect(lambda: self.setCurrentIndex(0))
|
||||
self.shop.show_info.connect(self.show_info)
|
||||
self.shop.show_game.connect(self.show_game_info)
|
||||
self.browse_games.show_game.connect(self.show_game_info)
|
||||
|
||||
def load(self):
|
||||
if not self.init:
|
||||
self.init = True
|
||||
self.shop.load()
|
||||
self.browse_games.prepare_request()
|
||||
|
||||
def show_game_info(self, data):
|
||||
self.info.update_game(data)
|
||||
|
|
147
rare/components/tabs/shop/browse_games.py
Normal file
147
rare/components/tabs/shop/browse_games.py
Normal file
|
@ -0,0 +1,147 @@
|
|||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
|
||||
from PyQt5.QtCore import QUrl, pyqtSignal, QJsonParseError, QJsonDocument
|
||||
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply, QNetworkAccessManager
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
from rare.components.tabs.shop.game_widgets import GameWidget
|
||||
from rare.ui.components.tabs.store.browse_games import Ui_browse_games
|
||||
from rare.utils.extra_widgets import FlowLayout, WaitingSpinner
|
||||
from rare.utils.utils import get_lang
|
||||
|
||||
logger = logging.getLogger("BrowseGames")
|
||||
|
||||
|
||||
class BrowseGames(QWidget, Ui_browse_games):
|
||||
show_game = pyqtSignal(dict)
|
||||
price = ""
|
||||
platform = (False, False)
|
||||
|
||||
def __init__(self, path):
|
||||
super(BrowseGames, self).__init__()
|
||||
self.setupUi(self)
|
||||
self.path = path
|
||||
self.games_widget = QWidget()
|
||||
self.games_widget.setLayout(FlowLayout())
|
||||
self.games.setWidget(self.games_widget)
|
||||
self.manager = QNetworkAccessManager()
|
||||
|
||||
self.stack.addWidget(WaitingSpinner())
|
||||
|
||||
self.clear_price.toggled.connect(lambda: self.prepare_request("") if self.clear_price.isChecked() else None)
|
||||
self.free_button.toggled.connect(lambda: self.prepare_request("free") if self.free_button.isChecked() else None)
|
||||
self.under10.toggled.connect(
|
||||
lambda: self.prepare_request("<price>[0, 1000)") if self.under10.isChecked() else None)
|
||||
self.under20.toggled.connect(
|
||||
lambda: self.prepare_request("<price>[0, 2000)") if self.under20.isChecked() else None)
|
||||
self.under30.toggled.connect(
|
||||
lambda: self.prepare_request("<price>[0, 3000)") if self.under30.isChecked() else None)
|
||||
self.above.toggled.connect(lambda: self.prepare_request("<price>[1499,]") if self.above.isChecked() else None)
|
||||
self.on_discount.toggled.connect(lambda: self.prepare_request("sale") if self.on_discount.isChecked() else None)
|
||||
|
||||
self.win_cb.toggled.connect(
|
||||
lambda: self.prepare_request(platform=(self.win_cb.isChecked(), self.mac_cb.isChecked())))
|
||||
self.mac_cb.toggled.connect(
|
||||
lambda: self.prepare_request(platform=(self.win_cb.isChecked(), self.mac_cb.isChecked())))
|
||||
|
||||
def prepare_request(self, price: str = None, platform: tuple = None):
|
||||
if price is not None:
|
||||
self.price = price
|
||||
if platform is not None:
|
||||
self.platform = platform
|
||||
|
||||
locale = get_lang()
|
||||
self.stack.setCurrentIndex(2)
|
||||
date = f"[,{datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%dT%X')}.{str(random.randint(0, 999)).zfill(3)}Z]"
|
||||
payload = {"variables": {"category": "games/edition/base|bundles/games|editors|software/edition/base",
|
||||
"count": 30, "country": locale.upper(), "keywords": "", "locale": locale,
|
||||
"sortDir": "DESC", "allowCountries": locale.upper(), "start": 0, "tag": "",
|
||||
"withMapping": True, "withPrice": True,
|
||||
"releaseDate": date, "effectiveDate": date
|
||||
},
|
||||
"query": game_query}
|
||||
|
||||
if self.price == "free":
|
||||
payload["variables"]["freeGame"] = True
|
||||
elif self.price.startswith("<price>"):
|
||||
payload["variables"]["priceRange"] = price.replace("<price>", "")
|
||||
elif self.price == "sale":
|
||||
payload["variables"]["onSale"] = True
|
||||
|
||||
if self.platform[0]:
|
||||
payload["variables"]["tag"] = "9547"
|
||||
if self.platform[1]:
|
||||
payload["variables"]["tag"] += "|10719"
|
||||
elif self.platform[1]:
|
||||
payload["variables"]["tag"] = "10719"
|
||||
|
||||
request = QNetworkRequest(QUrl("https://www.epicgames.com/graphql"))
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
self.game_request = self.manager.post(request, json.dumps(payload).encode("utf-8"))
|
||||
self.game_request.finished.connect(self.show_games)
|
||||
|
||||
def show_games(self):
|
||||
if self.game_request:
|
||||
if self.game_request.error() == QNetworkReply.NoError:
|
||||
error = QJsonParseError()
|
||||
json_data = QJsonDocument.fromJson(self.game_request.readAll().data(), error)
|
||||
|
||||
if error.error == error.NoError:
|
||||
try:
|
||||
games = json.loads(json_data.toJson().data().decode())["data"]["Catalog"]["searchStore"][
|
||||
"elements"]
|
||||
except TypeError as e:
|
||||
logger.error("Type Error: " + str(e))
|
||||
self.stack.setCurrentIndex(1)
|
||||
else:
|
||||
QWidget().setLayout(self.games_widget.layout())
|
||||
self.games_widget.setLayout(FlowLayout())
|
||||
|
||||
for game in games:
|
||||
w = GameWidget(self.path, game, 275)
|
||||
self.games_widget.layout().addWidget(w)
|
||||
w.show_info.connect(self.show_game.emit)
|
||||
self.stack.setCurrentIndex(0)
|
||||
return
|
||||
|
||||
else:
|
||||
logger.info(self.slug, error.errorString())
|
||||
else:
|
||||
print(self.game_request.errorString())
|
||||
self.stack.setCurrentIndex(1)
|
||||
|
||||
|
||||
game_query = "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, " \
|
||||
"$keywords: String, $locale: String, $namespace: String, $withMapping: Boolean = false, $itemNs: String, " \
|
||||
"$sortBy: String, $sortDir: String, $start: Int, $tag: String, $releaseDate: String, $withPrice: Boolean " \
|
||||
"= false, $withPromotions: Boolean = false, $priceRange: String, $freeGame: Boolean, $onSale: Boolean, " \
|
||||
"$effectiveDate: String) {\n Catalog {\n searchStore(\n allowCountries: $allowCountries\n " \
|
||||
"category: $category\n count: $count\n country: $country\n keywords: $keywords\n " \
|
||||
"locale: $locale\n namespace: $namespace\n itemNs: $itemNs\n sortBy: $sortBy\n " \
|
||||
"sortDir: $sortDir\n releaseDate: $releaseDate\n start: $start\n tag: $tag\n " \
|
||||
"priceRange: $priceRange\n freeGame: $freeGame\n onSale: $onSale\n effectiveDate: " \
|
||||
"$effectiveDate\n ) {\n elements {\n title\n id\n namespace\n " \
|
||||
"description\n effectiveDate\n keyImages {\n type\n url\n }\n " \
|
||||
" currentPrice\n seller {\n id\n name\n }\n productSlug\n " \
|
||||
" urlSlug\n url\n tags {\n id\n }\n items {\n id\n " \
|
||||
" namespace\n }\n customAttributes {\n key\n value\n }\n " \
|
||||
"categories {\n path\n }\n catalogNs @include(if: $withMapping) {\n " \
|
||||
"mappings(pageType: \"productHome\") {\n pageSlug\n pageType\n }\n " \
|
||||
"}\n offerMappings @include(if: $withMapping) {\n pageSlug\n pageType\n " \
|
||||
"}\n price(country: $country) @include(if: $withPrice) {\n totalPrice {\n " \
|
||||
"discountPrice\n originalPrice\n voucherDiscount\n discount\n " \
|
||||
" currencyCode\n currencyInfo {\n decimals\n }\n fmtPrice(" \
|
||||
"locale: $locale) {\n originalPrice\n discountPrice\n " \
|
||||
"intermediatePrice\n }\n }\n lineOffers {\n appliedRules {\n " \
|
||||
" id\n endDate\n discountSetting {\n discountType\n " \
|
||||
" }\n }\n }\n }\n promotions(category: $category) @include(if: " \
|
||||
"$withPromotions) {\n promotionalOffers {\n promotionalOffers {\n " \
|
||||
"startDate\n endDate\n discountSetting {\n discountType\n " \
|
||||
" discountPercentage\n }\n }\n }\n " \
|
||||
"upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n " \
|
||||
"endDate\n discountSetting {\n discountType\n " \
|
||||
"discountPercentage\n }\n }\n }\n }\n }\n paging {\n " \
|
||||
" count\n total\n }\n }\n }\n}\n "
|
150
rare/components/tabs/shop/game_widgets.py
Normal file
150
rare/components/tabs/shop/game_widgets.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtCore import pyqtSignal, QSettings, Qt, QUrl, QJsonParseError, QJsonDocument
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel
|
||||
|
||||
from rare.utils.extra_widgets import ImageLabel
|
||||
from rare.utils.utils import get_lang
|
||||
|
||||
|
||||
class GameWidget(QWidget):
|
||||
show_info = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, path, json_info=None, width=300):
|
||||
super(GameWidget, self).__init__()
|
||||
self.manager = QNetworkAccessManager()
|
||||
self.width = width
|
||||
if json_info:
|
||||
self.init_ui(json_info, path)
|
||||
self.path = path
|
||||
|
||||
def init_ui(self, json_info, path):
|
||||
self.path = path
|
||||
self.layout = QVBoxLayout()
|
||||
self.image = ImageLabel()
|
||||
self.json_info = json_info
|
||||
self.slug = json_info["productSlug"]
|
||||
|
||||
self.title = json_info["title"]
|
||||
for img in json_info["keyImages"]:
|
||||
if img["type"] in ["DieselStoreFrontWide", "OfferImageWide", "VaultClosed"]:
|
||||
if img["type"] == "VaultClosed" and self.title != "Mystery Game":
|
||||
continue
|
||||
self.image.update_image(img["url"], json_info["title"], (self.width, int(self.width * 9 / 16)))
|
||||
break
|
||||
else:
|
||||
print(json_info["keyImages"])
|
||||
|
||||
save = QSettings().value("cache_images", True, bool)
|
||||
if os.path.exists(p := os.path.join(self.path, f"{json_info['title']}_wide.png")) and save:
|
||||
self.image.setPixmap(QPixmap(p)
|
||||
.scaled(self.width, int(self.width * 9 / 16), transformMode=Qt.SmoothTransformation))
|
||||
else:
|
||||
for img in json_info["keyImages"]:
|
||||
if img["type"] in ["DieselStoreFrontWide", "VaultClosed"]:
|
||||
if img["type"] == "VaultClosed" and self.title != "Mystery Game":
|
||||
continue
|
||||
self.image_request = self.manager.get(QNetworkRequest(QUrl(img["url"])))
|
||||
self.image_request.finished.connect(lambda: self.image_ready(save))
|
||||
break
|
||||
else:
|
||||
# No image found
|
||||
logging.error(f"No image found for {self.title}")
|
||||
|
||||
self.layout.addWidget(self.image)
|
||||
|
||||
self.title_label = QLabel(json_info["title"])
|
||||
self.title_label.setWordWrap(True)
|
||||
self.layout.addWidget(self.title_label)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def image_ready(self, save: bool):
|
||||
if self.image_request:
|
||||
if self.image_request.error() == QNetworkReply.NoError:
|
||||
data = self.image_request.readAll().data()
|
||||
if save:
|
||||
with open(os.path.join(self.path, f"{self.title}_wide.png"), "wb") as file:
|
||||
file.write(data)
|
||||
file.close()
|
||||
pixmap = QPixmap()
|
||||
pixmap.loadFromData(data)
|
||||
self.image.setPixmap(pixmap.scaled(self.width, int(self.width * 9 / 16),
|
||||
transformMode=Qt.SmoothTransformation))
|
||||
|
||||
def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None:
|
||||
self.show_info.emit(self.json_info)
|
||||
|
||||
@classmethod
|
||||
def from_request(cls, name, path):
|
||||
c = cls(path)
|
||||
c.manager = QNetworkAccessManager()
|
||||
c.request = c.manager.get(QNetworkRequest())
|
||||
|
||||
locale = get_lang()
|
||||
payload = json.dumps({
|
||||
"query": query,
|
||||
"variables": {"category": "games/edition/base|bundles/games|editors|software/edition/base", "count": 1,
|
||||
"country": "DE", "keywords": name, "locale": locale, "sortDir": "DESC",
|
||||
"allowCountries": locale.upper(),
|
||||
"start": 0, "tag": "", "withMapping": False, "withPrice": True}
|
||||
}).encode()
|
||||
request = QNetworkRequest(QUrl("https://www.epicgames.com/graphql"))
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
c.search_request = c.manager.post(request, payload)
|
||||
c.search_request.finished.connect(lambda: c.handle_response(path))
|
||||
return c
|
||||
|
||||
def handle_response(self, path):
|
||||
if self.search_request:
|
||||
if self.search_request.error() == QNetworkReply.NoError:
|
||||
error = QJsonParseError()
|
||||
json_data = QJsonDocument.fromJson(self.search_request.readAll().data(), error)
|
||||
if QJsonParseError.NoError == error.error:
|
||||
data = json.loads(json_data.toJson().data().decode())["data"]["Catalog"]["searchStore"][
|
||||
"elements"][0]
|
||||
self.init_ui(data, path)
|
||||
else:
|
||||
logging.error(error.errorString())
|
||||
return
|
||||
|
||||
else:
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
query = "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, " \
|
||||
"$keywords: String, $locale: String, $namespace: String, $withMapping: Boolean = false, $itemNs: String, " \
|
||||
"$sortBy: String, $sortDir: String, $start: Int, $tag: String, $releaseDate: String, $withPrice: Boolean = " \
|
||||
"false, $withPromotions: Boolean = false, $priceRange: String, $freeGame: Boolean, $onSale: Boolean, " \
|
||||
"$effectiveDate: String) {\n Catalog {\n searchStore(\n allowCountries: $allowCountries\n " \
|
||||
"category: $category\n count: $count\n country: $country\n keywords: $keywords\n locale: " \
|
||||
"$locale\n namespace: $namespace\n itemNs: $itemNs\n sortBy: $sortBy\n sortDir: " \
|
||||
"$sortDir\n releaseDate: $releaseDate\n start: $start\n tag: $tag\n priceRange: " \
|
||||
"$priceRange\n freeGame: $freeGame\n onSale: $onSale\n effectiveDate: $effectiveDate\n ) {" \
|
||||
"\n elements {\n title\n id\n namespace\n description\n " \
|
||||
"effectiveDate\n keyImages {\n type\n url\n }\n currentPrice\n " \
|
||||
"seller {\n id\n name\n }\n productSlug\n urlSlug\n url\n " \
|
||||
" tags {\n id\n }\n items {\n id\n namespace\n }\n " \
|
||||
"customAttributes {\n key\n value\n }\n categories {\n path\n " \
|
||||
"}\n catalogNs @include(if: $withMapping) {\n mappings(pageType: \"productHome\") {\n " \
|
||||
" pageSlug\n pageType\n }\n }\n offerMappings @include(if: $withMapping) " \
|
||||
"{\n pageSlug\n pageType\n }\n price(country: $country) @include(if: " \
|
||||
"$withPrice) {\n totalPrice {\n discountPrice\n originalPrice\n " \
|
||||
"voucherDiscount\n discount\n currencyCode\n currencyInfo {\n " \
|
||||
"decimals\n }\n fmtPrice(locale: $locale) {\n originalPrice\n " \
|
||||
"discountPrice\n intermediatePrice\n }\n }\n lineOffers {\n " \
|
||||
" appliedRules {\n id\n endDate\n discountSetting {\n " \
|
||||
"discountType\n }\n }\n }\n }\n promotions(category: " \
|
||||
"$category) @include(if: $withPromotions) {\n promotionalOffers {\n promotionalOffers {\n " \
|
||||
" startDate\n endDate\n discountSetting {\n " \
|
||||
"discountType\n discountPercentage\n }\n }\n }\n " \
|
||||
"upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n " \
|
||||
"endDate\n discountSetting {\n discountType\n discountPercentage\n " \
|
||||
" }\n }\n }\n }\n }\n paging {\n count\n " \
|
||||
"total\n }\n }\n }\n}\n "
|
|
@ -67,7 +67,7 @@ class _SearchResultItem(QGroupBox):
|
|||
price = result['price']['totalPrice']['fmtPrice']['originalPrice']
|
||||
discount_price = result['price']['totalPrice']['fmtPrice']['discountPrice']
|
||||
price_layout = QHBoxLayout()
|
||||
price_label = QLabel(price)
|
||||
price_label = QLabel(price if price != "0" else self.tr("Free"))
|
||||
price_layout.addWidget(price_label)
|
||||
|
||||
if price != discount_price:
|
||||
|
|
|
@ -20,9 +20,10 @@ class ShopGameInfo(QWidget, Ui_shop_info):
|
|||
data: dict
|
||||
|
||||
# TODO Design
|
||||
def __init__(self):
|
||||
def __init__(self, installed_titles: list):
|
||||
super(ShopGameInfo, self).__init__()
|
||||
self.setupUi(self)
|
||||
self.installed = installed_titles
|
||||
self.open_store_button.clicked.connect(self.button_clicked)
|
||||
self.image = ImageLabel()
|
||||
self.image_stack.addWidget(self.image)
|
||||
|
@ -38,6 +39,12 @@ class ShopGameInfo(QWidget, Ui_shop_info):
|
|||
slug = slug.replace("/home", "")
|
||||
self.slug = slug
|
||||
self.title.setText(data["title"])
|
||||
if data["namespace"] in self.installed:
|
||||
self.open_store_button.setText(self.tr("Show Game on Epic Page"))
|
||||
self.owned_label.setVisible(True)
|
||||
else:
|
||||
self.open_store_button.setText(self.tr("Buy Game in Epic Games Store"))
|
||||
self.owned_label.setVisible(False)
|
||||
|
||||
self.dev.setText(self.tr("Loading"))
|
||||
self.image.setPixmap(QPixmap())
|
||||
|
@ -73,8 +80,10 @@ class ShopGameInfo(QWidget, Ui_shop_info):
|
|||
return
|
||||
self.game = ShopGame.from_json(game, self.data)
|
||||
self.title.setText(self.game.title)
|
||||
|
||||
self.price.setText(self.game.price)
|
||||
if self.game.price != "0":
|
||||
self.price.setText(self.game.price)
|
||||
else:
|
||||
self.price.setText(self.tr("Free"))
|
||||
if self.game.price != self.game.discount_price:
|
||||
self.discount_price.setText(self.game.discount_price)
|
||||
self.discount_price.setVisible(True)
|
||||
|
@ -90,7 +99,7 @@ class ShopGameInfo(QWidget, Ui_shop_info):
|
|||
self.req_group_box.layout().addWidget(min_label, 0, 1)
|
||||
self.req_group_box.layout().addWidget(rec_label, 0, 2)
|
||||
|
||||
for i, (key, value) in enumerate(self.game.reqs["Windows"].items()):
|
||||
for i, (key, value) in enumerate(self.game.reqs.get("Windows", {}).items()):
|
||||
self.req_group_box.layout().addWidget(QLabel(key), i + 1, 0)
|
||||
min_label = QLabel(value[0])
|
||||
min_label.setWordWrap(True)
|
||||
|
|
|
@ -63,7 +63,10 @@ class ShopGame:
|
|||
tmp.available_voice_langs = api_data["data"]["requirements"].get("languages", "Failed")
|
||||
tmp.reqs = {}
|
||||
for i, system in enumerate(api_data["data"]["requirements"]["systems"]):
|
||||
tmp.reqs[system["systemType"]] = {}
|
||||
try:
|
||||
tmp.reqs[system["systemType"]] = {}
|
||||
except KeyError:
|
||||
continue
|
||||
for req in system["details"]:
|
||||
try:
|
||||
tmp.reqs[system["systemType"]][req["title"]] = (req["minimum"], req["recommended"])
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from json import JSONDecodeError
|
||||
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, QUrl, QJsonDocument, QJsonParseError, \
|
||||
QStringListModel, QSettings
|
||||
from PyQt5.QtGui import QPixmap
|
||||
QStringListModel
|
||||
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QCompleter, QGroupBox, QHBoxLayout, QScrollArea
|
||||
from PyQt5.QtWidgets import QWidget, QCompleter, QGroupBox, QHBoxLayout, QScrollArea
|
||||
|
||||
from rare.components.tabs.shop.game_widgets import GameWidget
|
||||
from rare.ui.components.tabs.store.store import Ui_ShopWidget
|
||||
from rare.utils.extra_widgets import WaitingSpinner, ImageLabel, FlowLayout
|
||||
from rare.utils.extra_widgets import WaitingSpinner, FlowLayout
|
||||
from rare.utils.utils import get_lang
|
||||
|
||||
logger = logging.getLogger("Shop")
|
||||
|
@ -26,10 +24,11 @@ class ShopWidget(QScrollArea, Ui_ShopWidget):
|
|||
active_search_request = False
|
||||
next_search = ""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, path):
|
||||
super(ShopWidget, self).__init__()
|
||||
self.setWidgetResizable(True)
|
||||
self.setupUi(self)
|
||||
self.path = path
|
||||
self.manager = QNetworkAccessManager()
|
||||
self.free_games_widget = QWidget()
|
||||
self.free_games_widget.setLayout(FlowLayout())
|
||||
|
@ -49,54 +48,13 @@ class ShopWidget(QScrollArea, Ui_ShopWidget):
|
|||
self.data = []
|
||||
|
||||
self.games_groupbox.setLayout(FlowLayout())
|
||||
self.games_groupbox.setVisible(False)
|
||||
|
||||
def load(self):
|
||||
if p := os.getenv("XDG_CACHE_HOME"):
|
||||
self.path = p
|
||||
else:
|
||||
self.path = os.path.expanduser("~/.cache/rare/cache/")
|
||||
if not os.path.exists(self.path):
|
||||
os.makedirs(self.path)
|
||||
url = "https://store-site-backend-static.ak.epicgames.com/freeGamesPromotions"
|
||||
self.free_game_request = self.manager.get(QNetworkRequest(QUrl(url)))
|
||||
self.free_game_request.finished.connect(self.add_free_games)
|
||||
|
||||
game_list = ["Satisfactory", "Among Us", "Star Wars Jedi Fallen Order", "Watch Dogs", "Subnautica Below Zero"]
|
||||
# TODO read from api
|
||||
locale = get_lang()
|
||||
payload = json.dumps(
|
||||
{"variables": {"category": "games/edition/base|bundles/games|editors|software/edition/base",
|
||||
"count": 15, "country": locale.upper(), "keywords": "", "locale": locale,
|
||||
"sortDir": "DESC", "allowCountries": locale.upper(), "start": 0, "tag": "",
|
||||
"withMapping": True, "withPrice": True
|
||||
},
|
||||
"query": game_query}).encode()
|
||||
|
||||
request = QNetworkRequest(QUrl("https://www.epicgames.com/graphql"))
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
self.game_request = self.manager.post(request, payload)
|
||||
self.game_request.finished.connect(self.show_recommended_games)
|
||||
|
||||
def show_recommended_games(self):
|
||||
print("lol")
|
||||
if self.game_request:
|
||||
if self.game_request.error() == QNetworkReply.NoError:
|
||||
try:
|
||||
games = json.loads(self.game_request.readAll().data().decode())["data"]["Catalog"]["searchStore"][
|
||||
"elements"]
|
||||
print(games)
|
||||
except JSONDecodeError:
|
||||
return
|
||||
else:
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
for game in games:
|
||||
w = GameWidget(self.path, game)
|
||||
self.games_groupbox.layout().addWidget(w)
|
||||
w.show_info.connect(self.show_game.emit)
|
||||
|
||||
def add_free_games(self):
|
||||
if self.free_game_request:
|
||||
if self.free_game_request.error() == QNetworkReply.NoError:
|
||||
|
@ -190,27 +148,31 @@ class ShopWidget(QScrollArea, Ui_ShopWidget):
|
|||
|
||||
def show_search_results(self, show_direct=False):
|
||||
if self.search_request:
|
||||
if self.search_request.error() == QNetworkReply.NoError:
|
||||
error = QJsonParseError()
|
||||
json_data = QJsonDocument.fromJson(self.search_request.readAll().data(), error)
|
||||
if QJsonParseError.NoError == error.error:
|
||||
data = json.loads(json_data.toJson().data().decode())["data"]["Catalog"]["searchStore"]["elements"]
|
||||
self.data = data
|
||||
if show_direct:
|
||||
self.show_search_result(True)
|
||||
return
|
||||
titles = [i.get("title") for i in data]
|
||||
model = QStringListModel()
|
||||
model.setStringList(titles)
|
||||
self.completer.setModel(model)
|
||||
# self.completer.popup()
|
||||
if self.search_request:
|
||||
self.search_request.deleteLater()
|
||||
else:
|
||||
logging.error(error.errorString())
|
||||
# response = .decode(encoding="utf-8")
|
||||
# print(response)
|
||||
# results = json.loads(response)
|
||||
try:
|
||||
if self.search_request.error() == QNetworkReply.NoError:
|
||||
error = QJsonParseError()
|
||||
json_data = QJsonDocument.fromJson(self.search_request.readAll().data(), error)
|
||||
if QJsonParseError.NoError == error.error:
|
||||
data = json.loads(json_data.toJson().data().decode())["data"]["Catalog"]["searchStore"][
|
||||
"elements"]
|
||||
self.data = data
|
||||
if show_direct:
|
||||
self.show_search_result(True)
|
||||
return
|
||||
titles = [i.get("title") for i in data]
|
||||
model = QStringListModel()
|
||||
model.setStringList(titles)
|
||||
self.completer.setModel(model)
|
||||
# self.completer.popup()
|
||||
if self.search_request:
|
||||
self.search_request.deleteLater()
|
||||
else:
|
||||
logging.error(error.errorString())
|
||||
# response = .decode(encoding="utf-8")
|
||||
# print(response)
|
||||
# results = json.loads(response)
|
||||
except RuntimeError:
|
||||
return
|
||||
|
||||
self.search_games(self.next_search)
|
||||
|
||||
|
@ -227,111 +189,6 @@ class ShopWidget(QScrollArea, Ui_ShopWidget):
|
|||
self.show_game.emit(result)
|
||||
|
||||
|
||||
class GameWidget(QWidget):
|
||||
show_info = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, path, json_info=None):
|
||||
super(GameWidget, self).__init__()
|
||||
self.manager = QNetworkAccessManager()
|
||||
if json_info:
|
||||
self.init_ui(json_info, path)
|
||||
self.path = path
|
||||
|
||||
def init_ui(self, json_info, path):
|
||||
self.path = path
|
||||
self.layout = QVBoxLayout()
|
||||
self.image = ImageLabel()
|
||||
self.json_info = json_info
|
||||
self.slug = json_info["productSlug"]
|
||||
self.width = 300
|
||||
self.title = json_info["title"]
|
||||
for img in json_info["keyImages"]:
|
||||
if img["type"] in ["DieselStoreFrontWide", "VaultClosed"]:
|
||||
if img["type"] == "VaultClosed" and self.title != "Mystery Game":
|
||||
continue
|
||||
self.image.update_image(img["url"], json_info["title"], (self.width, int(self.width * 9 / 16)))
|
||||
break
|
||||
else:
|
||||
print("No image found")
|
||||
|
||||
save = QSettings().value("cache_images", True, bool)
|
||||
if os.path.exists(p := os.path.join(self.path, f"{json_info['title']}_wide.png")) and save:
|
||||
self.image.setPixmap(QPixmap(p)
|
||||
.scaled(self.width, int(self.width * 9 / 16), transformMode=Qt.SmoothTransformation))
|
||||
else:
|
||||
for img in json_info["keyImages"]:
|
||||
if img["type"] in ["DieselStoreFrontWide", "VaultClosed"]:
|
||||
if img["type"] == "VaultClosed" and self.title != "Mystery Game":
|
||||
continue
|
||||
self.image_request = self.manager.get(QNetworkRequest(QUrl(img["url"])))
|
||||
self.image_request.finished.connect(lambda: self.image_ready(save))
|
||||
break
|
||||
else:
|
||||
# No image found
|
||||
logger.error(f"No image found for {self.title}")
|
||||
|
||||
self.layout.addWidget(self.image)
|
||||
|
||||
self.title_label = QLabel(json_info["title"])
|
||||
self.title_label.setWordWrap(True)
|
||||
self.layout.addWidget(self.title_label)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def image_ready(self, save: bool):
|
||||
if self.image_request:
|
||||
if self.image_request.error() == QNetworkReply.NoError:
|
||||
data = self.image_request.readAll().data()
|
||||
if save:
|
||||
with open(os.path.join(self.path, f"{self.title}_wide.png"), "wb") as file:
|
||||
file.write(data)
|
||||
file.close()
|
||||
pixmap = QPixmap()
|
||||
pixmap.loadFromData(data)
|
||||
self.image.setPixmap(pixmap.scaled(self.width, int(self.width * 9 / 16),
|
||||
transformMode=Qt.SmoothTransformation))
|
||||
|
||||
def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None:
|
||||
self.show_info.emit(self.json_info)
|
||||
|
||||
@classmethod
|
||||
def from_request(cls, name, path):
|
||||
c = cls(path)
|
||||
c.manager = QNetworkAccessManager()
|
||||
c.request = c.manager.get(QNetworkRequest())
|
||||
|
||||
locale = get_lang()
|
||||
payload = json.dumps({
|
||||
"query": query,
|
||||
"variables": {"category": "games/edition/base|bundles/games|editors|software/edition/base", "count": 1,
|
||||
"country": "DE", "keywords": name, "locale": locale, "sortDir": "DESC",
|
||||
"allowCountries": locale.upper(),
|
||||
"start": 0, "tag": "", "withMapping": False, "withPrice": True}
|
||||
}).encode()
|
||||
request = QNetworkRequest(QUrl("https://www.epicgames.com/graphql"))
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
c.search_request = c.manager.post(request, payload)
|
||||
c.search_request.finished.connect(lambda: c.handle_response(path))
|
||||
return c
|
||||
|
||||
def handle_response(self, path):
|
||||
if self.search_request:
|
||||
if self.search_request.error() == QNetworkReply.NoError:
|
||||
error = QJsonParseError()
|
||||
json_data = QJsonDocument.fromJson(self.search_request.readAll().data(), error)
|
||||
if QJsonParseError.NoError == error.error:
|
||||
data = json.loads(json_data.toJson().data().decode())["data"]["Catalog"]["searchStore"][
|
||||
"elements"][0]
|
||||
self.init_ui(data, path)
|
||||
else:
|
||||
logging.error(error.errorString())
|
||||
return
|
||||
|
||||
else:
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
query = "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, " \
|
||||
"$keywords: String, $locale: String, $namespace: String, $withMapping: Boolean = false, $itemNs: String, " \
|
||||
"$sortBy: String, $sortDir: String, $start: Int, $tag: String, $releaseDate: String, $withPrice: Boolean = " \
|
||||
|
@ -362,35 +219,3 @@ query = "query searchStoreQuery($allowCountries: String, $category: String, $cou
|
|||
"endDate\n discountSetting {\n discountType\n discountPercentage\n " \
|
||||
" }\n }\n }\n }\n }\n paging {\n count\n " \
|
||||
"total\n }\n }\n }\n}\n "
|
||||
|
||||
game_query = "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, " \
|
||||
"$keywords: String, $locale: String, $namespace: String, $withMapping: Boolean = false, $itemNs: String, " \
|
||||
"$sortBy: String, $sortDir: String, $start: Int, $tag: String, $releaseDate: String, $withPrice: Boolean " \
|
||||
"= false, $withPromotions: Boolean = false, $priceRange: String, $freeGame: Boolean, $onSale: Boolean, " \
|
||||
"$effectiveDate: String) {\n Catalog {\n searchStore(\n allowCountries: $allowCountries\n " \
|
||||
"category: $category\n count: $count\n country: $country\n keywords: $keywords\n " \
|
||||
"locale: $locale\n namespace: $namespace\n itemNs: $itemNs\n sortBy: $sortBy\n " \
|
||||
"sortDir: $sortDir\n releaseDate: $releaseDate\n start: $start\n tag: $tag\n " \
|
||||
"priceRange: $priceRange\n freeGame: $freeGame\n onSale: $onSale\n effectiveDate: " \
|
||||
"$effectiveDate\n ) {\n elements {\n title\n id\n namespace\n " \
|
||||
"description\n effectiveDate\n keyImages {\n type\n url\n }\n " \
|
||||
" currentPrice\n seller {\n id\n name\n }\n productSlug\n " \
|
||||
" urlSlug\n url\n tags {\n id\n }\n items {\n id\n " \
|
||||
" namespace\n }\n customAttributes {\n key\n value\n }\n " \
|
||||
"categories {\n path\n }\n catalogNs @include(if: $withMapping) {\n " \
|
||||
"mappings(pageType: \"productHome\") {\n pageSlug\n pageType\n }\n " \
|
||||
"}\n offerMappings @include(if: $withMapping) {\n pageSlug\n pageType\n " \
|
||||
"}\n price(country: $country) @include(if: $withPrice) {\n totalPrice {\n " \
|
||||
"discountPrice\n originalPrice\n voucherDiscount\n discount\n " \
|
||||
" currencyCode\n currencyInfo {\n decimals\n }\n fmtPrice(" \
|
||||
"locale: $locale) {\n originalPrice\n discountPrice\n " \
|
||||
"intermediatePrice\n }\n }\n lineOffers {\n appliedRules {\n " \
|
||||
" id\n endDate\n discountSetting {\n discountType\n " \
|
||||
" }\n }\n }\n }\n promotions(category: $category) @include(if: " \
|
||||
"$withPromotions) {\n promotionalOffers {\n promotionalOffers {\n " \
|
||||
"startDate\n endDate\n discountSetting {\n discountType\n " \
|
||||
" discountPercentage\n }\n }\n }\n " \
|
||||
"upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n " \
|
||||
"endDate\n discountSetting {\n discountType\n " \
|
||||
"discountPercentage\n }\n }\n }\n }\n }\n paging {\n " \
|
||||
" count\n total\n }\n }\n }\n}\n "
|
||||
|
|
145
rare/ui/components/tabs/store/browse_games.py
Normal file
145
rare/ui/components/tabs/store/browse_games.py
Normal file
|
@ -0,0 +1,145 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'browse_games.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.4
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_browse_games(object):
|
||||
def setupUi(self, browse_games):
|
||||
browse_games.setObjectName("browse_games")
|
||||
browse_games.resize(706, 541)
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(browse_games)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.games_gb = QtWidgets.QGroupBox(browse_games)
|
||||
self.games_gb.setObjectName("games_gb")
|
||||
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.games_gb)
|
||||
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||
self.stack = QtWidgets.QStackedWidget(self.games_gb)
|
||||
self.stack.setObjectName("stack")
|
||||
self.games_page = QtWidgets.QWidget()
|
||||
self.games_page.setObjectName("games_page")
|
||||
self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.games_page)
|
||||
self.verticalLayout_5.setObjectName("verticalLayout_5")
|
||||
self.games = QtWidgets.QScrollArea(self.games_page)
|
||||
self.games.setWidgetResizable(True)
|
||||
self.games.setObjectName("games")
|
||||
self.scrollAreaWidgetContents = QtWidgets.QWidget()
|
||||
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 394, 306))
|
||||
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
|
||||
self.games.setWidget(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout_5.addWidget(self.games)
|
||||
self.stack.addWidget(self.games_page)
|
||||
self.error = QtWidgets.QWidget()
|
||||
self.error.setObjectName("error")
|
||||
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.error)
|
||||
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||
self.error_label = QtWidgets.QLabel(self.error)
|
||||
self.error_label.setObjectName("error_label")
|
||||
self.verticalLayout_6.addWidget(self.error_label)
|
||||
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout_6.addItem(spacerItem)
|
||||
self.stack.addWidget(self.error)
|
||||
self.verticalLayout_4.addWidget(self.stack)
|
||||
self.horizontalLayout_2.addWidget(self.games_gb)
|
||||
self.filter_gb = QtWidgets.QGroupBox(browse_games)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.filter_gb.sizePolicy().hasHeightForWidth())
|
||||
self.filter_gb.setSizePolicy(sizePolicy)
|
||||
self.filter_gb.setMaximumSize(QtCore.QSize(200, 16777215))
|
||||
self.filter_gb.setFlat(False)
|
||||
self.filter_gb.setCheckable(False)
|
||||
self.filter_gb.setObjectName("filter_gb")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(self.filter_gb)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.filter_scroll = QtWidgets.QScrollArea(self.filter_gb)
|
||||
self.filter_scroll.setWidgetResizable(True)
|
||||
self.filter_scroll.setObjectName("filter_scroll")
|
||||
self.scroll_widget = QtWidgets.QWidget()
|
||||
self.scroll_widget.setGeometry(QtCore.QRect(0, 0, 174, 479))
|
||||
self.scroll_widget.setObjectName("scroll_widget")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.scroll_widget)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.price_gb = QtWidgets.QGroupBox(self.scroll_widget)
|
||||
self.price_gb.setObjectName("price_gb")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.price_gb)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.clear_price = QtWidgets.QRadioButton(self.price_gb)
|
||||
self.clear_price.setChecked(True)
|
||||
self.clear_price.setObjectName("clear_price")
|
||||
self.verticalLayout_2.addWidget(self.clear_price)
|
||||
self.free_button = QtWidgets.QRadioButton(self.price_gb)
|
||||
self.free_button.setObjectName("free_button")
|
||||
self.verticalLayout_2.addWidget(self.free_button)
|
||||
self.under10 = QtWidgets.QRadioButton(self.price_gb)
|
||||
self.under10.setObjectName("under10")
|
||||
self.verticalLayout_2.addWidget(self.under10)
|
||||
self.under20 = QtWidgets.QRadioButton(self.price_gb)
|
||||
self.under20.setObjectName("under20")
|
||||
self.verticalLayout_2.addWidget(self.under20)
|
||||
self.under30 = QtWidgets.QRadioButton(self.price_gb)
|
||||
self.under30.setObjectName("under30")
|
||||
self.verticalLayout_2.addWidget(self.under30)
|
||||
self.above = QtWidgets.QRadioButton(self.price_gb)
|
||||
self.above.setObjectName("above")
|
||||
self.verticalLayout_2.addWidget(self.above)
|
||||
self.on_discount = QtWidgets.QRadioButton(self.price_gb)
|
||||
self.on_discount.setObjectName("on_discount")
|
||||
self.verticalLayout_2.addWidget(self.on_discount)
|
||||
self.verticalLayout_3.addWidget(self.price_gb)
|
||||
self.platform_gb = QtWidgets.QGroupBox(self.scroll_widget)
|
||||
self.platform_gb.setObjectName("platform_gb")
|
||||
self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.platform_gb)
|
||||
self.verticalLayout_7.setObjectName("verticalLayout_7")
|
||||
self.win_cb = QtWidgets.QCheckBox(self.platform_gb)
|
||||
self.win_cb.setObjectName("win_cb")
|
||||
self.verticalLayout_7.addWidget(self.win_cb)
|
||||
self.mac_cb = QtWidgets.QCheckBox(self.platform_gb)
|
||||
self.mac_cb.setObjectName("mac_cb")
|
||||
self.verticalLayout_7.addWidget(self.mac_cb)
|
||||
self.verticalLayout_3.addWidget(self.platform_gb)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout_3.addItem(spacerItem1)
|
||||
self.filter_scroll.setWidget(self.scroll_widget)
|
||||
self.verticalLayout.addWidget(self.filter_scroll)
|
||||
self.horizontalLayout_2.addWidget(self.filter_gb)
|
||||
|
||||
self.retranslateUi(browse_games)
|
||||
self.stack.setCurrentIndex(1)
|
||||
QtCore.QMetaObject.connectSlotsByName(browse_games)
|
||||
|
||||
def retranslateUi(self, browse_games):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
browse_games.setWindowTitle(_translate("browse_games", "Form"))
|
||||
self.games_gb.setTitle(_translate("browse_games", "Games"))
|
||||
self.error_label.setText(_translate("browse_games", "An error occured"))
|
||||
self.filter_gb.setTitle(_translate("browse_games", "Filter"))
|
||||
self.price_gb.setTitle(_translate("browse_games", "Price"))
|
||||
self.clear_price.setText(_translate("browse_games", "Clear price filter"))
|
||||
self.free_button.setText(_translate("browse_games", "Free"))
|
||||
self.under10.setText(_translate("browse_games", "Under 10"))
|
||||
self.under20.setText(_translate("browse_games", "Under 20"))
|
||||
self.under30.setText(_translate("browse_games", "Under 30"))
|
||||
self.above.setText(_translate("browse_games", "14.99 and above"))
|
||||
self.on_discount.setText(_translate("browse_games", "Discount"))
|
||||
self.platform_gb.setTitle(_translate("browse_games", "Platform"))
|
||||
self.win_cb.setText(_translate("browse_games", "Windows"))
|
||||
self.mac_cb.setText(_translate("browse_games", "Mac"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
browse_games = QtWidgets.QWidget()
|
||||
ui = Ui_browse_games()
|
||||
ui.setupUi(browse_games)
|
||||
browse_games.show()
|
||||
sys.exit(app.exec_())
|
225
rare/ui/components/tabs/store/browse_games.ui
Normal file
225
rare/ui/components/tabs/store/browse_games.ui
Normal file
|
@ -0,0 +1,225 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>browse_games</class>
|
||||
<widget class="QWidget" name="browse_games">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>706</width>
|
||||
<height>541</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="games_gb">
|
||||
<property name="title">
|
||||
<string>Games</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stack">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="games_page">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="games">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>394</width>
|
||||
<height>306</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="error">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="error_label">
|
||||
<property name="text">
|
||||
<string>An error occured</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<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>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="filter_gb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="filter_scroll">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scroll_widget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>174</width>
|
||||
<height>479</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="price_gb">
|
||||
<property name="title">
|
||||
<string>Price</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="clear_price">
|
||||
<property name="text">
|
||||
<string>Clear price filter</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="free_button">
|
||||
<property name="text">
|
||||
<string>Free</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="under10">
|
||||
<property name="text">
|
||||
<string>Under 10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="under20">
|
||||
<property name="text">
|
||||
<string>Under 20</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="under30">
|
||||
<property name="text">
|
||||
<string>Under 30</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="above">
|
||||
<property name="text">
|
||||
<string>14.99 and above</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="on_discount">
|
||||
<property name="text">
|
||||
<string>Discount</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="platform_gb">
|
||||
<property name="title">
|
||||
<string>Platform</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="win_cb">
|
||||
<property name="text">
|
||||
<string>Windows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mac_cb">
|
||||
<property name="text">
|
||||
<string>Mac</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</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>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -35,6 +35,9 @@ class Ui_shop_info(object):
|
|||
self.dev.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.dev.setObjectName("dev")
|
||||
self.verticalLayout_2.addWidget(self.dev)
|
||||
self.owned_label = QtWidgets.QLabel(shop_info)
|
||||
self.owned_label.setObjectName("owned_label")
|
||||
self.verticalLayout_2.addWidget(self.owned_label)
|
||||
self.price = QtWidgets.QLabel(shop_info)
|
||||
self.price.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.price.setObjectName("price")
|
||||
|
@ -69,6 +72,7 @@ class Ui_shop_info(object):
|
|||
self.back_button.setText(_translate("shop_info", "Back"))
|
||||
self.title.setText(_translate("shop_info", "Error"))
|
||||
self.dev.setText(_translate("shop_info", "TextLabel"))
|
||||
self.owned_label.setText(_translate("shop_info", "You already own this game"))
|
||||
self.price.setText(_translate("shop_info", "TextLabel"))
|
||||
self.discount_price.setText(_translate("shop_info", "TextLabel"))
|
||||
self.open_store_button.setText(_translate("shop_info", "Buy Game in Epic Games Store"))
|
||||
|
|
|
@ -52,6 +52,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="owned_label">
|
||||
<property name="text">
|
||||
<string>You already own this game</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="price">
|
||||
<property name="text">
|
||||
|
|
Loading…
Reference in a new issue