1
0
Fork 0
mirror of synced 2024-05-18 19:42:54 +12:00
Rare/rare/components/tabs/store/shop_widget.py
2023-12-12 13:02:07 +02:00

368 lines
12 KiB
Python

import datetime
import logging
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import (
QGroupBox,
QScrollArea,
QCheckBox,
QLabel,
QPushButton,
QHBoxLayout,
)
from legendary.core import LegendaryCore
from rare.ui.components.tabs.store.store import Ui_ShopWidget
from rare.utils.extra_widgets import WaitingSpinner, ButtonLineEdit
from rare.widgets.flow_layout import FlowLayout
from .constants import Constants
from .game_widgets import GameWidget
from .shop_api_core import ShopApiCore
from .shop_models import BrowseModel
logger = logging.getLogger("Shop")
# noinspection PyAttributeOutsideInit,PyBroadException
class ShopWidget(QScrollArea, Ui_ShopWidget):
show_info = pyqtSignal(str)
show_game = pyqtSignal(dict)
free_game_widgets = []
active_search_request = False
next_search = ""
wishlist: list = []
def __init__(self, path, core: LegendaryCore, shop_api: ShopApiCore):
super(ShopWidget, self).__init__()
self.setWidgetResizable(True)
self.setupUi(self)
self.path = path
self.core = core
self.api_core = shop_api
self.price = ""
self.tags = []
self.types = []
self.update_games_allowed = True
self.free_widget.setLayout(FlowLayout())
self.free_stack.addWidget(WaitingSpinner())
self.free_stack.setCurrentIndex(1)
self.discount_widget.setLayout(FlowLayout())
self.discount_stack.addWidget(WaitingSpinner())
self.discount_stack.setCurrentIndex(1)
self.game_widget.setLayout(FlowLayout())
self.game_stack.addWidget(WaitingSpinner())
self.game_stack.setCurrentIndex(1)
self.search_bar = ButtonLineEdit(
"fa.search", placeholder_text=self.tr("Search Games")
)
self.layout().insertWidget(0, self.search_bar)
# self.search_bar.textChanged.connect(self.search_games)
self.search_bar.returnPressed.connect(self.show_search_results)
self.search_bar.buttonClicked.connect(self.show_search_results)
self.init_filter()
self.search_bar.setHidden(True)
self.filter_gb.setHidden(True)
self.filter_game_gb.setHidden(True)
# self.search_bar.textChanged.connect(self.load_completer)
def load(self):
# load free games
self.api_core.get_free_games(self.add_free_games)
# load wishlist
self.api_core.get_wishlist(self.add_wishlist_items)
# load browse games
self.prepare_request()
def update_wishlist(self):
self.api_core.get_wishlist(self.add_wishlist_items)
def add_wishlist_items(self, wishlist):
for i in range(self.discount_widget.layout().count()):
item = self.discount_widget.layout().itemAt(i)
if item:
item.widget().deleteLater()
if wishlist and wishlist[0] == "error":
self.discount_widget.layout().addWidget(
QLabel(self.tr("Failed to get wishlist: {}").format(wishlist[1]))
)
btn = QPushButton(self.tr("Reload"))
self.discount_widget.layout().addWidget(btn)
btn.clicked.connect(
lambda: self.api_core.get_wishlist(self.add_wishlist_items)
)
self.discount_stack.setCurrentIndex(0)
return
discounts = 0
for game in wishlist:
if not game:
continue
try:
if game["offer"]["price"]["totalPrice"]["discount"] > 0:
w = GameWidget(self.path, game["offer"])
w.show_info.connect(self.show_game.emit)
self.discount_widget.layout().addWidget(w)
discounts += 1
except Exception as e:
logger.warning(f"{game} {e}")
continue
self.discounts_gb.setVisible(discounts > 0)
self.discount_stack.setCurrentIndex(0)
# fix widget overlay
self.discount_widget.layout().update()
def add_free_games(self, free_games: list):
for i in range(self.free_widget.layout().count()):
item = self.free_widget.layout().itemAt(i)
if item:
item.widget().deleteLater()
if free_games and free_games[0] == "error":
self.free_widget.layout().addWidget(
QLabel(self.tr("Failed to fetch free games: {}").format(free_games[1]))
)
btn = QPushButton(self.tr("Reload"))
self.free_widget.layout().addWidget(btn)
btn.clicked.connect(
lambda: self.api_core.get_free_games(self.add_free_games)
)
self.free_stack.setCurrentIndex(0)
return
self.free_games_now = QGroupBox(self.tr("Now Free"))
self.free_games_now.setLayout(QHBoxLayout())
self.free_widget.layout().addWidget(self.free_games_now)
self.coming_free_games = QGroupBox(self.tr("Free Games next week"))
self.coming_free_games.setLayout(QHBoxLayout())
self.free_widget.layout().addWidget(self.coming_free_games)
date = datetime.datetime.now()
free_games_now = []
coming_free_games = []
for game in free_games:
try:
if (
game["price"]["totalPrice"]["fmtPrice"]["discountPrice"] == "0"
and game["price"]["totalPrice"]["fmtPrice"]["originalPrice"]
!= game["price"]["totalPrice"]["fmtPrice"]["discountPrice"]
):
free_games_now.append(game)
continue
if game["title"] == "Mystery Game":
coming_free_games.append(game)
continue
except KeyError as e:
logger.warning(str(e))
try:
# parse datetime to check if game is next week or now
try:
start_date = datetime.datetime.strptime(
game["promotions"]["upcomingPromotionalOffers"][0][
"promotionalOffers"
][0]["startDate"],
"%Y-%m-%dT%H:%M:%S.%fZ",
)
except Exception:
try:
start_date = datetime.datetime.strptime(
game["promotions"]["promotionalOffers"][0][
"promotionalOffers"
][0]["startDate"],
"%Y-%m-%dT%H:%M:%S.%fZ",
)
except Exception as e:
continue
except TypeError:
print("type error")
continue
if start_date > date:
coming_free_games.append(game)
# free games now
now_free = 0
for free_game in free_games_now:
w = GameWidget(self.path, free_game)
w.show_info.connect(self.show_game.emit)
self.free_games_now.layout().addWidget(w)
self.free_game_widgets.append(w)
now_free += 1
if now_free == 0:
self.free_games_now.layout().addWidget(
QLabel(self.tr("Could not find current free game"))
)
# free games next week
for free_game in coming_free_games:
w = GameWidget(self.path, free_game)
if free_game["title"] != "Mystery Game":
w.show_info.connect(self.show_game.emit)
self.coming_free_games.layout().addWidget(w)
# self.coming_free_games.setFixedWidth(int(40 + len(coming_free_games) * 300))
self.free_stack.setCurrentIndex(0)
def show_search_results(self):
if self.search_bar.text():
self.show_info.emit(self.search_bar.text())
def init_filter(self):
self.none_price.toggled.connect(
lambda: self.prepare_request("") if self.none_price.isChecked() else None
)
self.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.on_discount.toggled.connect(lambda: self.prepare_request())
constants = Constants()
self.checkboxes = []
for groupbox, variables in [
(self.genre_gb, constants.categories),
(self.platform_gb, constants.platforms),
(self.others_gb, constants.others),
(self.type_gb, constants.types),
]:
for text, tag in variables:
checkbox = CheckBox(text, tag)
checkbox.activated.connect(lambda x: self.prepare_request(added_tag=x))
checkbox.deactivated.connect(
lambda x: self.prepare_request(removed_tag=x)
)
groupbox.layout().addWidget(checkbox)
self.checkboxes.append(checkbox)
self.reset_button.clicked.connect(self.reset_filters)
def reset_filters(self):
self.update_games_allowed = False
for cb in self.checkboxes:
cb.setChecked(False)
self.none_price.setChecked(True)
self.tags = []
self.types = []
self.update_games_allowed = True
self.prepare_request("")
self.on_discount.setChecked(False)
def prepare_request(
self,
price: str = None,
added_tag: int = 0,
removed_tag: int = 0,
added_type: str = "",
removed_type: str = "",
):
if not self.update_games_allowed:
return
if price is not None:
self.price = price
if added_tag != 0:
self.tags.append(added_tag)
if removed_tag != 0 and removed_tag in self.tags:
self.tags.remove(removed_tag)
if added_type:
self.types.append(added_type)
if removed_type and removed_type in self.types:
self.types.remove(removed_type)
if (self.types or self.price) or self.tags or self.on_discount.isChecked():
self.free_game_group_box.setVisible(False)
self.discounts_gb.setVisible(False)
else:
self.free_game_group_box.setVisible(True)
if len(self.discounts_gb.layout().children()) > 0:
self.discounts_gb.setVisible(True)
self.game_stack.setCurrentIndex(1)
browse_model = BrowseModel(
language_code=self.core.language_code,
country_code=self.core.country_code,
count=20,
price=self.price,
onSale=self.on_discount.isChecked(),
)
browse_model.tag = "|".join(self.tags)
if self.types:
browse_model.category = "|".join(self.types)
self.api_core.browse_games(browse_model, self.show_games)
def show_games(self, data):
for item in (
self.game_widget.layout().itemAt(i)
for i in range(self.game_widget.layout().count())
):
item.widget().deleteLater()
if data:
for game in data:
w = GameWidget(self.path, game, 275)
self.game_widget.layout().addWidget(w)
w.show_info.connect(self.show_game.emit)
else:
self.game_widget.layout().addWidget(
QLabel(self.tr("Could not get games matching the filter"))
)
self.game_stack.setCurrentIndex(0)
self.game_widget.layout().update()
class CheckBox(QCheckBox):
activated = pyqtSignal(str)
deactivated = pyqtSignal(str)
def __init__(self, text, tag):
super(CheckBox, self).__init__(text)
self.tag = tag
self.toggled.connect(self.handle_toggle)
def handle_toggle(self):
if self.isChecked():
self.activated.emit(self.tag)
else:
self.deactivated.emit(self.tag)