"Module Juungle App" import sys import os from datetime import datetime import tempfile import requests from PyQt5.QtWidgets import QMainWindow, QComboBox # pylint: disable= no-name-in-module from PyQt5.QtWidgets import QApplication, QGridLayout # pylint: disable= no-name-in-module from PyQt5.QtWidgets import QLabel, QCompleter, QLineEdit, QWidget # pylint: disable= no-name-in-module from PyQt5.QtWidgets import QGroupBox, QVBoxLayout, QHBoxLayout # pylint: disable= no-name-in-module from PyQt5.QtGui import QPixmap # pylint: disable= no-name-in-module from PyQt5.QtCore import Qt # pylint: disable= no-name-in-module from nft import NFTDB from juungle.nft import NFTs # pylint: disable=import-error from juungle import __version__ as juungle_version CACHE_DIR_PATH = '{}/juungle-cache'.format(tempfile.gettempdir()) VERSION = '0.5.2' MIN_JUUNGLE_VERSION = '0.6.2' def version_tuple(version): """Convert string into version""" return tuple(map(int, version.split('.'))) if version_tuple(juungle_version) < version_tuple(MIN_JUUNGLE_VERSION): MSG = ('Juungle package should be higher than {}. Package version is' ' {}. \nRun "python3 -m pip install -U juungle"') print(MSG.format(MIN_JUUNGLE_VERSION, juungle_version)) sys.exit(1) def cache_exists(file_id): """ Check if the file already exists. """ if not os.path.isdir(CACHE_DIR_PATH): os.mkdir(CACHE_DIR_PATH) return os.path.isfile('{}/{}'.format(CACHE_DIR_PATH, file_id)) class PyQtLayout(QMainWindow): def __init__(self, nfts): super().__init__() self.nfts = NFTDB(nfts) self.info_nfts = nfts self.initUI() self.id_names = {} title = ('Juungle.net UI v{} BETA ' '- Last update: {}').format(VERSION, datetime.now()) self.setWindowTitle(title) def initUI(self): """initUI""" widget = QWidget() # main_menu = self.menuBar() # main_menu.addMenu('Options') vbox = QVBoxLayout() self.search_edit = QLineEdit() self.search_edit.setPlaceholderText('Search by name...') self.search_edit.returnPressed.connect(self.update_search) vbox.addWidget(self.search_edit) self.min_value = QLineEdit() self.min_value.setPlaceholderText('Min value in BCH') self.min_value.returnPressed.connect(self.update_search_price) vbox.addWidget(self.min_value) self.max_value = QLineEdit() self.max_value.setPlaceholderText('Max value in BCH') self.max_value.returnPressed.connect(self.update_search_price) vbox.addWidget(self.max_value) def add_combo(label, items): hbox = QHBoxLayout() l_label = QLabel(label) l_label.adjustSize() hbox.addWidget(l_label) combo = QComboBox(widget) for i in items: combo.addItem(i[0], i[1]) combo.currentIndexChanged.connect(self.update_options) hbox.addWidget(combo) return hbox, combo hbox, self.own_nft = add_combo( 'Types', [('All', None), ('Only mine', True), ('Not mine', False)] ) vbox.addLayout(hbox) hbox, self.options = add_combo( 'For sale?', [('All', None), ('For Sale', None), ('Sold/Not for sale', None)] ) vbox.addLayout(hbox) hbox = QHBoxLayout() l_label = QLabel('NFT Group') hbox.addWidget(l_label) self.cb_group = QComboBox(widget) self.update_group_cb() self.cb_group.currentIndexChanged.connect(self.update_options) hbox.addWidget(self.cb_group) vbox.addLayout(hbox) filter_gb = QGroupBox('Filters') filter_gb.setLayout(vbox) vbox = QVBoxLayout() hbox = QHBoxLayout() l_label = QLabel('NFT name:') hbox.addWidget(l_label) self.lbl_n_nfts = QLabel('') hbox.addWidget(self.lbl_n_nfts) self.cb_nfts = QComboBox(widget) self.cb_nfts.currentIndexChanged.connect(self.update_image) hbox.addWidget(self.cb_nfts) vbox.addLayout(hbox) self.lbl_image = QLabel(widget) vbox.addWidget(self.lbl_image) image_gb = QGroupBox('Image') image_gb.setLayout(vbox) vbox = QVBoxLayout() self.info_box = { "name": QLabel('NFTName', widget), "price": QLabel('Price', widget), "price_history": QLabel('', widget), } self.info_box['price_history'].setFixedWidth(200) vbox.addWidget(self.info_box['name']) vbox.addWidget(self.info_box['price']) vbox.addWidget(self.info_box['price_history']) info_gb = QGroupBox('Info') info_gb.setLayout(vbox) main_grid = QGridLayout(widget) main_grid.addWidget(filter_gb, 0, 0) main_grid.addWidget(image_gb, 0, 1) main_grid.addWidget(info_gb, 0, 2) widget.setLayout(main_grid) self.setCentralWidget(widget) self.update_options(0) self.show() def update_search(self): self.cb_nfts.setCurrentText(self.search_edit.text()) self.search_edit.clear() def update_search_price(self): self.update_options(self.options.currentIndex()) def update_group_cb(self): self.cb_group.clear() self.cb_group.addItem('All', None) for group in self.nfts.get_groups(): self.cb_group.addItem(group[0], group[1]) def update_options(self, _): self.cb_nfts.clear() self.id_names = {} self.search_edit.clear() cb_index = self.options.currentIndex() for nft in self.nfts.get_nfts(mine=self.own_nft.currentData(), group_id=self.cb_group.currentData()): if cb_index == 0: prices_nft = self.nfts.get_nft_history(nft[1], True) price_bch = prices_nft[1] if self.min_value.text(): if not price_bch or price_bch and \ price_bch <= float(self.min_value.text()): continue if self.max_value.text(): if not price_bch or price_bch and \ price_bch >= float(self.max_value.text()): continue self.id_names[nft[0]] = nft[1] if cb_index == 1: if not nft[4]: continue prices_nft = self.nfts.get_nft_history(nft[1], True) price_bch = prices_nft[1] if self.min_value.text(): if not price_bch or price_bch and \ price_bch <= float(self.min_value.text()): continue if self.max_value.text(): if not price_bch or price_bch and \ price_bch >= float(self.max_value.text()): continue self.id_names[nft[0]] = nft[1] if cb_index == 2: if not nft[3]: continue self.id_names[nft[0]] = nft[1] names = sorted(self.id_names.keys()) completer = QCompleter(names) completer.setCaseSensitivity(Qt.CaseInsensitive) self.search_edit.setCompleter(completer) for i in names: self.cb_nfts.addItem(i, self.id_names[i]) msg = "1/{} listed".format(len(names)) self.lbl_n_nfts.setText(msg) self.cb_nfts.setFocus() def update_image(self, index): pixmap = QPixmap() nft = None for i in self.info_nfts: nft = self.info_nfts[i][-1] if self.cb_nfts.itemData(index) == i: break if not nft: print(self.cb_nfts.currentText()) image = None if not cache_exists(nft.token_id): image = requests.get(nft.image, stream=True).content with open('{}/{}'.format(CACHE_DIR_PATH, nft.token_id), 'wb+') as f_image: f_image.write(image) else: with open('{}/{}'.format(CACHE_DIR_PATH, nft.token_id), 'rb') as f_image: image = f_image.read() pixmap.loadFromData(image) img_height = 500 pixmap_resized = pixmap if pixmap.height() > img_height: pixmap_resized = pixmap.scaledToHeight(img_height) self.lbl_image.setPixmap(pixmap_resized) self.info_box['name'].setText('Name: {}'.format(nft.name)) if nft.price_satoshis: price = '{} {}'.format(nft.price_bch, 'BCH') else: price = '-' self.info_box['price'].setText('Price: {}'.format(price)) msg = 'Price history:

' for n in self.nfts.get_nft_history(nft.token_id, order_by='asc'): if n[2]: msg += ('Sold for {} BCH
'.format(n[1])) if n[3]: msg += ('' '{}{} BCH
').format( nft.token_id, 'Click to buy for ', n[1]) self.info_box['price_history'].setText(msg) self.info_box['price_history'].setOpenExternalLinks(True) self.cb_nfts.setFixedWidth(300) msg = "{}/{} listed".format(index, self.cb_nfts.count()) self.lbl_n_nfts.setText(msg) def main(): app = QApplication([]) nfts = NFTs() nfts.get_nfts() ex = PyQtLayout(nfts.group_ids) sys.exit(app.exec_()) if __name__ == '__main__': main()