Compare commits

..
Author SHA1 Message Date
rapeafed b6a7e6a355 WowPlayer preview fix #2 2021-10-21 10:41:43 -04:00
rapeafed 4c55f398db WowPlayer preview fix #1 2021-10-20 15:43:10 -04:00
rapeafed 969fd50408 WowPlayer preview 2021-10-16 05:55:16 -04:00
64 changed files with 2173 additions and 1629 deletions
+5
View File
@@ -10,7 +10,9 @@ set(VERSION_REVISION "0")
set(VERSION "beta-4") set(VERSION "beta-4")
option(FETCH_DEPS "Download dependencies if they are not found" ON) option(FETCH_DEPS "Download dependencies if they are not found" ON)
option(XMRIG "Include XMRig module")
option(OPENVR "Include OpenVR support") option(OPENVR "Include OpenVR support")
option(QML "Include QtQuick (QML)")
option(ANDROID "Android deployment") option(ANDROID "Android deployment")
option(ANDROID_DEBUG "View the Android app on desktop") option(ANDROID_DEBUG "View the Android app on desktop")
option(TOR_BIN "Path to Tor binary to embed inside WOWlet") option(TOR_BIN "Path to Tor binary to embed inside WOWlet")
@@ -31,6 +33,9 @@ set(BUILD_GUI_DEPS ON)
set(BUILD_64 ON CACHE BOOL "Build 64-bit binaries") set(BUILD_64 ON CACHE BOOL "Build 64-bit binaries")
set(INSTALL_VENDORED_LIBUNBOUND ${STATIC}) set(INSTALL_VENDORED_LIBUNBOUND ${STATIC})
set(USE_SINGLE_BUILDDIR ON) set(USE_SINGLE_BUILDDIR ON)
if(OPENVR OR ANDROID_DEBUG)
set(QML ON)
endif()
# Are we in debug mode? # Are we in debug mode?
set(_CMAKE_BUILD_TYPE "") set(_CMAKE_BUILD_TYPE "")
+48 -16
View File
@@ -39,7 +39,11 @@ file(GLOB SOURCE_FILES
"dialog/*.cpp" "dialog/*.cpp"
) )
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Quick QuickWidgets Qml QuickControls2 QuickCompiler QmlImportScanner Multimedia) if(QML)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Quick Qml QuickControls2 QmlImportScanner Multimedia MultimediaWidgets)
else()
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Multimedia MultimediaWidgets)
endif()
if(OPENVR) if(OPENVR)
# include some extra files # include some extra files
@@ -144,6 +148,7 @@ target_include_directories(wowlet PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/utils ${CMAKE_CURRENT_SOURCE_DIR}/utils
${CMAKE_CURRENT_SOURCE_DIR}/tor ${CMAKE_CURRENT_SOURCE_DIR}/tor
${CMAKE_CURRENT_SOURCE_DIR}/qrcode ${CMAKE_CURRENT_SOURCE_DIR}/qrcode
${CMAKE_CURRENT_SOURCE_DIR}/widgets
${X11_INCLUDE_DIR} ${X11_INCLUDE_DIR}
${Boost_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR}
@@ -154,6 +159,8 @@ target_include_directories(wowlet PUBLIC
${Qt5Svg_INCLUDE_DIRS} ${Qt5Svg_INCLUDE_DIRS}
${Qt5Xml_INCLUDE_DIRS} ${Qt5Xml_INCLUDE_DIRS}
${Qt5WebSockets_INCLUDE_DIRS} ${Qt5WebSockets_INCLUDE_DIRS}
${Qt5Multimedia_INCLUDE_DIRS}
${Qt5MultimediaWidgets_INCLUDE_DIRS}
) )
if(OPENVR) if(OPENVR)
@@ -168,6 +175,10 @@ if(TOR_BIN)
target_compile_definitions(wowlet PRIVATE HAS_TOR_BIN=1) target_compile_definitions(wowlet PRIVATE HAS_TOR_BIN=1)
endif() endif()
if(XMRIG)
target_compile_definitions(wowlet PRIVATE HAS_XMRIG=1)
endif()
if(ANDROID) if(ANDROID)
target_compile_definitions(wowlet PRIVATE HAS_ANDROID=1) target_compile_definitions(wowlet PRIVATE HAS_ANDROID=1)
endif() endif()
@@ -208,7 +219,10 @@ endif()
target_compile_definitions(wowlet PUBLIC VR_API_PUBLIC) target_compile_definitions(wowlet PUBLIC VR_API_PUBLIC)
qt5_import_qml_plugins(${PROJECT_NAME}) if(QML)
qt5_import_qml_plugins(${PROJECT_NAME})
target_compile_definitions(wowlet PRIVATE HAS_QML=1)
endif()
target_compile_definitions(wowlet target_compile_definitions(wowlet
PUBLIC PUBLIC
@@ -219,6 +233,8 @@ target_compile_definitions(wowlet
${Qt5Svg_DEFINITIONS} ${Qt5Svg_DEFINITIONS}
${Qt5Xml_DEFINITIONS} ${Qt5Xml_DEFINITIONS}
${Qt5WebSockets_DEFINITIONS} ${Qt5WebSockets_DEFINITIONS}
${Qt5Multimedia_DEFINITIONS}
${Qt5MultimediaWidgets_DEFINITIONS}
) )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
@@ -249,20 +265,34 @@ target_link_libraries(wowlet PUBLIC
${EXTRA_LIBRARIES}) ${EXTRA_LIBRARIES})
# Link Qt libraries # Link Qt libraries
target_link_libraries(wowlet PUBLIC if(QML)
Qt5::Core target_link_libraries(wowlet PUBLIC
Qt5::Widgets Qt5::Core
Qt5::Gui Qt5::Widgets
Qt5::Network Qt5::Gui
Qt5::Svg Qt5::Network
Qt5::QSvgPlugin Qt5::Svg
Qt5::QSvgIconPlugin Qt5::QSvgPlugin
Qt5::Xml Qt5::QSvgIconPlugin
Qt5::WebSockets Qt5::Xml
Qt5::Quick Qt5::WebSockets
Qt5::Qml Qt5::Quick
Qt5::QuickControls2 Qt5::Qml
Qt5::QuickWidgets) Qt5::QuickControls2
Qt5::Multimedia
Qt5::MultimediaWidgets)
else()
target_link_libraries(wowlet PUBLIC
Qt5::Core
Qt5::Widgets
Qt5::Gui
Qt5::Network
Qt5::Svg
Qt5::Xml
Qt5::WebSockets
Qt5::Multimedia
Qt5::MultimediaWidgets)
endif()
if(ANDROID) if(ANDROID)
# yolo some hardcoded paths # yolo some hardcoded paths
@@ -366,7 +396,9 @@ message(STATUS "VERSION_MAJOR: ${VERSION_MAJOR}")
message(STATUS "VERSION_MINOR: ${VERSION_MINOR}") message(STATUS "VERSION_MINOR: ${VERSION_MINOR}")
message(STATUS "VERSION_REVISION: ${VERSION_REVISION}") message(STATUS "VERSION_REVISION: ${VERSION_REVISION}")
message(STATUS "STATIC: ${STATIC}") message(STATUS "STATIC: ${STATIC}")
message(STATUS "Include QtQuick (QML): ${QML}")
message(STATUS "VERSION: ${VERSION}") message(STATUS "VERSION: ${VERSION}")
message(STATUS "Include the XMRIG tab: ${XMRIG}")
message(STATUS "Include Valve's OpenVR library: ${OPENVR}") message(STATUS "Include Valve's OpenVR library: ${OPENVR}")
message(STATUS "This build is for Android: ${ANDROID}") message(STATUS "This build is for Android: ${ANDROID}")
message(STATUS "This build is for testing the Android app on desktop: ${ANDROID_DEBUG}") message(STATUS "This build is for testing the Android app on desktop: ${ANDROID_DEBUG}")
+11 -34
View File
@@ -100,21 +100,8 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
connect(this, &AppContext::nodeSourceChanged, this->nodes, &Nodes::onNodeSourceChanged); connect(this, &AppContext::nodeSourceChanged, this->nodes, &Nodes::onNodeSourceChanged);
connect(this, &AppContext::setCustomNodes, this->nodes, &Nodes::setCustomNodes); connect(this, &AppContext::setCustomNodes, this->nodes, &Nodes::setCustomNodes);
// init backend URLs // Tor & socks proxy
if(cmdargs->isSet("backend-host")) this->ws = new WSClient(this, wsUrl);
this->backendHost = cmdargs->value("backend-host");
if(cmdargs->isSet("backend-host"))
this->backendPort = cmdargs->value("backend-port").toUInt();
if(cmdargs->isSet("backend-tls"))
this->backendTLS = true;
backendWSUrl = this->backendTLS ? "wss://" : "ws://";
backendWSUrl += QString("%1:%2").arg(this->backendHost).arg(this->backendPort);
backendHTTPUrl = this->backendTLS ? "https://" : "http://";
backendHTTPUrl += QString("%1:%2").arg(this->backendHost).arg(this->backendPort);
// init websocket client
this->ws = new WSClient(this);
connect(this->ws, &WSClient::WSMessage, this, &AppContext::onWSMessage); connect(this->ws, &WSClient::WSMessage, this, &AppContext::onWSMessage);
connect(this->ws, &WSClient::connectionEstablished, this, &AppContext::wsConnected); connect(this->ws, &WSClient::connectionEstablished, this, &AppContext::wsConnected);
connect(this->ws, &WSClient::closed, this, &AppContext::wsDisconnected); connect(this->ws, &WSClient::closed, this, &AppContext::wsDisconnected);
@@ -163,8 +150,10 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
AppContext::prices = new Prices(); AppContext::prices = new Prices();
// XMRig // XMRig
#ifdef HAS_XMRIG
this->XMRig = new XmRig(this->configDirectory, this); this->XMRig = new XmRig(this->configDirectory, this);
this->XMRig->prepare(); this->XMRig->prepare();
#endif
this->walletManager = WalletManager::instance(); this->walletManager = WalletManager::instance();
QString logPath = QString("%1/daemon.log").arg(configDirectory); QString logPath = QString("%1/daemon.log").arg(configDirectory);
@@ -182,25 +171,17 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
// libwallet connects // libwallet connects
connect(this->walletManager, &WalletManager::walletOpened, this, &AppContext::onWalletOpened); connect(this->walletManager, &WalletManager::walletOpened, this, &AppContext::onWalletOpened);
// hideOnClose
auto hideOnClose = config()->get(Config::hideOnClose).toBool();
if(hideOnClose)
QApplication::setQuitOnLastWindowClosed(false);
} }
void AppContext::initTor() { void AppContext::initTor() {
this->tor = new Tor(this, this); this->tor = new Tor(this, this);
this->tor->start(); this->tor->start();
if (!isWhonix && !backendHost.contains(".onion")) { if (!isWhonix && wsUrl.contains(".onion")) {
qDebug() << "'backend-host' did not contain '.onion' - running without Tor proxy."; this->networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
return; this->network->setProxy(*networkProxy);
this->ws->webSocket.setProxy(*networkProxy);
} }
this->networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
this->network->setProxy(*networkProxy);
this->ws->webSocket.setProxy(*networkProxy);
} }
void AppContext::initWS() { void AppContext::initWS() {
@@ -440,19 +421,15 @@ void AppContext::onWSMessage(const QJsonObject &msg) {
if(changed) if(changed)
emit blockHeightWSUpdated(this->heights); emit blockHeightWSUpdated(this->heights);
} }
else if(cmd == "yellwow") {
this->yellowPagesData = msg.value("data").toArray();
emit yellowUpdated();
}
else if(cmd == "rpc_nodes") { else if(cmd == "rpc_nodes") {
this->onWSNodes(msg.value("data").toArray()); this->onWSNodes(msg.value("data").toArray());
} }
#if defined(HAS_XMRIG)
else if(cmd == "xmrig") { else if(cmd == "xmrig") {
this->XMRigDownloads(msg.value("data").toObject()); this->XMRigDownloads(msg.value("data").toObject());
} }
else if(cmd == "wownerod_releases") { #endif
emit WownerodDownloads(msg.value("data").toObject());
}
else if(cmd == "crypto_rates") { else if(cmd == "crypto_rates") {
QJsonArray crypto_rates = msg.value("data").toArray(); QJsonArray crypto_rates = msg.value("data").toArray();
AppContext::prices->cryptoPricesReceived(crypto_rates); AppContext::prices->cryptoPricesReceived(crypto_rates);
+1 -10
View File
@@ -66,13 +66,7 @@ public:
QString defaultWalletDir; QString defaultWalletDir;
QString defaultWalletDirRoot; QString defaultWalletDirRoot;
QString tmpTxDescription; QString tmpTxDescription;
QString wsUrl = "6wku2m4zrv6j666crlo7lzofv6ud6enzllyhou3ijeigpukymi37caad.onion";
// https://git.wownero.com/wowlet/wowlet-backend/
QString backendHost = "6wku2m4zrv6j666crlo7lzofv6ud6enzllyhou3ijeigpukymi37caad.onion";
unsigned int backendPort = 80;
bool backendTLS = false;
QString backendWSUrl;
QString backendHTTPUrl;
QString walletPath; QString walletPath;
QString walletPassword = ""; QString walletPassword = "";
@@ -112,7 +106,6 @@ public:
static QMap<QString, QString> txDescriptionCache; static QMap<QString, QString> txDescriptionCache;
static QMap<QString, QString> txCache; static QMap<QString, QString> txCache;
static TxFiatHistory *txFiatHistory; static TxFiatHistory *txFiatHistory;
QJsonArray yellowPagesData;
QJsonObject versionPending; QJsonObject versionPending;
// libwalletqt // libwalletqt
@@ -212,10 +205,8 @@ signals:
void nodesUpdated(QList<QSharedPointer<WowletNode>> &nodes); void nodesUpdated(QList<QSharedPointer<WowletNode>> &nodes);
void ccsUpdated(QList<QSharedPointer<CCSEntry>> &entries); void ccsUpdated(QList<QSharedPointer<CCSEntry>> &entries);
void suchWowUpdated(const QJsonArray &such_data); void suchWowUpdated(const QJsonArray &such_data);
void yellowUpdated();
void nodeSourceChanged(NodeSource nodeSource); void nodeSourceChanged(NodeSource nodeSource);
void XMRigDownloads(const QJsonObject &data); void XMRigDownloads(const QJsonObject &data);
void WownerodDownloads(const QJsonObject &data);
void pinLookupReceived(QString address, QString pin); void pinLookupReceived(QString address, QString pin);
void pinLookupErrorReceived(); void pinLookupErrorReceived();
void pinReceived(QString pin); void pinReceived(QString pin);
+1 -29
View File
@@ -28,8 +28,6 @@
<file>assets/images/confirmed.svg</file> <file>assets/images/confirmed.svg</file>
<file>assets/images/connect.svg</file> <file>assets/images/connect.svg</file>
<file>assets/images/copy.png</file> <file>assets/images/copy.png</file>
<file>assets/images/dog_running.gif</file>
<file>assets/images/dog_sitting.gif</file>
<file>assets/images/edit.png</file> <file>assets/images/edit.png</file>
<file>assets/images/exchange.png</file> <file>assets/images/exchange.png</file>
<file>assets/images/exchange_white.png</file> <file>assets/images/exchange_white.png</file>
@@ -39,7 +37,6 @@
<file>assets/images/eye_blind.png</file> <file>assets/images/eye_blind.png</file>
<file>assets/images/wowlet.png</file> <file>assets/images/wowlet.png</file>
<file>assets/images/file.png</file> <file>assets/images/file.png</file>
<file>assets/images/fire.png</file>
<file>assets/images/gnome-calc.png</file> <file>assets/images/gnome-calc.png</file>
<file>assets/images/history.png</file> <file>assets/images/history.png</file>
<file>assets/images/info.png</file> <file>assets/images/info.png</file>
@@ -227,32 +224,7 @@
<file>assets/images/xmrig.svg</file> <file>assets/images/xmrig.svg</file>
<file>assets/images/zoom.png</file> <file>assets/images/zoom.png</file>
<file>assets/mnemonic_25_english.txt</file> <file>assets/mnemonic_25_english.txt</file>
<file>assets/videos/do_you_even_wow_special_friend.mp4</file>
<file>assets/restore_heights_wownero_mainnet.txt</file> <file>assets/restore_heights_wownero_mainnet.txt</file>
<file alias="mining/bottom_center_console.png">assets/images/mining/bottom_center_console.png</file>
<file alias="mining/intel.png">assets/images/mining/intel.png</file>
<file alias="mining/amd.png">assets/images/mining/amd.png</file>
<file alias="mining/lowerleft_circle.png">assets/images/mining/lowerleft_circle.png</file>
<file alias="mining/lowerleft.png">assets/images/mining/lowerleft.png</file>
<file alias="mining/lower_repeat.png">assets/images/mining/lower_repeat.png</file>
<file alias="mining/lowerright.png">assets/images/mining/lowerright.png</file>
<file alias="mining/r_bottom.png">assets/images/mining/r_bottom.png</file>
<file alias="mining/r_left.png">assets/images/mining/r_left.png</file>
<file alias="mining/r_right.png">assets/images/mining/r_right.png</file>
<file alias="mining/topleft.png">assets/images/mining/topleft.png</file>
<file alias="mining/topright_bar.png">assets/images/mining/topright_bar.png</file>
<file alias="mining/topright_left.png">assets/images/mining/topright_left.png</file>
<file alias="mining/topright_middle.png">assets/images/mining/topright_middle.png</file>
<file alias="mining/topright_right.png">assets/images/mining/topright_right.png</file>
<file alias="mining/warning.png">assets/images/mining/warning.png</file>
<file alias="mining/axe.png">assets/images/mining/axe.png</file>
<file alias="mining/lowerleft_btn.png">assets/images/mining/lowerleft_btn.png</file>
<file alias="mining/elmo.gif">assets/images/mining/elmo.gif</file>
<file alias="mining/bubble.png">assets/images/mining/bubble.png</file>
<file alias="mining/mining.webp">assets/images/mining/mining.webp</file>
<file alias="fonts/ComicMono.ttf">assets/fonts/ComicMono.ttf</file>
<file alias="fonts/ComicMono-Bold.ttf">assets/fonts/ComicMono-Bold.ttf</file>
<file alias="mining.qml">ui/qml/mining.qml</file>
</qresource> </qresource>
</RCC> </RCC>
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.
+7 -74
View File
@@ -32,22 +32,17 @@ ContactsWidget::ContactsWidget(QWidget *parent) :
this->newContact(); this->newContact();
}); });
// row context menu
m_rowMenu = new QMenu(ui->contacts);
m_rowMenu->addAction(QIcon(":/assets/images/copy.png"), "Copy address", this, &ContactsWidget::copyAddress);
m_rowMenu->addAction(QIcon(":/assets/images/copy.png"), "Copy name", this, &ContactsWidget::copyName);
m_rowMenu->addAction("Pay to", this, &ContactsWidget::payTo);
m_rowMenu->addAction("Delete", this, &ContactsWidget::deleteContact);
connect(ui->contacts, &QTreeView::customContextMenuRequested, [=](const QPoint & point){ connect(ui->contacts, &QTreeView::customContextMenuRequested, [=](const QPoint & point){
QModelIndex index = ui->contacts->indexAt(point); QModelIndex index = ui->contacts->indexAt(point);
if (index.isValid()) { if (index.isValid()) {
auto username = index.model()->data(index.siblingAtColumn(AddressBookModel::Description), Qt::UserRole).toString();
m_rowMenu = new QMenu(ui->contacts);
if(username.contains("(yp)"))
m_rowMenu->addAction(QIcon(":/assets/images/network.png"), "Visit user's YellWOWPage", this, &ContactsWidget::visitYellowPage);
m_rowMenu->addAction(QIcon(":/assets/images/copy.png"), "Copy address", this, &ContactsWidget::copyAddress);
m_rowMenu->addAction(QIcon(":/assets/images/copy.png"), "Copy name", this, &ContactsWidget::copyName);
m_rowMenu->addAction("Pay to", this, &ContactsWidget::payTo);
m_rowMenu->addAction("Delete", this, &ContactsWidget::deleteContact);
m_rowMenu->exec(ui->contacts->viewport()->mapToGlobal(point)); m_rowMenu->exec(ui->contacts->viewport()->mapToGlobal(point));
m_rowMenu->deleteLater();
} }
else { else {
m_contextMenu->exec(ui->contacts->viewport()->mapToGlobal(point)); m_contextMenu->exec(ui->contacts->viewport()->mapToGlobal(point));
@@ -57,68 +52,6 @@ ContactsWidget::ContactsWidget(QWidget *parent) :
connect(ui->search, &QLineEdit::textChanged, this, &ContactsWidget::setSearchFilter); connect(ui->search, &QLineEdit::textChanged, this, &ContactsWidget::setSearchFilter);
} }
QMap<QString, QString> ContactsWidget::data() {
auto rtn = QMap<QString, QString>();
for (int i = 0; i < m_ctx->currentWallet->addressBook()->count(); i++) {
m_ctx->currentWallet->addressBook()->getRow(i, [&rtn](const AddressBookInfo &entry) {
rtn[entry.description()] = entry.address();
});
}
return rtn;
}
unsigned int ContactsWidget::rowIndex(const QString &name) {
// name -> row index lookup
int result = -1;
for (int i = 0; i < m_ctx->currentWallet->addressBook()->count(); i++) {
m_ctx->currentWallet->addressBook()->getRow(i, [i, name, &result](const AddressBookInfo &entry) {
if(entry.description() == name) result = i;
return;
});
if(result != -1)
return result;
}
return result;
}
void ContactsWidget::loadYellowPages() {
if (m_ctx->currentWallet == nullptr || m_ctx->yellowPagesData.empty())
return;
auto contacts = this->data();
for (auto item: m_ctx->yellowPagesData) {
auto obj = item.toObject();
const auto username = QString("%1 (yp)").arg(obj.value("username").toString());
const auto address = obj.value("address").toString();
if(contacts.contains(username)) {
if(contacts[username] == address) continue;
// update the address
auto idx = this->rowIndex(username);
if(idx == -1) continue;
m_model->deleteRow((int)idx);
}
bool addressValid = WalletManager::addressValid(address, m_ctx->currentWallet->nettype());
if (!addressValid) {
continue;
}
m_ctx->currentWallet->addressBook()->addRow(address, "", username);
}
}
void ContactsWidget::visitYellowPage() {
auto index = ui->contacts->currentIndex();
auto username = index.model()->data(
index.siblingAtColumn(AddressBookModel::Description),
Qt::UserRole).toString();
username = username.replace(" (yp)", "").trimmed();
Utils::externalLinkWarning(this, QString("https://yellow.wownero.com/user/%1").arg(username));
}
void ContactsWidget::copyAddress() { void ContactsWidget::copyAddress() {
QModelIndex index = ui->contacts->currentIndex(); QModelIndex index = ui->contacts->currentIndex();
ModelUtils::copyColumn(&index, AddressBookModel::Address); ModelUtils::copyColumn(&index, AddressBookModel::Address);
-5
View File
@@ -22,7 +22,6 @@ class ContactsWidget : public QWidget
public: public:
explicit ContactsWidget(QWidget *parent = nullptr); explicit ContactsWidget(QWidget *parent = nullptr);
void setModel(AddressBookModel * model); void setModel(AddressBookModel * model);
QMap<QString, QString> data();
~ContactsWidget() override; ~ContactsWidget() override;
public slots: public slots:
@@ -31,11 +30,9 @@ public slots:
void payTo(); void payTo();
void newContact(QString address = "", QString name = ""); void newContact(QString address = "", QString name = "");
void deleteContact(); void deleteContact();
void visitYellowPage();
void setShowFullAddresses(bool show); void setShowFullAddresses(bool show);
void setSearchFilter(const QString &filter); void setSearchFilter(const QString &filter);
void resetModel(); void resetModel();
void loadYellowPages();
signals: signals:
void fillAddress(QString &address); void fillAddress(QString &address);
@@ -53,8 +50,6 @@ private:
QMenu *m_headerMenu; QMenu *m_headerMenu;
AddressBookModel * m_model; AddressBookModel * m_model;
AddressBookProxyModel * m_proxyModel; AddressBookProxyModel * m_proxyModel;
unsigned int rowIndex(const QString &name);
}; };
#endif // CONTACTSWIDGET_H #endif // CONTACTSWIDGET_H
-2
View File
@@ -50,7 +50,6 @@ void DebugInfoDialog::updateInfo() {
ui->label_synchronized->setText(m_ctx->currentWallet->synchronized() ? "True" : "False"); ui->label_synchronized->setText(m_ctx->currentWallet->synchronized() ? "True" : "False");
auto node = m_ctx->nodes->connection(); auto node = m_ctx->nodes->connection();
ui->label_websocketURL->setText(m_ctx->backendWSUrl);
ui->label_remoteNode->setText(node.full); ui->label_remoteNode->setText(node.full);
ui->label_walletStatus->setText(this->statusToString(m_ctx->currentWallet->connectionStatus())); ui->label_walletStatus->setText(this->statusToString(m_ctx->currentWallet->connectionStatus()));
ui->label_torStatus->setText(torStatus); ui->label_torStatus->setText(torStatus);
@@ -102,7 +101,6 @@ void DebugInfoDialog::copyToClipboad() {
text += QString("Remote node: %1 \n").arg(ui->label_remoteNode->text()); text += QString("Remote node: %1 \n").arg(ui->label_remoteNode->text());
text += QString("Wallet status: %1 \n").arg(ui->label_walletStatus->text()); text += QString("Wallet status: %1 \n").arg(ui->label_walletStatus->text());
text += QString("Tor status: %1 \n").arg(ui->label_torStatus->text()); text += QString("Tor status: %1 \n").arg(ui->label_torStatus->text());
text += QString("Websocket URL: %1 \n").arg(ui->label_websocketURL->text());
text += QString("Websocket status: %1 \n").arg(ui->label_websocketStatus->text()); text += QString("Websocket status: %1 \n").arg(ui->label_websocketStatus->text());
text += QString("Network type: %1 \n").arg(ui->label_netType->text()); text += QString("Network type: %1 \n").arg(ui->label_netType->text());
+16 -30
View File
@@ -183,14 +183,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="0"> <item row="12" column="0">
<widget class="QLabel" name="label_19"> <widget class="QLabel" name="label_19">
<property name="text"> <property name="text">
<string>Websocket status:</string> <string>Websocket status:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="1"> <item row="12" column="1">
<widget class="QLabel" name="label_websocketStatus"> <widget class="QLabel" name="label_websocketStatus">
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
@@ -200,21 +200,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="14" column="1"> <item row="13" column="1">
<widget class="Line" name="line_3"> <widget class="Line" name="line_3">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="15" column="0"> <item row="14" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Network type:</string> <string>Network type:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="15" column="1"> <item row="14" column="1">
<widget class="QLabel" name="label_netType"> <widget class="QLabel" name="label_netType">
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
@@ -224,14 +224,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="16" column="0"> <item row="15" column="0">
<widget class="QLabel" name="label_23"> <widget class="QLabel" name="label_23">
<property name="text"> <property name="text">
<string>Seed type:</string> <string>Seed type:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="16" column="1"> <item row="15" column="1">
<widget class="QLabel" name="label_seedType"> <widget class="QLabel" name="label_seedType">
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
@@ -241,14 +241,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="17" column="0"> <item row="16" column="0">
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_7">
<property name="text"> <property name="text">
<string>View only:</string> <string>View only:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="17" column="1"> <item row="16" column="1">
<widget class="QLabel" name="label_viewOnly"> <widget class="QLabel" name="label_viewOnly">
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
@@ -258,14 +258,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="21" column="0"> <item row="20" column="0">
<widget class="QLabel" name="label_24"> <widget class="QLabel" name="label_24">
<property name="text"> <property name="text">
<string>Timestamp:</string> <string>Timestamp:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="21" column="1"> <item row="20" column="1">
<widget class="QLabel" name="label_timestamp"> <widget class="QLabel" name="label_timestamp">
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
@@ -275,14 +275,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="20" column="0"> <item row="19" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>Operating system:</string> <string>Operating system:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="20" column="1"> <item row="19" column="1">
<widget class="QLabel" name="label_OS"> <widget class="QLabel" name="label_OS">
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
@@ -292,7 +292,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="19" column="1"> <item row="18" column="1">
<widget class="Line" name="line_4"> <widget class="Line" name="line_4">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@@ -316,34 +316,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="18" column="1"> <item row="17" column="1">
<widget class="QLabel" name="label_primaryOnly"> <widget class="QLabel" name="label_primaryOnly">
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="18" column="0"> <item row="17" column="0">
<widget class="QLabel" name="label_11"> <widget class="QLabel" name="label_11">
<property name="text"> <property name="text">
<string>Primary only:</string> <string>Primary only:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Websocket URL:</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_websocketURL">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
-17
View File
@@ -9,23 +9,6 @@
namespace globals namespace globals
{ {
const qreal cdiv = 1e11; const qreal cdiv = 1e11;
enum Tabs {
HOME = 0,
HISTORY,
SEND,
RECEIVE,
COINS,
CALC,
XMRIG
};
enum TabsHome {
FORUM,
REDDIT,
SUCHWOW,
WFS
};
} }
#endif //WOWLET_GLOBALS_H #endif //WOWLET_GLOBALS_H
+8 -10
View File
@@ -31,7 +31,6 @@ Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
Q_INIT_RESOURCE(assets); Q_INIT_RESOURCE(assets);
qputenv("QML_DISABLE_DISK_CACHE", "1");
#if defined(Q_OS_MAC) && defined(HAS_TOR_BIN) #if defined(Q_OS_MAC) && defined(HAS_TOR_BIN)
Q_INIT_RESOURCE(assets_tor_macos); Q_INIT_RESOURCE(assets_tor_macos);
@@ -108,15 +107,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
QCommandLineOption androidDebugOption(QStringList() << "android-debug", "Start the Android interface without actually running on Android - for debugging purposes. Requires -DANDROID_DEBUG=ON CMake definition."); QCommandLineOption androidDebugOption(QStringList() << "android-debug", "Start the Android interface without actually running on Android - for debugging purposes. Requires -DANDROID_DEBUG=ON CMake definition.");
parser.addOption(androidDebugOption); parser.addOption(androidDebugOption);
QCommandLineOption backendHostOption(QStringList() << "backend-host", "specify your own `wowlet-backend` host", "backend-host");
parser.addOption(backendHostOption);
QCommandLineOption backendPortOption(QStringList() << "backend-port", "specify your own `wowlet-backend` port", "backend-port");
parser.addOption(backendPortOption);
QCommandLineOption backendTLS(QStringList() << "backend-tls", "`wowlet-backend` is running via TLS? 'wss://' and 'https://' will be used.", "backend-tls");
parser.addOption(backendTLS);
auto parsed = parser.parse(argv_); auto parsed = parser.parse(argv_);
if(!parsed) { if(!parsed) {
qCritical() << parser.errorText(); qCritical() << parser.errorText();
@@ -141,8 +131,16 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
#endif #endif
qRegisterMetaType<QVector<QString>>(); qRegisterMetaType<QVector<QString>>();
#ifdef HAS_QML
qputenv("QML_DISABLE_DISK_CACHE", "1");
#endif
#ifdef __ANDROID__ #ifdef __ANDROID__
if(android || androidDebug) { if(android || androidDebug) {
#ifndef HAS_QML
qCritical() << "Wowlet compiled without QML support. Try -DQML=ON";
return 1;
#endif
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication mobile_app(argc, argv); QGuiApplication mobile_app(argc, argv);
auto *ctx = new AppContext(&parser); auto *ctx = new AppContext(&parser);
+26 -50
View File
@@ -108,14 +108,11 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
m_trayIcon = new QSystemTrayIcon(QIcon(":/assets/images/appicons/64x64.png")); m_trayIcon = new QSystemTrayIcon(QIcon(":/assets/images/appicons/64x64.png"));
m_trayIcon->show(); m_trayIcon->show();
m_trayActionHome = new QAction("Show", this);
m_trayActionHome->setStatusTip("Show");
m_trayActionCalc = new QAction("Calc", this); m_trayActionCalc = new QAction("Calc", this);
m_trayActionCalc->setStatusTip("Calculator"); m_trayActionCalc->setStatusTip("Calculator");
m_trayActionSend = new QAction("Send", this); m_trayActionSend = new QAction("Send", this);
m_trayActionSend->setStatusTip("Send a WOW payment"); m_trayActionSend->setStatusTip("Send WOW payment");
m_trayActionHistory = new QAction("History", this); m_trayActionHistory = new QAction("History", this);
m_trayActionHistory->setStatusTip("View incoming transfers"); m_trayActionHistory->setStatusTip("View incoming transfers");
@@ -123,7 +120,6 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
m_trayActionExit = new QAction("Quit", this); m_trayActionExit = new QAction("Quit", this);
m_trayActionExit->setStatusTip("Exit application"); m_trayActionExit->setStatusTip("Exit application");
m_trayMenu.addAction(m_trayActionHome);
m_trayMenu.addAction(m_trayActionSend); m_trayMenu.addAction(m_trayActionSend);
m_trayMenu.addAction(m_trayActionHistory); m_trayMenu.addAction(m_trayActionHistory);
m_trayMenu.addAction(m_trayActionCalc); m_trayMenu.addAction(m_trayActionCalc);
@@ -131,7 +127,6 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
m_trayIcon->setContextMenu(&m_trayMenu); m_trayIcon->setContextMenu(&m_trayMenu);
// @TODO: only init tray *after* boot // @TODO: only init tray *after* boot
connect(m_trayActionHome, &QAction::triggered, this, &MainWindow::showHomeWindow);
connect(m_trayActionCalc, &QAction::triggered, this, &MainWindow::showCalcWindow); connect(m_trayActionCalc, &QAction::triggered, this, &MainWindow::showCalcWindow);
connect(m_trayActionSend, &QAction::triggered, this, &MainWindow::showSendTab); connect(m_trayActionSend, &QAction::triggered, this, &MainWindow::showSendTab);
connect(m_trayActionHistory, &QAction::triggered, this, &MainWindow::showHistoryTab); connect(m_trayActionHistory, &QAction::triggered, this, &MainWindow::showHistoryTab);
@@ -171,25 +166,22 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
connect(m_ctx->nodes, &Nodes::WSNodeExhausted, this, &MainWindow::showWSNodeExhaustedMessage); connect(m_ctx->nodes, &Nodes::WSNodeExhausted, this, &MainWindow::showWSNodeExhaustedMessage);
// XMRig // XMRig
#ifdef HAS_XMRIG
m_xmrig = new XMRigWidget(m_ctx, this); m_xmrig = new XMRigWidget(m_ctx, this);
ui->xmrRigLayout->addWidget(m_xmrig); ui->xmrRigLayout->addWidget(m_xmrig);
connect(m_ctx->XMRig, &XmRig::output, m_xmrig, &XMRigWidget::onProcessOutput); connect(m_ctx->XMRig, &XmRig::output, m_xmrig, &XMRigWidget::onProcessOutput);
connect(m_ctx->XMRig, &XmRig::error, m_xmrig, &XMRigWidget::onProcessError); connect(m_ctx->XMRig, &XmRig::error, m_xmrig, &XMRigWidget::onProcessError);
connect(m_ctx->XMRig, &XmRig::output, m_xmrig, &XMRigWidget::daemonOutput);
connect(m_ctx->XMRig, &XmRig::error, m_xmrig, &XMRigWidget::daemonOutput);
connect(m_ctx->XMRig, &XmRig::blockReward, m_xmrig, &XMRigWidget::onBlockReward);
connect(m_ctx->XMRig, &XmRig::hashrate, m_xmrig, &XMRigWidget::onHashrate); connect(m_ctx->XMRig, &XmRig::hashrate, m_xmrig, &XMRigWidget::onHashrate);
connect(m_ctx->XMRig, &XmRig::daemonStateChanged, m_xmrig, &XMRigWidget::onDaemonStateChanged);
connect(m_ctx->XMRig, &XmRig::syncStatus, m_xmrig, &XMRigWidget::onSyncStatus);
connect(m_ctx->XMRig, &XmRig::uptimeChanged, m_xmrig, &XMRigWidget::onUptimeChanged);
connect(m_ctx->XMRig, &XmRig::daemonStateChanged, [=](DaemonMiningState state) {
m_ctx->setWindowTitle(state >= DaemonMiningState::mining);
});
connect(m_ctx, &AppContext::walletClosed, m_xmrig, &XMRigWidget::onWalletClosed); connect(m_ctx, &AppContext::walletClosed, m_xmrig, &XMRigWidget::onWalletClosed);
connect(m_ctx, &AppContext::walletOpened, m_xmrig, &XMRigWidget::onWalletOpened); connect(m_ctx, &AppContext::walletOpened, m_xmrig, &XMRigWidget::onWalletOpened);
connect(m_ctx, &AppContext::XMRigDownloads, m_xmrig, &XMRigWidget::onRigDownloads); connect(m_ctx, &AppContext::XMRigDownloads, m_xmrig, &XMRigWidget::onDownloads);
connect(m_ctx, &AppContext::WownerodDownloads, m_xmrig, &XMRigWidget::onWownerodDownloads);
connect(m_xmrig, &XMRigWidget::miningStarted, [=]{ m_ctx->setWindowTitle(true); });
connect(m_xmrig, &XMRigWidget::miningEnded, [=]{ m_ctx->setWindowTitle(false); });
#else
ui->tabWidget->setTabVisible(Tabs::XMRIG, false);
#endif
connect(ui->ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen); connect(ui->ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen);
connect(m_ctx, &AppContext::ccsUpdated, ui->ccsWidget->model(), &CCSModel::updateEntries); connect(m_ctx, &AppContext::ccsUpdated, ui->ccsWidget->model(), &CCSModel::updateEntries);
@@ -200,9 +192,8 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
connect(ui->redditWidget, &RedditWidget::setStatusText, this, &MainWindow::setStatusText); connect(ui->redditWidget, &RedditWidget::setStatusText, this, &MainWindow::setStatusText);
connect(ui->tabWidget, &QTabWidget::currentChanged, m_xmrig, &XMRigWidget::onMenuTabChanged);
connect(ui->tabHomeWidget, &QTabWidget::currentChanged, [](int index){ connect(ui->tabHomeWidget, &QTabWidget::currentChanged, [](int index){
config()->set(Config::homeWidget, globals::TabsHome(index)); config()->set(Config::homeWidget, TabsHome(index));
}); });
connect(m_ctx, &AppContext::donationNag, [=]{ connect(m_ctx, &AppContext::donationNag, [=]{
@@ -301,7 +292,7 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
}); });
connect(ui->receiveWidget, &ReceiveWidget::showTransactions, [this](const QString &text) { connect(ui->receiveWidget, &ReceiveWidget::showTransactions, [this](const QString &text) {
ui->historyWidget->setSearchText(text); ui->historyWidget->setSearchText(text);
ui->tabWidget->setCurrentIndex(globals::Tabs::HISTORY); ui->tabWidget->setCurrentIndex(Tabs::HISTORY);
}); });
// History // History
@@ -312,7 +303,6 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
// Contacts // Contacts
connect(ui->contactWidget, &ContactsWidget::fillAddress, ui->sendWidget, &SendWidget::fillAddress); connect(ui->contactWidget, &ContactsWidget::fillAddress, ui->sendWidget, &SendWidget::fillAddress);
connect(m_ctx, &AppContext::yellowUpdated, ui->contactWidget, &ContactsWidget::loadYellowPages);
// Open alias // Open alias
connect(ui->sendWidget, &SendWidget::resolveOpenAlias, m_ctx, &AppContext::onOpenAliasResolve); connect(ui->sendWidget, &SendWidget::resolveOpenAlias, m_ctx, &AppContext::onOpenAliasResolve);
@@ -338,9 +328,9 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
connect(m_ctx, &AppContext::walletAboutToClose, [=]{ connect(m_ctx, &AppContext::walletAboutToClose, [=]{
if (!config()->get(Config::showTabHome).toBool()) if (!config()->get(Config::showTabHome).toBool())
ui->tabWidget->setCurrentIndex(globals::Tabs::HISTORY); ui->tabWidget->setCurrentIndex(Tabs::HISTORY);
else else
ui->tabWidget->setCurrentIndex(globals::Tabs::HOME); ui->tabWidget->setCurrentIndex(Tabs::HOME);
// Clear all tables when wallet is closed // Clear all tables when wallet is closed
ui->historyWidget->resetModel(); ui->historyWidget->resetModel();
@@ -425,9 +415,13 @@ void MainWindow::initMenu() {
m_tabShowHideMapper["Calc"] = new ToggleTab(ui->tabCalc, "Calc", "Calc", ui->actionShow_calc, Config::showTabCalc); m_tabShowHideMapper["Calc"] = new ToggleTab(ui->tabCalc, "Calc", "Calc", ui->actionShow_calc, Config::showTabCalc);
m_tabShowHideSignalMapper->setMapping(ui->actionShow_calc, "Calc"); m_tabShowHideSignalMapper->setMapping(ui->actionShow_calc, "Calc");
#if defined(HAS_XMRIG)
connect(ui->actionShow_XMRig, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); connect(ui->actionShow_XMRig, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
m_tabShowHideMapper["Mining"] = new ToggleTab(ui->tabXmrRig, "Mining", "Mining", ui->actionShow_XMRig, Config::showTabXMRig); m_tabShowHideMapper["Mining"] = new ToggleTab(ui->tabXmrRig, "Mining", "Mining", ui->actionShow_XMRig, Config::showTabXMRig);
m_tabShowHideSignalMapper->setMapping(ui->actionShow_XMRig, "Mining"); m_tabShowHideSignalMapper->setMapping(ui->actionShow_XMRig, "Mining");
#else
ui->actionShow_XMRig->setVisible(false);
#endif
for (const auto &key: m_tabShowHideMapper.keys()) { for (const auto &key: m_tabShowHideMapper.keys()) {
const auto toggleTab = m_tabShowHideMapper.value(key); const auto toggleTab = m_tabShowHideMapper.value(key);
@@ -526,7 +520,7 @@ void MainWindow::menuToggleTabVisible(const QString &key){
void MainWindow::initWidgets() { void MainWindow::initWidgets() {
int homeWidget = config()->get(Config::homeWidget).toInt(); int homeWidget = config()->get(Config::homeWidget).toInt();
ui->tabHomeWidget->setCurrentIndex(globals::TabsHome(homeWidget)); ui->tabHomeWidget->setCurrentIndex(TabsHome(homeWidget));
} }
WalletWizard *MainWindow::createWizard(WalletWizard::Page startPage){ WalletWizard *MainWindow::createWizard(WalletWizard::Page startPage){
@@ -638,7 +632,6 @@ void MainWindow::onWalletOpened(Wallet *wallet) {
// contacts widget // contacts widget
ui->contactWidget->setModel(m_ctx->currentWallet->addressBookModel()); ui->contactWidget->setModel(m_ctx->currentWallet->addressBookModel());
ui->contactWidget->loadYellowPages();
// coins page // coins page
m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount());
@@ -973,6 +966,7 @@ void MainWindow::menuNewRestoreClicked() {
void MainWindow::menuQuitClicked() { void MainWindow::menuQuitClicked() {
cleanupBeforeClose(); cleanupBeforeClose();
QCoreApplication::quit(); QCoreApplication::quit();
} }
@@ -1042,16 +1036,9 @@ void MainWindow::skinChanged(const QString &skinName) {
} }
void MainWindow::closeEvent(QCloseEvent *event) { void MainWindow::closeEvent(QCloseEvent *event) {
auto hideOnClose = config()->get(Config::hideOnClose).toBool();
if(hideOnClose && !this->isHidden()) {
this->hide();
event->ignore();
return;
}
cleanupBeforeClose(); cleanupBeforeClose();
QWidget::closeEvent(event); QWidget::closeEvent(event);
QApplication::exit();
} }
void MainWindow::donateButtonClicked() { void MainWindow::donateButtonClicked() {
@@ -1060,35 +1047,25 @@ void MainWindow::donateButtonClicked() {
donation = 0.1337; donation = 0.1337;
ui->sendWidget->fill(m_ctx->donationAddress, "Donation to the WOWlet development team", donation); ui->sendWidget->fill(m_ctx->donationAddress, "Donation to the WOWlet development team", donation);
ui->tabWidget->setCurrentIndex(globals::Tabs::SEND); ui->tabWidget->setCurrentIndex(Tabs::SEND);
} }
void MainWindow::showHistoryTab() { void MainWindow::showHistoryTab() {
this->raise(); this->raise();
this->show(); ui->tabWidget->setCurrentIndex(Tabs::HISTORY);
ui->tabWidget->setCurrentIndex(globals::Tabs::HISTORY);
} }
void MainWindow::showSendTab() { void MainWindow::showSendTab() {
this->raise(); this->raise();
this->show(); ui->tabWidget->setCurrentIndex(Tabs::SEND);
ui->tabWidget->setCurrentIndex(globals::Tabs::SEND);
}
void MainWindow::showHomeWindow() {
this->raise();
this->show();
ui->tabWidget->setCurrentIndex(globals::Tabs::HOME);
} }
void MainWindow::showCalcWindow() { void MainWindow::showCalcWindow() {
this->raise();
this->show();
m_windowCalc->show(); m_windowCalc->show();
} }
void MainWindow::payToMany() { void MainWindow::payToMany() {
ui->tabWidget->setCurrentIndex(globals::Tabs::SEND); ui->tabWidget->setCurrentIndex(Tabs::SEND);
ui->sendWidget->payToMany(); ui->sendWidget->payToMany();
QMessageBox::information(this, "Pay to many", "Enter a list of outputs in the 'Pay to' field.\n" QMessageBox::information(this, "Pay to many", "Enter a list of outputs in the 'Pay to' field.\n"
"One output per line.\n" "One output per line.\n"
@@ -1098,7 +1075,7 @@ void MainWindow::payToMany() {
void MainWindow::showSendScreen(const CCSEntry &entry) { void MainWindow::showSendScreen(const CCSEntry &entry) {
ui->sendWidget->fill(entry); ui->sendWidget->fill(entry);
ui->tabWidget->setCurrentIndex(globals::Tabs::SEND); ui->tabWidget->setCurrentIndex(Tabs::SEND);
} }
void MainWindow::suchDonate(const QString address) { void MainWindow::suchDonate(const QString address) {
@@ -1106,7 +1083,7 @@ void MainWindow::suchDonate(const QString address) {
QString preferredCurrency = config()->get(Config::preferredFiatCurrency).toString(); QString preferredCurrency = config()->get(Config::preferredFiatCurrency).toString();
double donation = AppContext::prices->convert(preferredCurrency, "WOW", tipAmount); double donation = AppContext::prices->convert(preferredCurrency, "WOW", tipAmount);
ui->sendWidget->fill(address, "SuchWow contribution :-)", donation); ui->sendWidget->fill(address, "SuchWow contribution :-)", donation);
ui->tabWidget->setCurrentIndex(globals::Tabs::SEND); ui->tabWidget->setCurrentIndex(Tabs::SEND);
} }
void MainWindow::onViewOnBlockExplorer(const QString &txid) { void MainWindow::onViewOnBlockExplorer(const QString &txid) {
@@ -1283,7 +1260,6 @@ void MainWindow::importOutputs() {
void MainWindow::cleanupBeforeClose() { void MainWindow::cleanupBeforeClose() {
m_ctx->closeWallet(false, true); m_ctx->closeWallet(false, true);
m_ctx->tor->stop(); m_ctx->tor->stop();
m_ctx->XMRig->stop();
this->saveGeo(); this->saveGeo();
} }
+17 -3
View File
@@ -33,7 +33,6 @@
#include "utils/config.h" #include "utils/config.h"
#include "wizard/walletwizard.h" #include "wizard/walletwizard.h"
#include "settings.h" #include "settings.h"
#include "globals.h"
#include "dialog/aboutdialog.h" #include "dialog/aboutdialog.h"
#include "dialog/signverifydialog.h" #include "dialog/signverifydialog.h"
#include "dialog/verifyproofdialog.h" #include "dialog/verifyproofdialog.h"
@@ -75,6 +74,23 @@ public:
qreal screenDpiPhysical; qreal screenDpiPhysical;
qreal screenRatio; qreal screenRatio;
enum Tabs {
HOME = 0,
HISTORY,
SEND,
RECEIVE,
COINS,
CALC,
XMRIG
};
enum TabsHome {
FORUM,
REDDIT,
SUCHWOW,
WFS
};
public slots: public slots:
void initWidgets(); void initWidgets();
void initMenu(); void initMenu();
@@ -93,7 +109,6 @@ public slots:
void showViewOnlyDialog(); void showViewOnlyDialog();
void donateButtonClicked(); void donateButtonClicked();
void showCalcWindow(); void showCalcWindow();
void showHomeWindow();
void payToMany(); void payToMany();
void showWalletCacheDebugDialog(); void showWalletCacheDebugDialog();
void showSendTab(); void showSendTab();
@@ -185,7 +200,6 @@ private:
QSystemTrayIcon *m_trayIcon; QSystemTrayIcon *m_trayIcon;
QMenu m_trayMenu; QMenu m_trayMenu;
QAction *m_trayActionHome;
QAction *m_trayActionCalc; QAction *m_trayActionCalc;
QAction *m_trayActionExit; QAction *m_trayActionExit;
QAction *m_trayActionSend; QAction *m_trayActionSend;
+49 -14
View File
@@ -181,6 +181,35 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_player">
<attribute name="title">
<string>WowPlayer</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_player">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="WowPlayerWidget" name="wowPlayerWidget" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>320</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab"> <widget class="QWidget" name="tab">
<attribute name="title"> <attribute name="title">
<string>WFS</string> <string>WFS</string>
@@ -316,20 +345,6 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tabXmrRig">
<attribute name="icon">
<iconset resource="assets.qrc">
<normaloff>:/assets/images/mining.png</normaloff>:/assets/images/mining.png</iconset>
</attribute>
<attribute name="title">
<string>Mining</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="xmrRigLayout"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabCalc"> <widget class="QWidget" name="tabCalc">
<attribute name="icon"> <attribute name="icon">
<iconset resource="assets.qrc"> <iconset resource="assets.qrc">
@@ -344,6 +359,20 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tabXmrRig">
<attribute name="icon">
<iconset resource="assets.qrc">
<normaloff>:/assets/images/mining.png</normaloff>:/assets/images/mining.png</iconset>
</attribute>
<attribute name="title">
<string>Mining</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="xmrRigLayout"/>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
</layout> </layout>
@@ -784,6 +813,12 @@
<header>widgets/suchwowwidget.h</header> <header>widgets/suchwowwidget.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>WowPlayerWidget</class>
<extends>QWidget</extends>
<header>widgets/wowplayerwidget.h</header>
<container>1</container>
</customwidget>
<customwidget> <customwidget>
<class>ForumWidget</class> <class>ForumWidget</class>
<extends>QWidget</extends> <extends>QWidget</extends>
-6
View File
@@ -30,11 +30,6 @@ Settings::Settings(QWidget *parent) :
m_ctx->updateBalance(); m_ctx->updateBalance();
}); });
connect(ui->checkBox_hideOnClose, &QCheckBox::toggled, [this](bool toggled){
config()->set(Config::hideOnClose, toggled);
QApplication::setQuitOnLastWindowClosed(toggled);
});
connect(ui->closeButton, &QDialogButtonBox::accepted, this, &Settings::close); connect(ui->closeButton, &QDialogButtonBox::accepted, this, &Settings::close);
// nodes // nodes
@@ -45,7 +40,6 @@ Settings::Settings(QWidget *parent) :
// setup checkboxes // setup checkboxes
ui->checkBox_externalLink->setChecked(config()->get(Config::warnOnExternalLink).toBool()); ui->checkBox_externalLink->setChecked(config()->get(Config::warnOnExternalLink).toBool());
ui->checkBox_hideBalance->setChecked(config()->get(Config::hideBalance).toBool()); ui->checkBox_hideBalance->setChecked(config()->get(Config::hideBalance).toBool());
ui->checkBox_hideOnClose->setChecked(config()->get(Config::hideOnClose).toBool());
// setup comboboxes // setup comboboxes
this->setupSkinCombobox(); this->setupSkinCombobox();
-7
View File
@@ -198,13 +198,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0">
<widget class="QCheckBox" name="checkBox_hideOnClose">
<property name="text">
<string>Hide application on close</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_node"> <widget class="QWidget" name="tab_node">
-678
View File
@@ -1,678 +0,0 @@
import QtQuick 2.7
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.3
Rectangle {
id: root
color: "#181725"
anchors.fill: parent
property variant buffer: []
property int bufferMaxLength: 12
// state: 0:idle 1:startup 2:syncing 3:mining
signal startMining();
signal stopMining();
Component.onCompleted: {
calcAvailableHeightConsoleLines();
}
onHeightChanged: {
calcAvailableHeightConsoleLines();
}
function calcAvailableHeightConsoleLines() {
var max_lines = parseInt(textContainer.height / 20);
if(root.bufferMaxLength != max_lines && max_lines >= 4)
root.bufferMaxLength = max_lines;
}
// width: 980
// height: 480
Column {
FontLoader { id: comicMono; source: "qrc:/fonts/ComicMono.ttf" }
FontLoader { id: comicMonoBold; source: "qrc:/fonts/ComicMono-Bold.ttf" }
}
ColumnLayout {
width: parent.width
height: parent.height
spacing: 0
RowLayout {
spacing: 0
Layout.fillWidth: true
Layout.preferredHeight: 128
Image {
source: "qrc:/mining/topleft.png"
Layout.preferredWidth: 435
Layout.preferredHeight: 128
smooth: false
// top-left monitors
ColumnLayout {
width: 102
height: 74
anchors.left: parent.left
anchors.leftMargin: 14
anchors.top: parent.top
anchors.topMargin: 42
Rectangle {
color: "transparent"
Layout.fillWidth: true
Layout.fillHeight: true
Text {
text: "Hashrate"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 4
font.pointSize: 14
font.family: comicMonoBold.name;
antialiasing: false
color: "#41FF00"
}
}
Rectangle {
color: "transparent"
Layout.fillWidth: true
Layout.fillHeight: true
Text {
id: hashRateText
text: "-"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 4
font.pointSize: 16
font.family: comicMono.name;
antialiasing: false
color: "#41FF00"
}
}
}
ColumnLayout {
width: 102
height: 74
anchors.left: parent.left
anchors.leftMargin: 142
anchors.top: parent.top
anchors.topMargin: 42
Rectangle {
color: "transparent"
Layout.fillWidth: true
Layout.fillHeight: true
Text {
text: "uptime"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 4
font.pointSize: 14
font.family: comicMonoBold.name;
antialiasing: false
color: "#41FF00"
}
}
Rectangle {
color: "transparent"
Layout.fillWidth: true
Layout.fillHeight: true
Text {
id: miningUptime
text: "-"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 4
font.pointSize: 12
font.family: comicMono.name;
antialiasing: false
color: "#41FF00"
}
}
}
AnimatedImage {
visible: mining.daemonMiningState !== 0
source: "qrc:/mining/mining.webp"
fillMode: Image.PreserveAspectCrop
width: 115
height: 86
anchors.left: parent.left
anchors.leftMargin: 263
anchors.top: parent.top
anchors.topMargin: 34
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.preferredHeight: 128
spacing: 0
Image {
source: "qrc:/mining/warning.png"
Layout.fillWidth: true
Layout.preferredHeight: 15
fillMode: Image.TileHorizontally
smooth: false
}
Image {
source: "qrc:/mining/topright_bar.png"
Layout.fillWidth: true
Layout.preferredHeight: 4
fillMode: Image.TileHorizontally
smooth: false
}
RowLayout {
spacing: 0
Layout.fillHeight: true
Layout.preferredHeight: 102
Image {
Layout.preferredWidth: 5
Layout.preferredHeight: parent.height
source: "qrc:/mining/topright_left.png"
smooth: false
}
Image {
Layout.fillWidth: true
Layout.preferredHeight: parent.height
source: "qrc:/mining/topright_middle.png"
fillMode: Image.TileHorizontally
smooth: false
RowLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.leftMargin: 6
anchors.right: parent.right
anchors.rightMargin: 8
anchors.topMargin: 12
height: 78
spacing: 16
ColumnLayout {
Layout.minimumWidth: 200
Layout.maximumWidth: 260
Layout.fillHeight: true
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
Text {
text: "Block Height"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 8
font.pointSize: 20
font.family: comicMonoBold.name;
color: "#41FF00"
antialiasing: false
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
Text {
id: heightText
text: "-"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 8
font.pointSize: 18
font.family: comicMonoBold.name;
color: "#41FF00"
antialiasing: false
}
}
}
ColumnLayout {
Layout.minimumWidth: 200
Layout.maximumWidth: 260
Layout.fillHeight: true
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
Text {
text: "Sync Progress"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 8
font.pointSize: 20
font.family: comicMonoBold.name;
color: "#41FF00"
antialiasing: false
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "transparent"
Text {
id: syncPctText
text: "-"
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
font.pointSize: 18
font.family: comicMonoBold.name;
color: "#41FF00"
antialiasing: false
}
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}
Image {
Layout.preferredWidth: 5
Layout.preferredHeight: parent.height
source: "qrc:/mining/topright_right.png"
smooth: false
}
}
Item {
Layout.preferredHeight: 7 // 15 + 4 + 102 + 7 = 128
Layout.fillWidth: true
}
}
}
RowLayout {
spacing: 0
//Layout.preferredHeight: 128
Layout.fillHeight: true
Layout.fillWidth: true
Image {
Layout.preferredWidth: 6
Layout.fillHeight: true
source: "qrc:/mining/r_left.png"
fillMode: Image.TileVertically
smooth: false
}
Item {
// text container
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
id: textContainer
color: "transparent"
height: parent.height - 20
width: parent.width - 32
clip: true
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
Text {
id: cons
anchors.margins: 4
anchors.fill: parent
text: "Miner is idle."
font.pointSize: 12
font.family: comicMono.name;
wrapMode: Text.WordWrap
color: "white"
}
}
}
Image {
Layout.preferredWidth: 6
Layout.fillHeight: true
source: "qrc:/mining/r_right.png"
fillMode: Image.TileVertically
smooth: false
}
}
RowLayout {
spacing: 0
Layout.preferredHeight: 140
Layout.fillWidth: true
Image {
Layout.preferredWidth: 306
Layout.preferredHeight: 140
source: "qrc:/mining/lowerleft.png"
smooth: false
AnimatedImage {
source: mining.daemonMiningState === 0 ? "qrc:/assets/images/dog_sitting.gif" : "qrc:/assets/images/dog_running.gif"
width: 80
height: 60
anchors.bottom: parent.bottom
anchors.bottomMargin: 22
anchors.left: parent.left
anchors.leftMargin: 22
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
showBubble();
}
onExited: {
hideBubble();
}
}
}
}
Image {
Layout.fillWidth: true
Layout.preferredHeight: 140
source: "qrc:/mining/lower_repeat.png"
fillMode: Image.TileHorizontally
smooth: false
}
Image {
Layout.preferredWidth: 236
Layout.preferredHeight: 140
source: "qrc:/mining/bottom_center_console.png"
smooth: false
Rectangle {
// middle console clock
anchors.left: parent.left
anchors.leftMargin: 100
anchors.top: parent.top
anchors.topMargin: 8
color: "transparent"
width: 54
height: 16
Text {
id: clock
text: ""
antialiasing: false
font.pointSize: 9
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.family: comicMonoBold.name;
color: "#41FF00";
Component.onCompleted: {
root.setClock();
}
}
}
Image {
source: {
var imgs = ["qrc:/mining/amd.png", "qrc:/mining/intel.png"];
return imgs[Math.floor(Math.random()*imgs.length)];
}
width: 100
height: 100
fillMode: Image.Pad
smooth: false
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
}
Image {
Layout.fillWidth: true
Layout.preferredHeight: 140
source: "qrc:/mining/lower_repeat.png"
fillMode: Image.TileHorizontally
smooth: false
}
Image {
Layout.preferredWidth: 308
Layout.preferredHeight: 140
source: "qrc:/mining/lowerright.png"
smooth: false
Rectangle {
// lower-right button container
color: "transparent"
width: 106
height: 100
anchors.right: parent.right
anchors.rightMargin: 11
anchors.top: parent.top
anchors.topMargin: 34
Image {
id: imgAxe
visible: mining.daemonMiningState === 0
source: "qrc:/mining/axe.png"
width: 73
height: 75
smooth: false
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
}
AnimatedImage {
visible: mining.daemonMiningState !== 0
source: "qrc:/mining/elmo.gif"
width: 106
height: 100
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Text {
id: stopMiningBtn
visible: true
text: "Stop Mining"
font.pointSize: 10
z: parent.z + 1
color: "black"
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 28
font.family: comicMonoBold.name;
antialiasing: false
}
}
MouseArea {
anchors.fill: parent
z: parent.z + 1
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if(mining.daemonMiningState === 0) {
root.startMining();
root.calcAvailableHeightConsoleLines();
}
else
root.stopMining();
}
onEntered: {
imgAxe.height = 64
imgAxe.width = 64
}
onExited: {
imgAxe.height = 75
imgAxe.width = 73
}
}
}
}
}
}
Image {
id: bubble
visible: false
source: "qrc:/mining/bubble.png"
width: 200
height: 60
anchors.bottom: parent.bottom
anchors.bottomMargin: 64
anchors.left: parent.left
anchors.leftMargin: 48
Rectangle {
anchors.top: parent.top
anchors.topMargin: 6
anchors.left: parent.left
anchors.leftMargin: 10
height: 26
color: "transparent"
width: 183
z: parent.z + 1
Text {
id: bubbleText
text: ""
color: "black"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
//font.family: ComicMonoBold.name;
}
}
}
Timer {
id: setClockTimer
interval: 1000*60
running: true
repeat: true
onTriggered: setClock()
}
Timer {
id: dogBubbleTimer
interval: 1000*30
running: true
repeat: true
onTriggered: {
if(Math.random() >= 0.5) return;
if(bubble.visible) return;
root.dogBubbleRemoval.stop();
root.dogBubbleRemoval.start();
var msg = root.bubbleMessage();
bubbleText.text = msg;
bubble.visible = true;
}
}
Timer {
id: dogBubbleRemoval
interval: 2500
running: false
repeat: false
onTriggered: bubble.visible = false;
}
function setClock() {
var now = new Date();
var hours = now.getHours();
var minutes = ('0'+now.getMinutes()).slice(-2);
clock.text = hours + ":" + minutes;
}
function resetComponents() {
hashRateText.text = "-";
miningUptime.text = "-";
syncPctText.text = "-";
heightText.text = "-";
}
function consoleAppend(line) {
if(root.buffer.length >= root.bufferMaxLength)
root.buffer.shift()
root.buffer.push(line);
cons.text = "";
for(var i = 0; i != root.bufferMaxLength; i++) {
if(root.buffer[i])
cons.text += root.buffer[i] + "\n";
}
}
Connections {
target: mining
function onDaemonOutput(line) {
root.consoleAppend(line);
}
function onSyncStatus(from, to, pct) {
syncPctText.text = pct + "%";
heightText.text = from + "/" + to;
}
function onUptimeChanged(uptime) {
miningUptime.text = uptime;
}
function onHashrate(hashrate) {
hashRateText.text = hashrate;
}
}
function showBubble() {
if(bubble.visible) return;
var msg = root.bubbleMessage();
bubbleText.text = msg;
bubble.visible = true;
}
function hideBubble() {
bubble.visible = false;
}
function bubbleMessage() {
var active = ["such work!", "mining WOW!", "woof woof!", "I am tired!", "mining :@", "weeeee", "blocks everywhere!", "wooohoo", "working, twerkin'", "looking4blocks", "mining blocks"];
var inactive = ["doing nothing!", "ZzZZzzZ", "wen mining?!", "ETA mining?!", "zZZzzZZz", "omg so bored", "so bored!!", "much idle, many zZz", "lets go!", "i'm ready!"];
var syncing = ["wen 1gbit", "syncin'", "zZzz", "ETA sync ready?!", "downloading blocks", "fetching blocks"];
var msg = "";
if(mining.daemonMiningState === 0) {
return inactive[Math.floor(Math.random()*inactive.length)];
} else if (mining.daemonMiningState === 2) {
return syncing[Math.floor(Math.random()*syncing.length)];
} else {
return active[Math.floor(Math.random()*active.length)];
}
}
}
+2 -4
View File
@@ -33,21 +33,19 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::autoOpenWalletPath,{QS("autoOpenWalletPath"), ""}}, {Config::autoOpenWalletPath,{QS("autoOpenWalletPath"), ""}},
{Config::walletPath,{QS("walletPath"), ""}}, {Config::walletPath,{QS("walletPath"), ""}},
{Config::xmrigPath,{QS("xmrigPath"), ""}}, {Config::xmrigPath,{QS("xmrigPath"), ""}},
{Config::wownerodPath, {QS("wownerodPath"), ""}}, {Config::xmrigPool,{QS("xmrigPool"), "cryptonote.social:2223"}},
{Config::nodes,{QS("nodes"), "{}"}}, {Config::nodes,{QS("nodes"), "{}"}},
{Config::websocketEnabled,{QS("websocketEnabled"), true}}, {Config::websocketEnabled,{QS("websocketEnabled"), true}},
{Config::nodeSource,{QS("nodeSource"), 0}}, {Config::nodeSource,{QS("nodeSource"), 0}},
{Config::useOnionNodes,{QS("useOnionNodes"), false}}, {Config::useOnionNodes,{QS("useOnionNodes"), false}},
{Config::showTabHome,{QS("showTabHome"), true}}, {Config::showTabHome,{QS("showTabHome"), true}},
{Config::showTabCoins,{QS("showTabCoins"), false}}, {Config::showTabCoins,{QS("showTabCoins"), false}},
{Config::showTabXMRig,{QS("showTabXMRig"), true}}, {Config::showTabXMRig,{QS("showTabXMRig"), false}},
{Config::showTabCalc,{QS("showTabCalc"), false}}, {Config::showTabCalc,{QS("showTabCalc"), false}},
{Config::geometry, {QS("geometry"), {}}}, {Config::geometry, {QS("geometry"), {}}},
{Config::windowState, {QS("windowState"), {}}}, {Config::windowState, {QS("windowState"), {}}},
{Config::firstRun,{QS("firstRun"), false}}, {Config::firstRun,{QS("firstRun"), false}},
{Config::hideBalance, {QS("hideBalance"), false}}, {Config::hideBalance, {QS("hideBalance"), false}},
{Config::hideOnClose, {QS("hideOnClose"), false}},
{Config::simplifiedMiningInterface, {QS("simplifiedMiningInterface"), false}},
{Config::hideFiatBalance, {QS("hideFiatBalance"), false}}, {Config::hideFiatBalance, {QS("hideFiatBalance"), false}},
{Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}}, {Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}},
{Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}}, {Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}},
+1 -3
View File
@@ -35,7 +35,7 @@ public:
walletDirectory, walletDirectory,
walletPath, walletPath,
xmrigPath, xmrigPath,
wownerodPath, xmrigPool,
nodes, nodes,
websocketEnabled, websocketEnabled,
nodeSource, nodeSource,
@@ -49,8 +49,6 @@ public:
firstRun, firstRun,
hideBalance, hideBalance,
hideFiatBalance, hideFiatBalance,
hideOnClose,
simplifiedMiningInterface,
redditFrontend, redditFrontend,
showHistorySyncNotice, showHistorySyncNotice,
ignoreUpdateWarning, ignoreUpdateWarning,
+5 -5
View File
@@ -8,18 +8,18 @@
#include "wsclient.h" #include "wsclient.h"
#include "appcontext.h" #include "appcontext.h"
WSClient::WSClient(AppContext *ctx, QObject *parent) : WSClient::WSClient(AppContext *ctx, const QString &url, QObject *parent) :
QObject(parent), QObject(parent),
m_ctx(ctx) { m_ctx(ctx) {
// this class connects to `https://git.wownero.com/wowlet/wowlet-backend/`
connect(&this->webSocket, &QWebSocket::binaryMessageReceived, this, &WSClient::onbinaryMessageReceived); connect(&this->webSocket, &QWebSocket::binaryMessageReceived, this, &WSClient::onbinaryMessageReceived);
connect(&this->webSocket, &QWebSocket::connected, this, &WSClient::onConnected); connect(&this->webSocket, &QWebSocket::connected, this, &WSClient::onConnected);
connect(&this->webSocket, &QWebSocket::disconnected, this, &WSClient::closed); connect(&this->webSocket, &QWebSocket::disconnected, this, &WSClient::closed);
connect(&this->webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &WSClient::onError); connect(&this->webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &WSClient::onError);
m_tor = m_ctx->backendHost.contains(".onion"); m_tor = url.contains(".onion");
this->url = QString("ws://%1/ws").arg(url);
// keep-alive // Keep websocket connection alive
connect(&m_pingTimer, &QTimer::timeout, [this]{ connect(&m_pingTimer, &QTimer::timeout, [this]{
if (this->webSocket.state() == QAbstractSocket::ConnectedState) if (this->webSocket.state() == QAbstractSocket::ConnectedState)
this->webSocket.ping(); this->webSocket.ping();
@@ -40,7 +40,7 @@ void WSClient::start() {
qDebug() << "WebSocket connect:" << url.url(); qDebug() << "WebSocket connect:" << url.url();
#endif #endif
if((m_tor && this->m_ctx->tor->torConnected) || !m_tor) if((m_tor && this->m_ctx->tor->torConnected) || !m_tor)
this->webSocket.open(QString("%1/ws").arg(m_ctx->backendWSUrl)); this->webSocket.open(QUrl(this->url));
if(!this->m_connectionTimer.isActive()) { if(!this->m_connectionTimer.isActive()) {
connect(&this->m_connectionTimer, &QTimer::timeout, this, &WSClient::checkConnection); connect(&this->m_connectionTimer, &QTimer::timeout, this, &WSClient::checkConnection);
+2 -1
View File
@@ -14,10 +14,11 @@ class WSClient : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit WSClient(AppContext *ctx, QObject *parent = nullptr); explicit WSClient(AppContext *ctx, const QString &url, QObject *parent = nullptr);
void start(); void start();
void sendMsg(const QByteArray &data); void sendMsg(const QByteArray &data);
QWebSocket webSocket; QWebSocket webSocket;
QString url;
signals: signals:
void closed(); void closed();
+53 -131
View File
@@ -7,24 +7,17 @@
#include "utils/utils.h" #include "utils/utils.h"
#include "utils/xmrig.h" #include "utils/xmrig.h"
#include "mainwindow.h" #include "appcontext.h"
XmRig::XmRig(const QString &configDir, QObject *parent) : XmRig::XmRig(const QString &configDir, QObject *parent) : QObject(parent) {
QObject(parent), this->rigDir = QDir(configDir).filePath("xmrig");
m_statusTimer(new QTimer(this))
{
m_statusTimer->setInterval(5000);
connect(m_statusTimer, &QTimer::timeout, [this]{
if(daemonMiningState == DaemonMiningState::mining && m_process.state() == QProcess::Running)
m_process.write("status\n");
});
} }
void XmRig::prepare() { void XmRig::prepare() {
m_process.setProcessChannelMode(QProcess::MergedChannels); m_process.setProcessChannelMode(QProcess::MergedChannels);
connect(&m_process, &QProcess::readyReadStandardOutput, this, &XmRig::onHandleProcessOutput); connect(&m_process, &QProcess::readyReadStandardOutput, this, &XmRig::handleProcessOutput);
connect(&m_process, &QProcess::errorOccurred, this, &XmRig::onHandleProcessError); connect(&m_process, &QProcess::errorOccurred, this, &XmRig::handleProcessError);
connect(&m_process, &QProcess::stateChanged, this, &XmRig::onProcessStateChanged); connect(&m_process, &QProcess::stateChanged, this, &XmRig::stateChanged);
} }
void XmRig::stop() { void XmRig::stop() {
@@ -35,145 +28,74 @@ void XmRig::stop() {
m_process.terminate(); m_process.terminate();
#endif #endif
} }
m_statusTimer->stop();
} }
bool XmRig::start(const QString &path, int threads) { void XmRig::start(const QString &path,
m_ctx = MainWindow::getContext(); int threads,
const QString &address,
const QString &username,
const QString &password,
bool tor, bool tls) {
auto state = m_process.state(); auto state = m_process.state();
if (state == QProcess::ProcessState::Running || if (state == QProcess::ProcessState::Running || state == QProcess::ProcessState::Starting) {
state == QProcess::ProcessState::Starting || emit error("Can't start XMRig, already running or starting");
daemonMiningState != DaemonMiningState::idle) { return;
emit error("Can't start wownerod, already running or starting");
return false;
} }
if(path.isEmpty()) { if(path.isEmpty()) {
emit error("wownerod path seems to be empty."); emit error("XmRig->Start path parameter missing.");
return false; return;
} }
if(!Utils::fileExists(path)) { if(!Utils::fileExists(path)) {
emit error(QString("Path to wownerod binary is invalid; file does not exist: %1").arg(path)); emit error(QString("Path to XMRig binary invalid; file does not exist: %1").arg(path));
return false; return;
} }
auto privateSpendKey = m_ctx->currentWallet->getSecretSpendKey();
QStringList arguments; QStringList arguments;
arguments << "--mining-threads" << QString::number(threads); arguments << "-o" << address;
arguments << "--start-mining" << m_ctx->currentWallet->address(0, 0); arguments << "-a" << "rx/wow";
arguments << "--spendkey" << privateSpendKey; arguments << "-u" << username;
if(!password.isEmpty())
arguments << "-p" << password;
arguments << "--no-color";
arguments << "-t" << QString::number(threads);
if(tor)
arguments << "-x" << QString("%1:%2").arg(Tor::torHost).arg(Tor::torPort);
if(tls)
arguments << "--tls";
arguments << "--donate-level" << "1";
QString cmd = QString("%1 %2").arg(path, arguments.join(" ")); QString cmd = QString("%1 %2").arg(path, arguments.join(" "));
cmd = cmd.replace(privateSpendKey, "[redacted]");
emit output(cmd.toUtf8()); emit output(cmd.toUtf8());
m_process.start(path, arguments); m_process.start(path, arguments);
m_statusTimer->start();
return true;
} }
void XmRig::onProcessStateChanged(QProcess::ProcessState state) { void XmRig::stateChanged(QProcess::ProcessState state) {
if(state == QProcess::ProcessState::Running) { if(state == QProcess::ProcessState::Running)
emit output("wownerod started"); emit output("XMRig started");
changeDaemonState(DaemonMiningState::startup); else if (state == QProcess::ProcessState::NotRunning)
} emit output("XMRig stopped");
else if (state == QProcess::ProcessState::NotRunning) { }
emit output("wownerod stopped");
changeDaemonState(DaemonMiningState::idle); void XmRig::handleProcessOutput() {
QByteArray _output = m_process.readAllStandardOutput();
if(_output.contains("miner") && _output.contains("speed")) {
// detect hashrate
auto str = Utils::barrayToString(_output);
auto spl = str.mid(str.indexOf("speed")).split(" ");
auto rate = spl.at(2) + "H/s";
qDebug() << "mining hashrate: " << rate;
emit hashrate(rate);
} }
emit output(_output);
} }
void XmRig::onHandleProcessOutput() { void XmRig::handleProcessError(QProcess::ProcessError err) {
QByteArray data = m_process.readAllStandardOutput();
for(auto &line: data.split('\n')) {
// remove timestamp
if(line.indexOf("\tI") >= 20)
line = line.remove(0, line.indexOf("\tI") + 2);
line = line.trimmed();
// sad attempt at removing ANSI color codes
// yes this is stupid, no i dont care
// works remarkably well so far lmao
auto ansi_start = QByteArray("\x1b\x5b");
line = line.replace(ansi_start, "");
line = line.replace("0;36m", "");
line = line.replace("0;35m", "");
line = line.replace("0;34m", "");
line = line.replace("0;33m", "");
line = line.replace("0;32m", "");
line = line.replace("1;32m", "");
line = line.replace("1;33m", "");
line = line.replace("1;34m", "");
line = line.replace("1;35m", "");
line = line.replace("1;36m", "");
if(line.startsWith("0m")) continue;
auto lower = line.toLower();
if(lower.isEmpty() || lower.startsWith("status")) continue;
if(lower.startsWith("the daemon will start synchronizing")) {
changeDaemonState(DaemonMiningState::startup);
} else if(lower.startsWith("synchronization started")) {
changeDaemonState(DaemonMiningState::syncing);
} else if(lower.startsWith("synced") && lower.contains("left")) {
if(daemonMiningState < DaemonMiningState::syncing) changeDaemonState(DaemonMiningState::syncing);
QRegularExpression re("synced (\\d+)\\/(\\d+) \\((\\d+)%, (\\d+) left");
QRegularExpressionMatch match = re.match(lower);
if (match.hasMatch()) {
auto from = match.captured(1);
auto to = match.captured(2);
auto pct = match.captured(3);
m_from = from.toUInt();
m_to = to.toUInt();
emit syncStatus(m_from, m_to, pct.toInt());
}
} else if(lower.contains("mining started. good luck")) {
emit syncStatus(m_to, m_to, 100);
changeDaemonState(DaemonMiningState::mining);
}
else if(lower.contains("you won a block reward"))
emit blockReward();
else if(lower.contains("mining at")) {
QRegularExpression re("Height\\: (\\d+)\\/(\\d+) \\((.*)\\) on mainnet, mining at (.*), net hash .*, uptime (.*)");
QRegularExpressionMatch match = re.match(line);
if (match.hasMatch()) {
m_from = match.captured(1).toUInt();
m_to = match.captured(2).toUInt();
unsigned int pct = match.captured(3).replace("%", "").toDouble();
auto rate = match.captured(4);
auto uptime = match.captured(5).replace(" ", "");
emit uptimeChanged(uptime);
emit syncStatus(m_to, m_to, pct);
emit hashrate(rate);
line = line.remove(0, line.indexOf("mining at"));
}
}
emit output(line.trimmed());
}
}
void XmRig::changeDaemonState(const DaemonMiningState state) {
if(daemonMiningState == state) return;
daemonMiningState = state;
emit daemonStateChanged(daemonMiningState);
}
void XmRig::onHandleProcessError(QProcess::ProcessError err) {
if (err == QProcess::ProcessError::Crashed) if (err == QProcess::ProcessError::Crashed)
emit error("wownerod crashed or killed"); emit error("XMRig crashed or killed");
else if (err == QProcess::ProcessError::FailedToStart) { else if (err == QProcess::ProcessError::FailedToStart) {
auto path = config()->get(Config::wownerodPath).toString(); auto path = config()->get(Config::xmrigPath).toString();
emit error(QString("wownerod binary failed to start: %1").arg(path)); emit error(QString("XMRig binary failed to start: %1").arg(path));
} }
changeDaemonState(DaemonMiningState::idle);
} }
+6 -23
View File
@@ -14,14 +14,6 @@
#include "utils/childproc.h" #include "utils/childproc.h"
enum DaemonMiningState {
idle = 0,
startup,
syncing,
mining
};
class AppContext;
class XmRig : public QObject class XmRig : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -30,33 +22,24 @@ public:
explicit XmRig(const QString &configDir, QObject *parent = nullptr); explicit XmRig(const QString &configDir, QObject *parent = nullptr);
void prepare(); void prepare();
bool start(const QString &path, int threads); void start(const QString &path, int threads, const QString &address, const QString &username, const QString &password, bool tor = false, bool tls = true);
void stop(); void stop();
DaemonMiningState daemonMiningState = DaemonMiningState::idle; QString rigDir;
QString rigPath;
signals: signals:
void error(const QString &msg); void error(const QString &msg);
void output(const QByteArray &data); void output(const QByteArray &data);
void blockReward();
void syncStatus(unsigned int from, unsigned int to, unsigned int pct);
void hashrate(const QString &rate); void hashrate(const QString &rate);
void daemonStateChanged(DaemonMiningState state);
void uptimeChanged(QString &uptime);
private slots: private slots:
void onProcessStateChanged(QProcess::ProcessState); void stateChanged(QProcess::ProcessState);
void onHandleProcessOutput(); void handleProcessOutput();
void onHandleProcessError(QProcess::ProcessError error); void handleProcessError(QProcess::ProcessError error);
private: private:
void changeDaemonState(DaemonMiningState state);
ChildProcess m_process; ChildProcess m_process;
AppContext *m_ctx;
QTimer *m_statusTimer;
unsigned int m_to;
unsigned int m_from;
}; };
#endif //WOWLET_XMRIG_H #endif //WOWLET_XMRIG_H
+1 -1
View File
@@ -19,7 +19,7 @@ SuchWowPost::SuchWowPost(AppContext *ctx, QObject *parent) :
m_ctx(ctx) { m_ctx(ctx) {
m_networkImg = new UtilsNetworking(m_ctx->network, this); m_networkImg = new UtilsNetworking(m_ctx->network, this);
m_networkThumb = new UtilsNetworking(m_ctx->network, this); m_networkThumb = new UtilsNetworking(m_ctx->network, this);
m_weburl = QString("%1/suchwow").arg(this->m_ctx->backendHTTPUrl); m_weburl = QString("http://%1/suchwow").arg(this->m_ctx->wsUrl);
} }
void SuchWowPost::onThumbReceived(QByteArray data) { void SuchWowPost::onThumbReceived(QByteArray data) {
+219
View File
@@ -0,0 +1,219 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "wowplayercontrols.h"
#include <QBoxLayout>
#include <QSlider>
#include <QStyle>
#include <QToolButton>
#include <QComboBox>
#include <QAudio>
PlayerControls::PlayerControls(QWidget *parent)
: QWidget(parent)
{
m_playButton = new QToolButton(this);
m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
connect(m_playButton, &QAbstractButton::clicked, this, &PlayerControls::playClicked);
m_stopButton = new QToolButton(this);
m_stopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop));
m_stopButton->setEnabled(false);
connect(m_stopButton, &QAbstractButton::clicked, this, &PlayerControls::stop);
m_nextButton = new QToolButton(this);
m_nextButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward));
connect(m_nextButton, &QAbstractButton::clicked, this, &PlayerControls::next);
m_previousButton = new QToolButton(this);
m_previousButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward));
connect(m_previousButton, &QAbstractButton::clicked, this, &PlayerControls::previous);
m_muteButton = new QToolButton(this);
m_muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume));
connect(m_muteButton, &QAbstractButton::clicked, this, &PlayerControls::muteClicked);
m_volumeSlider = new QSlider(Qt::Horizontal, this);
m_volumeSlider->setRange(0, 100);
connect(m_volumeSlider, &QSlider::valueChanged, this, &PlayerControls::onVolumeSliderValueChanged);
m_rateBox = new QComboBox(this);
m_rateBox->addItem("0.5x", QVariant(0.5));
m_rateBox->addItem("1.0x", QVariant(1.0));
m_rateBox->addItem("2.0x", QVariant(2.0));
m_rateBox->setCurrentIndex(1);
connect(m_rateBox, QOverload<int>::of(&QComboBox::activated), this, &PlayerControls::updateRate);
QBoxLayout *layout = new QHBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_stopButton);
layout->addWidget(m_previousButton);
layout->addWidget(m_playButton);
layout->addWidget(m_nextButton);
layout->addWidget(m_muteButton);
layout->addWidget(m_volumeSlider);
layout->addWidget(m_rateBox);
setLayout(layout);
}
QMediaPlayer::State PlayerControls::state() const
{
return m_playerState;
}
void PlayerControls::setState(QMediaPlayer::State state)
{
if (state != m_playerState) {
m_playerState = state;
switch (state) {
case QMediaPlayer::StoppedState:
m_stopButton->setEnabled(false);
m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
break;
case QMediaPlayer::PlayingState:
m_stopButton->setEnabled(true);
m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause));
break;
case QMediaPlayer::PausedState:
m_stopButton->setEnabled(true);
m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
break;
}
}
}
int PlayerControls::volume() const
{
qreal linearVolume = QAudio::convertVolume(m_volumeSlider->value() / qreal(100),
QAudio::LogarithmicVolumeScale,
QAudio::LinearVolumeScale);
return qRound(linearVolume * 100);
}
void PlayerControls::setVolume(int volume)
{
qreal logarithmicVolume = QAudio::convertVolume(volume / qreal(100),
QAudio::LinearVolumeScale,
QAudio::LogarithmicVolumeScale);
m_volumeSlider->setValue(qRound(logarithmicVolume * 100));
}
bool PlayerControls::isMuted() const
{
return m_playerMuted;
}
void PlayerControls::setMuted(bool muted)
{
if (muted != m_playerMuted) {
m_playerMuted = muted;
m_muteButton->setIcon(style()->standardIcon(muted
? QStyle::SP_MediaVolumeMuted
: QStyle::SP_MediaVolume));
}
}
void PlayerControls::playClicked()
{
switch (m_playerState) {
case QMediaPlayer::StoppedState:
case QMediaPlayer::PausedState:
emit play();
break;
case QMediaPlayer::PlayingState:
emit pause();
break;
}
}
void PlayerControls::muteClicked()
{
emit changeMuting(!m_playerMuted);
}
qreal PlayerControls::playbackRate() const
{
return m_rateBox->itemData(m_rateBox->currentIndex()).toDouble();
}
void PlayerControls::setPlaybackRate(float rate)
{
for (int i = 0; i < m_rateBox->count(); ++i) {
if (qFuzzyCompare(rate, float(m_rateBox->itemData(i).toDouble()))) {
m_rateBox->setCurrentIndex(i);
return;
}
}
m_rateBox->addItem(QString("%1x").arg(rate), QVariant(rate));
m_rateBox->setCurrentIndex(m_rateBox->count() - 1);
}
void PlayerControls::updateRate()
{
emit changeRate(playbackRate());
}
void PlayerControls::onVolumeSliderValueChanged()
{
emit changeVolume(volume());
}
+109
View File
@@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef PLAYERCONTROLS_H
#define PLAYERCONTROLS_H
#include <QMediaPlayer>
#include <QWidget>
QT_BEGIN_NAMESPACE
class QAbstractButton;
class QAbstractSlider;
class QComboBox;
QT_END_NAMESPACE
class PlayerControls : public QWidget
{
Q_OBJECT
public:
explicit PlayerControls(QWidget *parent = nullptr);
QMediaPlayer::State state() const;
int volume() const;
bool isMuted() const;
qreal playbackRate() const;
public slots:
void setState(QMediaPlayer::State state);
void setVolume(int volume);
void setMuted(bool muted);
void setPlaybackRate(float rate);
signals:
void play();
void pause();
void stop();
void next();
void previous();
void changeVolume(int volume);
void changeMuting(bool muting);
void changeRate(qreal rate);
private slots:
void playClicked();
void muteClicked();
void updateRate();
void onVolumeSliderValueChanged();
private:
QMediaPlayer::State m_playerState = QMediaPlayer::StoppedState;
bool m_playerMuted = false;
QAbstractButton *m_playButton = nullptr;
QAbstractButton *m_stopButton = nullptr;
QAbstractButton *m_nextButton = nullptr;
QAbstractButton *m_previousButton = nullptr;
QAbstractButton *m_muteButton = nullptr;
QAbstractSlider *m_volumeSlider = nullptr;
QComboBox *m_rateBox = nullptr;
};
#endif // PLAYERCONTROLS_H
+568
View File
@@ -0,0 +1,568 @@
//
// Created by rapeafed on 2021.
//
// You may need to build the project (run Qt uic code generator) to get "ui_WowPlayerWidget.h" resolved
#include <QMediaPlaylist>
#include "wowplayercontrols.h"
#include "wowvideowidget.h"
#include "wowplaylistmodel.h"
//#include "wowhistogramwidget.h"
#include <QMediaService>
#include <QVideoProbe>
#include <QAudioProbe>
#include <QMediaMetaData>
#include <QtWidgets>
#include <QVideoWidget>
#include <QStandardItemModel>
#include <QtMultimedia>
#include <QtMultimediaWidgets>
#include <QMediaService>
#include <QMediaPlaylist>
#include <QVideoProbe>
#include <QAudioProbe>
#include <QMediaMetaData>
#include <QtWidgets>
#include <QMediaPlayer>
//#include <QtMultimedia/QMediaPlayer>
#include "wowplayerwidget.h"
#include "ui_wowplayerwidget.h"
WowPlayerWidget::WowPlayerWidget(QWidget *parent) :
QWidget(parent), ui(new Ui::WowPlayerWidget) {
// d = new Private;
// d->mediaPlayer = new QMediaPlayer(this, QMediaPlayer::StreamPlayback);
//d->networkAccessManager = new QNetworkAccessManager(this);
// QMediaPlayer myAudio;
ui->setupUi(this);
//QMediaPlayer *player = new QMediaPlayer();
//! [create-objs]
//QMediaPlayer player = new QMediaPlayer;
//QMediaPlayer *player = new QMediaPlayer();
//m_player = new QMediaPlayer;
//QMediaPlayer *player = new QMediaPlayer;
m_player = new QMediaPlayer(this);
m_player->setAudioRole(QAudio::VideoRole);
qInfo() << "Supported audio roles:";
for (QAudio::Role role : m_player->supportedAudioRoles())
qInfo() << " " << role;
// owned by PlaylistModel
m_playlist = new QMediaPlaylist();
m_player->setPlaylist(m_playlist);
//! [create-objs]
connect(m_player, &QMediaPlayer::durationChanged, this, &WowPlayerWidget::durationChanged);
connect(m_player, &QMediaPlayer::positionChanged, this, &WowPlayerWidget::positionChanged);
connect(m_player, QOverload<>::of(&QMediaPlayer::metaDataChanged), this, &WowPlayerWidget::metaDataChanged);
connect(m_playlist, &QMediaPlaylist::currentIndexChanged, this, &WowPlayerWidget::playlistPositionChanged);
connect(m_player, &QMediaPlayer::mediaStatusChanged, this, &WowPlayerWidget::statusChanged);
connect(m_player, &QMediaPlayer::bufferStatusChanged, this, &WowPlayerWidget::bufferingProgress);
connect(m_player, &QMediaPlayer::videoAvailableChanged, this, &WowPlayerWidget::videoAvailableChanged);
connect(m_player, QOverload<QMediaPlayer::Error>::of(&QMediaPlayer::error), this, &WowPlayerWidget::displayErrorMessage);
connect(m_player, &QMediaPlayer::stateChanged, this, &WowPlayerWidget::stateChanged);
// QHBoxLayout *wowPlayerLayout = new QHBoxLayout(this);;
//! [2]
m_videoWidget = new VideoWidget(ui->verticalWidget);
m_player->setVideoOutput(m_videoWidget);
m_playlistModel = new PlaylistModel(this);
m_playlistModel->setPlaylist(m_playlist);
//! [2]
m_playlistView = new QListView(this);
m_playlistView->setModel(m_playlistModel);
m_playlistView->setCurrentIndex(m_playlistModel->index(m_playlist->currentIndex(), 0));
connect(m_playlistView, &QAbstractItemView::activated, this, &WowPlayerWidget::jump);
m_slider = new QSlider(Qt::Horizontal, this);
m_slider->setRange(0, m_player->duration() / 1000);
m_labelDuration = new QLabel(this);
connect(m_slider, &QSlider::sliderMoved, this, &WowPlayerWidget::seek);
//connect(m_slider, &QSlider::, this, &WowPlayerWidget::seek);
//m_labelHistogram = new QLabel(this);
//m_labelHistogram->setText("Histogram:");
//m_videoHistogram = new HistogramWidget(this);
//m_audioHistogram = new HistogramWidget(this);
//QHBoxLayout *histogramLayout = new QHBoxLayout;
//histogramLayout->addWidget(m_labelHistogram);
//histogramLayout->addWidget(m_videoHistogram, 1);
//histogramLayout->addWidget(m_audioHistogram, 2);
//m_videoProbe = new QVideoProbe(this);
//connect(m_videoProbe, &QVideoProbe::videoFrameProbed, m_videoHistogram, &HistogramWidget::processFrame);
//m_videoProbe->setSource(m_player);
//m_audioProbe = new QAudioProbe(this);
//connect(m_audioProbe, &QAudioProbe::audioBufferProbed, m_audioHistogram, &HistogramWidget::processBuffer);
//m_audioProbe->setSource(m_player);
QPushButton *playWowIRCRadioButton = new QPushButton(tr("Play IRC!Radio"), this);
QPushButton *taesteWowButton = new QPushButton(tr("Tæste Wow"), ui->verticalWidget);
QPushButton *tuneButton = new QPushButton(tr("!Tune"), ui->verticalWidget);
QPushButton *openButton = new QPushButton(tr("Open"), this);
connect(playWowIRCRadioButton, &QPushButton::clicked, this, &WowPlayerWidget::playWowIRCRadio);
connect(taesteWowButton, &QPushButton::clicked, this, &WowPlayerWidget::taesteWow);
connect(tuneButton, &QPushButton::clicked, this, &WowPlayerWidget::tune);
connect(openButton, &QPushButton::clicked, this, &WowPlayerWidget::open);
PlayerControls *controls = new PlayerControls(this);
controls->setState(m_player->state());
controls->setVolume(m_player->volume());
controls->setMuted(controls->isMuted());
connect(controls, &PlayerControls::play, m_player, &QMediaPlayer::play);
connect(controls, &PlayerControls::pause, m_player, &QMediaPlayer::pause);
connect(controls, &PlayerControls::stop, m_player, &QMediaPlayer::stop);
connect(controls, &PlayerControls::next, m_playlist, &QMediaPlaylist::next);
connect(controls, &PlayerControls::previous, this, &WowPlayerWidget::previousClicked);
connect(controls, &PlayerControls::changeVolume, m_player, &QMediaPlayer::setVolume);
connect(controls, &PlayerControls::changeMuting, m_player, &QMediaPlayer::setMuted);
connect(controls, &PlayerControls::changeRate, m_player, &QMediaPlayer::setPlaybackRate);
connect(controls, &PlayerControls::stop, m_videoWidget, QOverload<>::of(&QVideoWidget::update));
connect(m_player, &QMediaPlayer::stateChanged, controls, &PlayerControls::setState);
connect(m_player, &QMediaPlayer::volumeChanged, controls, &PlayerControls::setVolume);
connect(m_player, &QMediaPlayer::mutedChanged, controls, &PlayerControls::setMuted);
m_fullScreenButton = new QPushButton(tr("FullScreen"), this);
m_fullScreenButton->setCheckable(true);
//m_colorButton = new QPushButton(tr("Color Options..."), this);
//m_colorButton->setEnabled(false);
//connect(m_colorButton, &QPushButton::clicked, this, &WowPlayerWidget::showColorDialog);
QBoxLayout *infoPanelLayout = new QVBoxLayout;
m_statusBar = new QPlainTextEdit;
m_statusLabel = new QLabel;
m_statusLabel->setMaximumHeight(30);
//m_TextBrowser = new QTextBrowser;
m_statusBar->setMaximumHeight(66);
//m_statusBar->sizeHint();
m_statusBar->setPlainText("More fun with Wowmero IRC!Radio\nIRC 140.211.166.64:6667\n#wownero-music");
m_statusLabel->setText("WowPlayer ready");
QUrl *history = new QUrl("https://radio.wownero.com/history.txt");
//m_TextBrowser->setSource(QUrl("https://radio.wownero.com/history.txt"));
//m_TextBrowser->reload();
//m_TextBrowser->setPlainText(history->toString());
//m_TextBrowser->append("<a href = \"https://radio.wownero.com/history.txt\"> History </a>");
infoPanelLayout->addWidget(m_statusLabel);//, 2);
infoPanelLayout->addWidget(m_statusBar);//, 2);
//infoPlanelLayout->addWidget(m_TextBrowser);
//infoPlanelLayout->addWidget(playWowIRCRadioButton);
QBoxLayout *playerButtonsLayout = new QHBoxLayout;
playerButtonsLayout->addWidget(playWowIRCRadioButton);
playerButtonsLayout->addWidget(taesteWowButton);
playerButtonsLayout->addWidget(tuneButton);
playerButtonsLayout->addWidget(openButton);
QBoxLayout *displayLayout = new QHBoxLayout;
displayLayout->addWidget(m_videoWidget, 2);
displayLayout->addWidget(m_playlistView);
QBoxLayout *controlLayout = new QHBoxLayout;
controlLayout->setContentsMargins(0, 0, 0, 0);
controlLayout->addLayout(playerButtonsLayout);
controlLayout->addStretch(1);
controlLayout->addWidget(controls);
controlLayout->addStretch(1);
controlLayout->addWidget(m_fullScreenButton);
//controlLayout->addWidget(m_colorButton);
QBoxLayout *layout = new QVBoxLayout;
QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addWidget(m_slider);
hLayout->addWidget(m_labelDuration);
layout->addLayout(infoPanelLayout);
layout->addLayout(hLayout);
layout->addLayout(controlLayout);
layout->addLayout(displayLayout);
//layout->addLayout(histogramLayout);
#if defined(Q_OS_QNX)
// On QNX, the main window doesn't have a title bar (or any other decorations).
// Create a status bar for the status information instead.
m_statusLabel = new QLabel;
m_statusBar = new QStatusBar;
m_statusBar->addPermanentWidget(m_statusLabel);
m_statusBar->setSizeGripEnabled(false); // Without mouse grabbing, it doesn't work very well.
layout->addWidget(m_statusBar);
#endif
setLayout(layout);
if (!isPlayerAvailable()) {
QMessageBox::warning(this, tr("Service not available"),
tr("The QMediaPlayer object does not have a valid service.\n"\
"Please check the media service plugins are installed."));
controls->setEnabled(false);
m_playlistView->setEnabled(false);
openButton->setEnabled(false);
m_colorButton->setEnabled(false);
m_fullScreenButton->setEnabled(false);
}
metaDataChanged();
}
WowPlayerWidget::~WowPlayerWidget() {
delete ui;
}
bool WowPlayerWidget::isPlayerAvailable() const
{
return m_player->isAvailable();
}
void WowPlayerWidget::playWowIRCRadio()
{
//PrepareSuchWowSlideShow();
/*
QImage img = QImage("qrc:///assets/images/wowlet.png").convertToFormat(QImage::Format_ARGB32);
QVideoSurfaceFormat format(img.size(), QVideoFrame::Format_ARGB32);
//QVideoWidget *videoWidget = new QVideoWidget;
m_videoWidget->videoSurface()->start(format);
m_videoWidget->videoSurface()->present(img);
//m_videoWidget->show();
*/
m_playlist->clear();
m_playlist->addMedia(QUrl("https://radio.wownero.com/wow.ogg"));
m_player->play();
}
void WowPlayerWidget::taesteWow()
{
setStatusInfo(tr("Wow"));
m_playlist->clear();
m_playlist->addMedia(QUrl("qrc:///assets/videos/do_you_even_wow_special_friend.mp4"));
m_playlist->addMedia(QUrl("https://radio.wownero.com/wow.ogg"));
m_player->play();
}
void WowPlayerWidget::tune()
{
setStatusInfo(tr("Undefined reference HellGate::TrollConnect(me, like, wownero, music)"));
}
void WowPlayerWidget::open()
{
QFileDialog fileDialog(this);
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
fileDialog.setWindowTitle(tr("Open Files"));
QStringList supportedMimeTypes = m_player->supportedMimeTypes();
if (!supportedMimeTypes.isEmpty()) {
supportedMimeTypes.append("audio/x-m3u"); // MP3 playlists
fileDialog.setMimeTypeFilters(supportedMimeTypes);
}
fileDialog.setDirectory(QStandardPaths::standardLocations(QStandardPaths::MoviesLocation).value(0, QDir::homePath()));
if (fileDialog.exec() == QDialog::Accepted)
addToPlaylist(fileDialog.selectedUrls());
//m_playlist->load(QUrl("https://radio.wownero.com/wow.ogg"));
//m_player->setMedia(QUrl("https://radio.wownero.com/wow.ogg"));
/*m_player->setMedia(QUrl("gst-pipeline: appsrc blocksize=4294967295 ! \
video/x-raw,format=BGRx,framerate=30/1,width=200,height=147 ! \
coloreffects preset=heat ! videoconvert ! video/x-raw,format=I420 ! jpegenc ! rtpjpegpay ! \
udpsink host=127.0.0.1 port=5000"));*/
// setMedia(QUrl::fromLocalFile("~/ Music/coolsong.mp3"));
//playbin uri=file:///projects/demo.ogv
}
static bool isPlaylist(const QUrl &url) // Check for ".m3u" playlists.
{
if (!url.isLocalFile())
return false;
const QFileInfo fileInfo(url.toLocalFile());
return fileInfo.exists() && !fileInfo.suffix().compare(QLatin1String("m3u"), Qt::CaseInsensitive);
}
void WowPlayerWidget::addToPlaylist(const QList<QUrl> &urls)
{
for (auto &url: urls) {
if (isPlaylist(url))
m_playlist->load(url);
else
m_playlist->addMedia(url);
}
}
void WowPlayerWidget::setCustomAudioRole(const QString &role)
{
m_player->setCustomAudioRole(role);
}
void WowPlayerWidget::durationChanged(qint64 duration)
{
m_duration = duration / 1000;
m_slider->setMaximum(m_duration);
}
void WowPlayerWidget::positionChanged(qint64 progress)
{
if (!m_slider->isSliderDown())
m_slider->setValue(progress / 1000);
updateDurationInfo(progress / 1000);
}
void WowPlayerWidget::metaDataChanged()
{
if (m_player->isMetaDataAvailable()) {
setTrackInfo(QString("%1 - %2")
.arg(m_player->metaData(QMediaMetaData::AlbumArtist).toString())
.arg(m_player->metaData(QMediaMetaData::Title).toString()));
if (m_coverLabel) {
QUrl url = m_player->metaData(QMediaMetaData::CoverArtUrlLarge).value<QUrl>();
m_coverLabel->setPixmap(!url.isEmpty()
? QPixmap(url.toString())
: QPixmap());
}
}
}
void WowPlayerWidget::previousClicked()
{
// Go to previous track if we are within the first 5 seconds of playback
// Otherwise, seek to the beginning.
if (m_player->position() <= 5000)
m_playlist->previous();
else
m_player->setPosition(0);
}
void WowPlayerWidget::jump(const QModelIndex &index)
{
if (index.isValid()) {
m_playlist->setCurrentIndex(index.row());
m_player->play();
}
}
void WowPlayerWidget::playlistPositionChanged(int currentItem)
{
//clearHistogram();
m_playlistView->setCurrentIndex(m_playlistModel->index(currentItem, 0));
}
void WowPlayerWidget::seek(int seconds)
{
m_player->setPosition(seconds * 1000);
}
void WowPlayerWidget::statusChanged(QMediaPlayer::MediaStatus status)
{
handleCursor(status);
// handle status message
switch (status) {
case QMediaPlayer::UnknownMediaStatus:
case QMediaPlayer::NoMedia:
case QMediaPlayer::LoadedMedia:
setStatusInfo(QString());
break;
case QMediaPlayer::LoadingMedia:
setStatusInfo(tr("Loading..."));
break;
case QMediaPlayer::BufferingMedia:
case QMediaPlayer::BufferedMedia:
setStatusInfo(tr("Buffering %1%").arg(m_player->bufferStatus()));
break;
case QMediaPlayer::StalledMedia:
setStatusInfo(tr("Stalled %1%").arg(m_player->bufferStatus()));
break;
case QMediaPlayer::EndOfMedia:
QApplication::alert(this);
break;
case QMediaPlayer::InvalidMedia:
displayErrorMessage();
break;
}
}
void WowPlayerWidget::stateChanged(QMediaPlayer::State state)
{
//if (state == QMediaPlayer::StoppedState)
// clearHistogram();
}
void WowPlayerWidget::handleCursor(QMediaPlayer::MediaStatus status)
{
#ifndef QT_NO_CURSOR
if (status == QMediaPlayer::LoadingMedia ||
status == QMediaPlayer::BufferingMedia ||
status == QMediaPlayer::StalledMedia)
setCursor(QCursor(Qt::BusyCursor));
else
unsetCursor();
#endif
}
void WowPlayerWidget::bufferingProgress(int progress)
{
if (m_player->mediaStatus() == QMediaPlayer::StalledMedia)
setStatusInfo(tr("Stalled %1%").arg(progress));
else
setStatusInfo(tr("Buffering %1%").arg(progress));
}
void WowPlayerWidget::videoAvailableChanged(bool available)
{
if (!available) {
disconnect(m_fullScreenButton, &QPushButton::clicked, m_videoWidget, &QVideoWidget::setFullScreen);
disconnect(m_videoWidget, &QVideoWidget::fullScreenChanged, m_fullScreenButton, &QPushButton::setChecked);
m_videoWidget->setFullScreen(false);
} else {
connect(m_fullScreenButton, &QPushButton::clicked, m_videoWidget, &QVideoWidget::setFullScreen);
connect(m_videoWidget, &QVideoWidget::fullScreenChanged, m_fullScreenButton, &QPushButton::setChecked);
if (m_fullScreenButton->isChecked())
m_videoWidget->setFullScreen(true);
}
//m_colorButton->setEnabled(available);
}
void WowPlayerWidget::setTrackInfo(const QString &info)
{
m_trackInfo = info;
//m_statusBar->setPlainText(m_trackInfo);
// m_statusBar->setPlainText("Wownero IRC!Radio"+m_trackInfo);
// m_statusLabel->setText(m_statusInfo);
if (m_statusBar) {
//if (!m_trackInfo.isEmpty()) m_statusBar->setPlainText("Wownero +++IRC!Radio"+m_trackInfo); else m_statusBar->setPlainText("");
m_statusBar->setPlainText(m_trackInfo);
m_statusLabel->setText(m_statusInfo);
} else {
if (!m_statusInfo.isEmpty())
m_statusBar->setPlainText(QString("%1 | %2").arg(m_trackInfo).arg(m_statusInfo));
else
m_statusBar->setPlainText(m_trackInfo);
}
}
void WowPlayerWidget::setStatusInfo(const QString &info)
{
m_statusInfo = info;
//m_statusBar->setPlainText(m_trackInfo);
//QFile *radioHistoryFile = new QFile("https://radio.wownero.com/history.txt");
//radioHistoryFile->open(QIODevice::ReadOnly);
//QString content = QString::fromUtf8(radioHistoryFile->readAll());
//content+="test";
// radioHistoryFile->close();
//m_TextBrowser->setSource(QUrl("https://radio.wownero.com/history.txt"));
//m_TextBrowser->reload();
if (!m_trackInfo.isEmpty()) m_statusBar->setPlainText("Wownero IRC!Radio"+m_trackInfo); else m_statusBar->setPlainText("");
// m_statusBar->setPlainText("Wownero IRC!Radio"+m_trackInfo);
m_statusLabel->setText(m_statusInfo);
/* if (m_statusBar) {
m_statusBar->showMessage(m_trackInfo);
m_statusLabel->setText(m_statusInfo);
} else {
if (!m_statusInfo.isEmpty())
setWindowTitle(QString("%1 | %2").arg(m_trackInfo).arg(m_statusInfo));
else
setWindowTitle(m_trackInfo);
}*/
}
void WowPlayerWidget::displayErrorMessage()
{
setStatusInfo(m_player->errorString());
}
void WowPlayerWidget::updateDurationInfo(qint64 currentInfo)
{
QString tStr;
if (currentInfo || m_duration) {
QTime currentTime((currentInfo / 3600) % 60, (currentInfo / 60) % 60,
currentInfo % 60, (currentInfo * 1000) % 1000);
QTime totalTime((m_duration / 3600) % 60, (m_duration / 60) % 60,
m_duration % 60, (m_duration * 1000) % 1000);
QString format = "mm:ss";
if (m_duration > 3600)
format = "hh:mm:ss";
tStr = currentTime.toString(format) + " / " + totalTime.toString(format);
}
m_labelDuration->setText(tStr);
}
void WowPlayerWidget::showColorDialog()
{
if (!m_colorDialog) {
QSlider *brightnessSlider = new QSlider(Qt::Horizontal);
brightnessSlider->setRange(-100, 100);
brightnessSlider->setValue(m_videoWidget->brightness());
connect(brightnessSlider, &QSlider::sliderMoved, m_videoWidget, &QVideoWidget::setBrightness);
connect(m_videoWidget, &QVideoWidget::brightnessChanged, brightnessSlider, &QSlider::setValue);
QSlider *contrastSlider = new QSlider(Qt::Horizontal);
contrastSlider->setRange(-100, 100);
contrastSlider->setValue(m_videoWidget->contrast());
connect(contrastSlider, &QSlider::sliderMoved, m_videoWidget, &QVideoWidget::setContrast);
connect(m_videoWidget, &QVideoWidget::contrastChanged, contrastSlider, &QSlider::setValue);
QSlider *hueSlider = new QSlider(Qt::Horizontal);
hueSlider->setRange(-100, 100);
hueSlider->setValue(m_videoWidget->hue());
connect(hueSlider, &QSlider::sliderMoved, m_videoWidget, &QVideoWidget::setHue);
connect(m_videoWidget, &QVideoWidget::hueChanged, hueSlider, &QSlider::setValue);
QSlider *saturationSlider = new QSlider(Qt::Horizontal);
saturationSlider->setRange(-100, 100);
saturationSlider->setValue(m_videoWidget->saturation());
connect(saturationSlider, &QSlider::sliderMoved, m_videoWidget, &QVideoWidget::setSaturation);
connect(m_videoWidget, &QVideoWidget::saturationChanged, saturationSlider, &QSlider::setValue);
QFormLayout *layout = new QFormLayout;
layout->addRow(tr("Brightness"), brightnessSlider);
layout->addRow(tr("Contrast"), contrastSlider);
layout->addRow(tr("Hue"), hueSlider);
layout->addRow(tr("Saturation"), saturationSlider);
QPushButton *button = new QPushButton(tr("Close"));
layout->addRow(button);
m_colorDialog = new QDialog(this);
m_colorDialog->setWindowTitle(tr("Color Options"));
m_colorDialog->setLayout(layout);
connect(button, &QPushButton::clicked, m_colorDialog, &QDialog::close);
}
m_colorDialog->show();
}
void WowPlayerWidget::clearHistogram()
{
//QMetaObject::invokeMethod(m_videoHistogram, "processFrame", Qt::QueuedConnection, Q_ARG(QVideoFrame, QVideoFrame()));
// QMetaObject::invokeMethod(m_audioHistogram, "processBuffer", Qt::QueuedConnection, Q_ARG(QAudioBuffer, QAudioBuffer()));
}
+95
View File
@@ -0,0 +1,95 @@
//
// Created by rapeafed on 2021.
//
#ifndef WOWLET_WOWPLAYERWIDGET_H
#define WOWLET_WOWPLAYERWIDGET_H
#include <QWidget>
#include <QList>
#include <QtMultimedia>
#include <QtMultimediaWidgets>
#include <QtMultimedia/QMediaPlayer>
#include "wowplaylistmodel.h"
#include "wowplayercontrols.h"
//#include "wowhistogramwidget.h"
QT_BEGIN_NAMESPACE
namespace Ui { class WowPlayerWidget; }
QT_END_NAMESPACE
class WowPlayerWidget : public QWidget {
Q_OBJECT
public:
explicit WowPlayerWidget(QWidget *parent = nullptr);
~WowPlayerWidget() override;
bool isPlayerAvailable() const;
void addToPlaylist(const QList<QUrl> &urls);
void setCustomAudioRole(const QString &role);
signals:
void fullScreenChanged(bool fullScreen);
private slots:
void open();
void playWowIRCRadio();
void taesteWow();
void tune();
void durationChanged(qint64 duration);
void positionChanged(qint64 progress);
void metaDataChanged();
void previousClicked();
void seek(int seconds);
void jump(const QModelIndex &index);
void playlistPositionChanged(int);
void statusChanged(QMediaPlayer::MediaStatus status);
void stateChanged(QMediaPlayer::State state);
void bufferingProgress(int progress);
void videoAvailableChanged(bool available);
void displayErrorMessage();
void showColorDialog();
private:
void clearHistogram();
void setTrackInfo(const QString &info);
void setStatusInfo(const QString &info);
void handleCursor(QMediaPlayer::MediaStatus status);
void updateDurationInfo(qint64 currentInfo);
Ui::WowPlayerWidget *ui;
QMediaPlayer *m_player = nullptr;
QMediaPlaylist *m_playlist = nullptr;
QVideoWidget *m_videoWidget = nullptr;
QTextBrowser *m_TextBrowser = nullptr;
QLabel *m_coverLabel = nullptr;
QSlider *m_slider = nullptr;
QLabel *m_labelDuration = nullptr;
QPushButton *m_fullScreenButton = nullptr;
QPushButton *m_colorButton = nullptr;
QDialog *m_colorDialog = nullptr;
QLabel *m_statusLabel = nullptr;
QPlainTextEdit *m_statusBar = nullptr;
QLabel *m_labelHistogram = nullptr;
//HistogramWidget *m_videoHistogram = nullptr;
//HistogramWidget *m_audioHistogram = nullptr;
QVideoProbe *m_videoProbe = nullptr;
QAudioProbe *m_audioProbe = nullptr;
PlaylistModel *m_playlistModel = nullptr;
QAbstractItemView *m_playlistView = nullptr;
QString m_trackInfo;
QString m_statusInfo;
qint64 m_duration;
};
#endif //WOWLET_WOWPLAYERWIDGET_H
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WowPlayerWidget</class>
<widget class="QWidget" name="WowPlayerWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>WowPlayerWidget</string>
</property>
<widget class="QWidget" name="verticalWidget" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>160</y>
<width>401</width>
<height>31</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout"/>
</widget>
</widget>
<resources/>
<connections/>
</ui>
+169
View File
@@ -0,0 +1,169 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "wowplaylistmodel.h"
#include <QFileInfo>
#include <QUrl>
#include <QMediaPlaylist>
PlaylistModel::PlaylistModel(QObject *parent)
: QAbstractItemModel(parent)
{
}
PlaylistModel::~PlaylistModel()
{
}
int PlaylistModel::rowCount(const QModelIndex &parent) const
{
return m_playlist && !parent.isValid() ? m_playlist->mediaCount() : 0;
}
int PlaylistModel::columnCount(const QModelIndex &parent) const
{
return !parent.isValid() ? ColumnCount : 0;
}
QModelIndex PlaylistModel::index(int row, int column, const QModelIndex &parent) const
{
return m_playlist && !parent.isValid()
&& row >= 0 && row < m_playlist->mediaCount()
&& column >= 0 && column < ColumnCount
? createIndex(row, column)
: QModelIndex();
}
QModelIndex PlaylistModel::parent(const QModelIndex &child) const
{
Q_UNUSED(child);
return QModelIndex();
}
QVariant PlaylistModel::data(const QModelIndex &index, int role) const
{
if (index.isValid() && role == Qt::DisplayRole) {
QVariant value = m_data[index];
if (!value.isValid() && index.column() == Title) {
QUrl location = m_playlist->media(index.row()).request().url();
return QFileInfo(location.path()).fileName();
}
return value;
}
return QVariant();
}
QMediaPlaylist *PlaylistModel::playlist() const
{
return m_playlist.data();
}
void PlaylistModel::setPlaylist(QMediaPlaylist *playlist)
{
if (m_playlist) {
disconnect(m_playlist.data(), &QMediaPlaylist::mediaAboutToBeInserted, this, &PlaylistModel::beginInsertItems);
disconnect(m_playlist.data(), &QMediaPlaylist::mediaInserted, this, &PlaylistModel::endInsertItems);
disconnect(m_playlist.data(), &QMediaPlaylist::mediaAboutToBeRemoved, this, &PlaylistModel::beginRemoveItems);
disconnect(m_playlist.data(), &QMediaPlaylist::mediaRemoved, this, &PlaylistModel::endRemoveItems);
disconnect(m_playlist.data(), &QMediaPlaylist::mediaChanged, this, &PlaylistModel::changeItems);
}
beginResetModel();
m_playlist.reset(playlist);
if (m_playlist) {
connect(m_playlist.data(), &QMediaPlaylist::mediaAboutToBeInserted, this, &PlaylistModel::beginInsertItems);
connect(m_playlist.data(), &QMediaPlaylist::mediaInserted, this, &PlaylistModel::endInsertItems);
connect(m_playlist.data(), &QMediaPlaylist::mediaAboutToBeRemoved, this, &PlaylistModel::beginRemoveItems);
connect(m_playlist.data(), &QMediaPlaylist::mediaRemoved, this, &PlaylistModel::endRemoveItems);
connect(m_playlist.data(), &QMediaPlaylist::mediaChanged, this, &PlaylistModel::changeItems);
}
endResetModel();
}
bool PlaylistModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
Q_UNUSED(role);
m_data[index] = value;
emit dataChanged(index, index);
return true;
}
void PlaylistModel::beginInsertItems(int start, int end)
{
m_data.clear();
beginInsertRows(QModelIndex(), start, end);
}
void PlaylistModel::endInsertItems()
{
endInsertRows();
}
void PlaylistModel::beginRemoveItems(int start, int end)
{
m_data.clear();
beginRemoveRows(QModelIndex(), start, end);
}
void PlaylistModel::endRemoveItems()
{
endInsertRows();
}
void PlaylistModel::changeItems(int start, int end)
{
m_data.clear();
emit dataChanged(index(start,0), index(end,ColumnCount));
}
+100
View File
@@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef PLAYLISTMODEL_H
#define PLAYLISTMODEL_H
#include <QAbstractItemModel>
#include <QScopedPointer>
QT_BEGIN_NAMESPACE
class QMediaPlaylist;
QT_END_NAMESPACE
class PlaylistModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum Column
{
Title = 0,
ColumnCount
};
explicit PlaylistModel(QObject *parent = nullptr);
~PlaylistModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QMediaPlaylist *playlist() const;
void setPlaylist(QMediaPlaylist *playlist);
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole) override;
private slots:
void beginInsertItems(int start, int end);
void endInsertItems();
void beginRemoveItems(int start, int end);
void endRemoveItems();
void changeItems(int start, int end);
private:
QScopedPointer<QMediaPlaylist> m_playlist;
QMap<QModelIndex, QVariant> m_data;
};
#endif // PLAYLISTMODEL_H
+91
View File
@@ -0,0 +1,91 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "wowvideowidget.h"
#include <QKeyEvent>
#include <QMouseEvent>
VideoWidget::VideoWidget(QWidget *parent)
: QVideoWidget(parent)
{
setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
QPalette p = palette();
p.setColor(QPalette::Window, Qt::black);
setPalette(p);
setAttribute(Qt::WA_OpaquePaintEvent);
}
void VideoWidget::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape && isFullScreen()) {
setFullScreen(false);
event->accept();
} else if (event->key() == Qt::Key_Enter && event->modifiers() & Qt::Key_Alt) {
setFullScreen(!isFullScreen());
event->accept();
} else {
QVideoWidget::keyPressEvent(event);
}
}
void VideoWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
setFullScreen(!isFullScreen());
event->accept();
}
void VideoWidget::mousePressEvent(QMouseEvent *event)
{
QVideoWidget::mousePressEvent(event);
}
+69
View File
@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef VIDEOWIDGET_H
#define VIDEOWIDGET_H
#include <QVideoWidget>
class VideoWidget : public QVideoWidget
{
Q_OBJECT
public:
explicit VideoWidget(QWidget *parent = nullptr);
protected:
void keyPressEvent(QKeyEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
};
#endif // VIDEOWIDGET_H
+157 -248
View File
@@ -15,28 +15,19 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) :
QWidget(parent), QWidget(parent),
ui(new Ui::XMRigWidget), ui(new Ui::XMRigWidget),
m_ctx(ctx), m_ctx(ctx),
m_modelRig(new QStandardItemModel(this)), m_model(new QStandardItemModel(this)),
m_modelWownerod(new QStandardItemModel(this)), m_contextMenu(new QMenu(this))
m_contextMenuRig(new QMenu(this)),
m_contextMenuWownerod(new QMenu(this))
{ {
ui->setupUi(this); ui->setupUi(this);
this->resetUI();
QPixmap p(":assets/images/fire.png"); QPixmap p(":assets/images/mining.png");
ui->lbl_logo->setPixmap(p.scaled(268, 271, Qt::KeepAspectRatio, Qt::SmoothTransformation)); ui->lbl_logo->setPixmap(p.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
// table XMRig // table
ui->tableRig->setModel(this->m_modelRig); ui->tableView->setModel(this->m_model);
m_contextMenuRig->addAction(QIcon(":/assets/images/network.png"), "Download file", this, &XMRigWidget::rigLinkClicked); m_contextMenu->addAction(QIcon(":/assets/images/network.png"), "Download file", this, &XMRigWidget::linkClicked);
connect(ui->tableRig, &QHeaderView::customContextMenuRequested, this, &XMRigWidget::showContextRigMenu); connect(ui->tableView, &QHeaderView::customContextMenuRequested, this, &XMRigWidget::showContextMenu);
connect(ui->tableRig, &QTableView::doubleClicked, this, &XMRigWidget::rigLinkClicked); connect(ui->tableView, &QTableView::doubleClicked, this, &XMRigWidget::linkClicked);
// table wownerod
ui->tableWownerod->setModel(this->m_modelWownerod);
m_contextMenuWownerod->addAction(QIcon(":/assets/images/network.png"), "Download file", this, &XMRigWidget::wownerodLinkClicked);
connect(ui->tableWownerod, &QHeaderView::customContextMenuRequested, this, &XMRigWidget::showContextWownerodMenu);
connect(ui->tableWownerod, &QTableView::doubleClicked, this, &XMRigWidget::wownerodLinkClicked);
// threads // threads
ui->threadSlider->setMinimum(1); ui->threadSlider->setMinimum(1);
@@ -53,107 +44,78 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) :
connect(ui->btn_browse, &QPushButton::clicked, this, &XMRigWidget::onBrowseClicked); connect(ui->btn_browse, &QPushButton::clicked, this, &XMRigWidget::onBrowseClicked);
connect(ui->btn_clear, &QPushButton::clicked, this, &XMRigWidget::onClearClicked); connect(ui->btn_clear, &QPushButton::clicked, this, &XMRigWidget::onClearClicked);
// graphics // defaults
bool simplifiedUI = config()->get(Config::simplifiedMiningInterface).toBool(); ui->btn_stop->setEnabled(false);
ui->comboBox_gfx->setCurrentIndex(simplifiedUI ? 1 : 0);
connect(ui->comboBox_gfx, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XMRigWidget::onSimplifiedMiningChanged);
// wownerod binary
auto path = config()->get(Config::wownerodPath).toString();
if(!path.isEmpty())
ui->lineEdit_path->setText(path);
connect(ui->lineEdit_path, &QLineEdit::textChanged, [=] {
config()->set(Config::wownerodPath, ui->lineEdit_path->text().trimmed());
});
// info
this->appendText(QString("Detected %1 CPU threads.").arg(threads));
if(path.isEmpty())
this->appendText(QString("wownerod path is empty - please point towards the wownerod executable.").arg(path));
else if(!Utils::fileExists(path))
this->appendText("Invalid path to the wownerod executable detected. Please set the correct path.");
else {
this->appendText(QString("wownerod path set to '%1'").arg(path));
this->appendText("Ready to mine.");
}
}
void XMRigWidget::resetUI() {
ui->consoleFrame->hide();
ui->qmlFrame->hide();
ui->qmlFrameTxt->hide();
ui->check_autoscroll->setChecked(true); ui->check_autoscroll->setChecked(true);
ui->relayTor->setChecked(false);
ui->check_tls->setChecked(true);
ui->label_status->setTextInteractionFlags(Qt::TextSelectableByMouse); ui->label_status->setTextInteractionFlags(Qt::TextSelectableByMouse);
ui->label_status->hide(); ui->label_status->hide();
ui->console->clear(); ui->soloFrame->hide();
ui->poolFrame->hide();
this->destroyQml(); // XMRig binary
} auto path = config()->get(Config::xmrigPath).toString();
if(!path.isEmpty()) {
void XMRigWidget::startUI() { ui->lineEdit_path->setText(path);
this->resetUI();
bool simplifiedUI = config()->get(Config::simplifiedMiningInterface).toBool();
if(simplifiedUI) {
this->initConsole();
} else {
this->initQML();
} }
}
void XMRigWidget::initConsole() { // pools
ui->consoleFrame->show(); ui->poolFrame->show();
} ui->combo_pools->insertItems(0, m_pools);
auto preferredPool = config()->get(Config::xmrigPool).toString();
void XMRigWidget::initQML() { if (m_pools.contains(preferredPool))
if(m_quickWidget != nullptr) return; ui->combo_pools->setCurrentIndex(m_pools.indexOf(preferredPool));
m_quickWidget = new QQuickWidget(this); else {
preferredPool = m_pools.at(0);
auto *qctx = m_quickWidget->rootContext(); config()->set(Config::xmrigPool, preferredPool);
qctx->setContextProperty("cfg", config());
qctx->setContextProperty("ctx", m_ctx);
qctx->setContextProperty("mining", this);
m_quickWidget->setSource(QUrl("qrc:/mining.qml"));
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
connect((QObject*)m_quickWidget->rootObject(), SIGNAL(startMining()),
this, SLOT(onStartClicked()));
connect((QObject*)m_quickWidget->rootObject(), SIGNAL(stopMining()),
this, SLOT(onStopClicked()));
ui->qmlFrame->layout()->addWidget(m_quickWidget);
ui->qmlFrame->show();
qDebug() << "created QML mining widget";
}
void XMRigWidget::destroyQml() {
if(m_quickWidget == nullptr) return;
m_quickWidget->disconnect();
m_quickWidget->deleteLater();
m_quickWidget = nullptr;
qDebug() << "destroyed QML mining widget";
}
void XMRigWidget::appendText(const QString &line) {
ui->console->appendPlainText(line);
m_consoleBuffer += 1;
if(m_consoleBuffer >= m_consoleBufferMax) {
ui->console->clear();
m_consoleBuffer = 0;
} }
connect(ui->combo_pools, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XMRigWidget::onPoolChanged);
// info
ui->console->appendPlainText(QString("Detected %1 CPU threads.").arg(threads));
if(!path.isEmpty() && !Utils::fileExists(path))
ui->console->appendPlainText("Invalid path to XMRig binary detected. Please reconfigure on the Settings tab.");
else
ui->console->appendPlainText(QString("XMRig path set to %1").arg(path));
ui->console->appendPlainText("Ready to mine.");
// username/password
connect(ui->lineEdit_password, &QLineEdit::editingFinished, [=]() {
m_ctx->currentWallet->setCacheAttribute("wowlet.xmrig_password", ui->lineEdit_password->text());
m_ctx->storeWallet();
});
connect(ui->lineEdit_address, &QLineEdit::editingFinished, [=]() {
m_ctx->currentWallet->setCacheAttribute("wowlet.xmrig_username", ui->lineEdit_address->text());
m_ctx->storeWallet();
});
// checkbox connects
connect(ui->check_solo, &QCheckBox::stateChanged, this, &XMRigWidget::onSoloChecked);
} }
void XMRigWidget::onWalletClosed() { void XMRigWidget::onWalletClosed() {
this->onStopClicked(); this->onStopClicked();
this->onClearClicked(); this->onClearClicked();
ui->lineEdit_password->setText("");
ui->lineEdit_address->setText("");
} }
void XMRigWidget::onWalletOpened(Wallet *wallet){ void XMRigWidget::onWalletOpened(Wallet *wallet){
int egiwoge = 1; // Xmrig username
auto username = m_ctx->currentWallet->getCacheAttribute("wowlet.xmrig_username");
if(!username.isEmpty())
ui->lineEdit_address->setText(username);
// Xmrig passwd
auto password = m_ctx->currentWallet->getCacheAttribute("wowlet.xmrig_password");
if(!password.isEmpty()) {
ui->lineEdit_password->setText(password);
} else {
ui->lineEdit_password->setText("wowlet");
m_ctx->currentWallet->setCacheAttribute("wowlet.xmrig_password", ui->lineEdit_password->text());
}
} }
void XMRigWidget::onThreadsValueChanged(int threads) { void XMRigWidget::onThreadsValueChanged(int threads) {
@@ -161,94 +123,99 @@ void XMRigWidget::onThreadsValueChanged(int threads) {
ui->label_threads->setText(QString("CPU threads: %1").arg(m_threads)); ui->label_threads->setText(QString("CPU threads: %1").arg(m_threads));
} }
void XMRigWidget::onPoolChanged(int pos) {
config()->set(Config::xmrigPool, m_pools.at(pos));
}
void XMRigWidget::onBrowseClicked() { void XMRigWidget::onBrowseClicked() {
QString fileName = QFileDialog::getOpenFileName( QString fileName = QFileDialog::getOpenFileName(
this, "Path to wownerod executable", QDir::homePath()); this, "Path to XMRig executable", QDir::homePath());
if (fileName.isEmpty()) return; if (fileName.isEmpty()) return;
config()->set(Config::wownerodPath, fileName); config()->set(Config::xmrigPath, fileName);
ui->lineEdit_path->setText(fileName); ui->lineEdit_path->setText(fileName);
} }
void XMRigWidget::onSyncStatus(unsigned int from, unsigned int to, unsigned int pct) {
emit syncStatus(from, to, pct);
}
void XMRigWidget::onDaemonStateChanged(DaemonMiningState state) {
if(state == DaemonMiningState::idle) {
ui->btn_stop->setEnabled(false);
ui->btn_start->setEnabled(true);
ui->label_status->hide();
} else {
ui->btn_stop->setEnabled(true);
ui->btn_start->setEnabled(false);
ui->label_status->show();
}
m_daemonMiningState = state;
emit daemonMiningStateChanged();
}
void XMRigWidget::onUptimeChanged(const QString &uptime) {
emit uptimeChanged(uptime);
}
void XMRigWidget::onBlockReward() {
QDateTime date = QDateTime::currentDateTime();
QString formattedTime = date.toString("yyyy/MM/dd hh:mm");
auto reward = QString("Congrats: new block found at %1").arg(formattedTime);
// @TODO: this might be blocking, what if multiple rewards happen?
QMessageBox::information(this, "Reward found", reward);
}
void XMRigWidget::onClearClicked() { void XMRigWidget::onClearClicked() {
ui->console->clear(); ui->console->clear();
} }
void XMRigWidget::onStartClicked() { void XMRigWidget::onStartClicked() {
auto binPath = config()->get(Config::wownerodPath).toString(); QString xmrigPath;
if(!m_ctx->XMRig->start(binPath, m_threads)) return; bool solo = ui->check_solo->isChecked();
xmrigPath = config()->get(Config::xmrigPath).toString();
// username is receiving address usually
auto username = m_ctx->currentWallet->getCacheAttribute("wowlet.xmrig_username");
auto password = m_ctx->currentWallet->getCacheAttribute("wowlet.xmrig_password");
if(username.isEmpty()) {
QString err = "Please specify a receiving address on the Settings screen";
ui->console->appendPlainText(err);
QMessageBox::warning(this, "Error", err);
return;
}
QString address;
if(solo)
address = ui->lineEdit_solo->text().trimmed();
else
address = config()->get(Config::xmrigPool).toString();
if(address.contains("cryptonote.social") && !username.contains(".")) {
// cryptonote social requires <addr>.<username>, we'll just grab a few chars from primary addy
username = QString("%1.%2").arg(username, m_ctx->currentWallet->address(0, 0).mid(0, 6));
}
m_ctx->XMRig->start(xmrigPath, m_threads, address, username, password, ui->relayTor->isChecked(), ui->check_tls->isChecked());
ui->btn_start->setEnabled(false); ui->btn_start->setEnabled(false);
ui->btn_stop->setEnabled(true); ui->btn_stop->setEnabled(true);
emit miningStarted();
} }
void XMRigWidget::onStopClicked() { void XMRigWidget::onStopClicked() {
if(m_ctx->XMRig->daemonMiningState != DaemonMiningState::idle) m_ctx->XMRig->stop();
m_ctx->XMRig->stop(); ui->btn_start->setEnabled(true);
ui->btn_stop->setEnabled(false);
ui->label_status->hide();
emit miningEnded();
} }
void XMRigWidget::onProcessOutput(const QByteArray &data) { void XMRigWidget::onProcessOutput(const QByteArray &data) {
auto line = Utils::barrayToString(data); auto output = Utils::barrayToString(data);
line = line.trimmed(); if(output.endsWith("\n"))
this->appendText(line); output = output.trimmed();
ui->console->appendPlainText(output);
if(ui->check_autoscroll->isChecked()) if(ui->check_autoscroll->isChecked())
ui->console->verticalScrollBar()->setValue(ui->console->verticalScrollBar()->maximum()); ui->console->verticalScrollBar()->setValue(ui->console->verticalScrollBar()->maximum());
} }
void XMRigWidget::onProcessError(const QString &msg) { void XMRigWidget::onProcessError(const QString &msg) {
this->appendText(msg); ui->console->appendPlainText("\n" + msg);
ui->btn_start->setEnabled(true);
ui->btn_stop->setEnabled(false);
ui->label_status->hide();
emit miningEnded();
} }
void XMRigWidget::onSimplifiedMiningChanged(int idx) { void XMRigWidget::onHashrate(const QString &hashrate) {
config()->set(Config::simplifiedMiningInterface, idx == 1);
this->startUI();
}
void XMRigWidget::onHashrate(const QString &rate) {
ui->label_status->show(); ui->label_status->show();
ui->label_status->setText(QString("Mining at %1").arg(rate)); ui->label_status->setText(QString("Mining at %1").arg(hashrate));
emit hashrate(rate);
} }
void XMRigWidget::onWownerodDownloads(const QJsonObject &data) { void XMRigWidget::onDownloads(const QJsonObject &data) {
m_modelWownerod->clear(); // For the downloads table we'll manually update the table
m_urlsWownerod.clear(); // with items once, as opposed to creating a class in
// src/models/. Saves effort; full-blown model
// is unnecessary in this case.
m_model->clear();
m_urls.clear();
auto version = data.value("version").toString(); auto version = data.value("version").toString();
ui->label_latest_version_wownerod->setText(QString("Latest version: %1").arg(version)); ui->label_latest_version->setText(QString("Latest version: %1").arg(version));
QJsonObject assets = data.value("assets").toObject(); QJsonObject assets = data.value("assets").toObject();
const auto _linux = assets.value("linux").toArray(); const auto _linux = assets.value("linux").toArray();
@@ -273,112 +240,54 @@ void XMRigWidget::onWownerodDownloads(const QJsonObject &data) {
auto _url = _obj.value("url").toString(); auto _url = _obj.value("url").toString();
auto _created_at = _obj.value("created_at").toString(); auto _created_at = _obj.value("created_at").toString();
m_urlsWownerod.append(_url); m_urls.append(_url);
auto download_count = _obj.value("download_count").toInt(); auto download_count = _obj.value("download_count").toInt();
m_modelWownerod->setItem(i, 0, Utils::qStandardItem(_name)); m_model->setItem(i, 0, Utils::qStandardItem(_name));
m_modelWownerod->setItem(i, 1, Utils::qStandardItem(_created_at)); m_model->setItem(i, 1, Utils::qStandardItem(_created_at));
m_modelWownerod->setItem(i, 2, Utils::qStandardItem(QString::number(download_count))); m_model->setItem(i, 2, Utils::qStandardItem(QString::number(download_count)));
i++; i++;
} }
m_modelWownerod->setHeaderData(0, Qt::Horizontal, tr("Filename"), Qt::DisplayRole); m_model->setHeaderData(0, Qt::Horizontal, tr("Filename"), Qt::DisplayRole);
m_modelWownerod->setHeaderData(1, Qt::Horizontal, tr("Date"), Qt::DisplayRole); m_model->setHeaderData(1, Qt::Horizontal, tr("Date"), Qt::DisplayRole);
m_modelWownerod->setHeaderData(2, Qt::Horizontal, tr("Downloads"), Qt::DisplayRole); m_model->setHeaderData(2, Qt::Horizontal, tr("Downloads"), Qt::DisplayRole);
ui->tableWownerod->verticalHeader()->setVisible(false); ui->tableView->verticalHeader()->setVisible(false);
ui->tableWownerod->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableWownerod->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
ui->tableWownerod->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
ui->tableWownerod->setColumnWidth(2, 100); ui->tableView->setColumnWidth(2, 100);
} }
void XMRigWidget::onMenuTabChanged(int index) { void XMRigWidget::showContextMenu(const QPoint &pos) {
if(m_tabIndex == globals::Tabs::XMRIG && index != m_tabIndex) QModelIndex index = ui->tableView->indexAt(pos);
this->resetUI(); if (!index.isValid()) {
else if(globals::Tabs(index + 1) == globals::Tabs::XMRIG)
this->startUI();
m_tabIndex = index + 1;
}
void XMRigWidget::onRigDownloads(const QJsonObject &data) {
m_modelRig->clear();
m_urlsRig.clear();
auto version = data.value("version").toString();
ui->label_latest_version_rig->setText(QString("Latest version: %1").arg(version));
QJsonObject assets = data.value("assets").toObject();
const auto _linux = assets.value("linux").toArray();
const auto macos = assets.value("macos").toArray();
const auto windows = assets.value("windows").toArray();
auto info = QSysInfo::productType();
QJsonArray *os_assets;
if(info == "osx") {
os_assets = const_cast<QJsonArray *>(&macos);
} else if (info == "windows") {
os_assets = const_cast<QJsonArray *>(&windows);
} else {
// assume linux
os_assets = const_cast<QJsonArray *>(&_linux);
}
int i = 0;
for(const auto &entry: *os_assets) {
auto _obj = entry.toObject();
auto _name = _obj.value("name").toString();
auto _url = _obj.value("url").toString();
auto _created_at = _obj.value("created_at").toString();
m_urlsRig.append(_url);
auto download_count = _obj.value("download_count").toInt();
m_modelRig->setItem(i, 0, Utils::qStandardItem(_name));
m_modelRig->setItem(i, 1, Utils::qStandardItem(_created_at));
m_modelRig->setItem(i, 2, Utils::qStandardItem(QString::number(download_count)));
i++;
}
m_modelRig->setHeaderData(0, Qt::Horizontal, tr("Filename"), Qt::DisplayRole);
m_modelRig->setHeaderData(1, Qt::Horizontal, tr("Date"), Qt::DisplayRole);
m_modelRig->setHeaderData(2, Qt::Horizontal, tr("Downloads"), Qt::DisplayRole);
ui->tableRig->verticalHeader()->setVisible(false);
ui->tableRig->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableRig->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
ui->tableRig->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
ui->tableRig->setColumnWidth(2, 100);
}
void XMRigWidget::showContextRigMenu(const QPoint &pos) {
QModelIndex index = ui->tableRig->indexAt(pos);
if (!index.isValid())
return; return;
m_contextMenuRig->exec(ui->tableRig->viewport()->mapToGlobal(pos)); }
m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos));
} }
void XMRigWidget::showContextWownerodMenu(const QPoint &pos) { void XMRigWidget::onSoloChecked(int state) {
QModelIndex index = ui->tableWownerod->indexAt(pos); if(state == 2) {
if (!index.isValid()) ui->poolFrame->hide();
return; ui->soloFrame->show();
m_contextMenuRig->exec(ui->tableWownerod->viewport()->mapToGlobal(pos)); ui->check_tls->setChecked(false);
}
else {
ui->poolFrame->show();
ui->soloFrame->hide();
}
} }
void XMRigWidget::wownerodLinkClicked() { void XMRigWidget::linkClicked() {
QModelIndex index = ui->tableRig->currentIndex(); QModelIndex index = ui->tableView->currentIndex();
auto download_link = m_urlsRig.at(index.row()); auto download_link = m_urls.at(index.row());
Utils::externalLinkWarning(this, download_link);
}
void XMRigWidget::rigLinkClicked() {
QModelIndex index = ui->tableRig->currentIndex();
auto download_link = m_urlsRig.at(index.row());
Utils::externalLinkWarning(this, download_link); Utils::externalLinkWarning(this, download_link);
} }
QStandardItemModel *XMRigWidget::model() { QStandardItemModel *XMRigWidget::model() {
return m_modelRig; return m_model;
} }
XMRigWidget::~XMRigWidget() { XMRigWidget::~XMRigWidget() {
+13 -51
View File
@@ -4,10 +4,6 @@
#ifndef XMRIGWIDGET_H #ifndef XMRIGWIDGET_H
#define XMRIGWIDGET_H #define XMRIGWIDGET_H
#include <QObject>
#include <QQuickWidget>
#include <QQuickView>
#include <QQmlContext>
#include <QMenu> #include <QMenu>
#include <QWidget> #include <QWidget>
#include <QItemSelection> #include <QItemSelection>
@@ -15,7 +11,6 @@
#include "utils/xmrig.h" #include "utils/xmrig.h"
#include "utils/config.h" #include "utils/config.h"
#include "appcontext.h" #include "appcontext.h"
#include "globals.h"
namespace Ui { namespace Ui {
class XMRigWidget; class XMRigWidget;
@@ -28,10 +23,6 @@ class XMRigWidget : public QWidget
public: public:
explicit XMRigWidget(AppContext *ctx, QWidget *parent = nullptr); explicit XMRigWidget(AppContext *ctx, QWidget *parent = nullptr);
~XMRigWidget() override; ~XMRigWidget() override;
Q_PROPERTY(int daemonMiningState READ daemonMiningState NOTIFY daemonMiningStateChanged);
int daemonMiningState() const { return m_daemonMiningState; }
QStandardItemModel *model(); QStandardItemModel *model();
public slots: public slots:
@@ -40,61 +31,32 @@ public slots:
void onStartClicked(); void onStartClicked();
void onStopClicked(); void onStopClicked();
void onClearClicked(); void onClearClicked();
void onBlockReward(); void onDownloads(const QJsonObject &data);
void onRigDownloads(const QJsonObject &data); void linkClicked();
void onWownerodDownloads(const QJsonObject &data);
void rigLinkClicked();
void wownerodLinkClicked();
void onProcessError(const QString &msg); void onProcessError(const QString &msg);
void onProcessOutput(const QByteArray &msg); void onProcessOutput(const QByteArray &msg);
void onHashrate(const QString &rate); void onHashrate(const QString &hashrate);
void onDaemonStateChanged(DaemonMiningState state); void onSoloChecked(int state);
void onSyncStatus(unsigned int from, unsigned int to, unsigned int pct);
void onUptimeChanged(const QString &uptime);
void onMenuTabChanged(int index);
private slots: private slots:
void onBrowseClicked(); void onBrowseClicked();
void onThreadsValueChanged(int date); void onThreadsValueChanged(int date);
void onSimplifiedMiningChanged(int idx); void onPoolChanged(int pos);
signals: signals:
void daemonOutput(const QString &line); void miningStarted();
void syncStatus(unsigned int from, unsigned int to, unsigned int pct); void miningEnded();
void hashrate(const QString &rate);
void daemonMiningStateChanged();
void uptimeChanged(const QString &uptime);
//protected:
// void resizeEvent(QResizeEvent *event) override;
private: private:
void showContextRigMenu(const QPoint &pos); void showContextMenu(const QPoint &pos);
void showContextWownerodMenu(const QPoint &pos);
void appendText(const QString &line);
AppContext *m_ctx; AppContext *m_ctx;
Ui::XMRigWidget *ui; Ui::XMRigWidget *ui;
QStandardItemModel *m_modelRig; QStandardItemModel *m_model;
QStandardItemModel *m_modelWownerod; QMenu *m_contextMenu;
QMenu *m_contextMenuRig;
QMenu *m_contextMenuWownerod;
int m_threads; int m_threads;
QStringList m_urlsRig; QStringList m_urls;
QStringList m_urlsWownerod; QStringList m_pools{"cryptonote.social:2223", "pool.hashvault.pro:8888"};
unsigned int m_tabIndex = 0;
unsigned int m_consoleBuffer = 0;
unsigned int m_consoleBufferMax = 2000;
int m_daemonMiningState = 0;
QQuickWidget *m_quickWidget = nullptr;
void resetUI();
void startUI();
void initConsole();
void initQML();
void destroyQml();
}; };
#endif #endif // REDDITWIDGET_H
+287 -176
View File
@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>854</width> <width>1329</width>
<height>431</height> <height>540</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -29,25 +29,22 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="tab"> <widget class="QWidget" name="tab">
<attribute name="title"> <attribute name="title">
<string>Mining</string> <string>Mining</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item row="0" column="0"> <item>
<widget class="QFrame" name="consoleFrame"> <widget class="QFrame" name="outputFrame">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="frameShadow"> <property name="frameShadow">
<enum>QFrame::Plain</enum> <enum>QFrame::Plain</enum>
</property> </property>
<property name="lineWidth"> <layout class="QVBoxLayout" name="verticalLayout_2">
<number>0</number>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@@ -60,14 +57,14 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item row="0" column="0"> <item>
<widget class="QPlainTextEdit" name="console"> <widget class="QPlainTextEdit" name="console">
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
<widget class="QPushButton" name="btn_clear"> <widget class="QPushButton" name="btn_clear">
@@ -122,128 +119,105 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QFrame" name="qmlFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QGridLayout" name="gridLayout_7">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="qmlFrameTxt">
<property name="text">
<string>QML area here</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_3"> <widget class="QWidget" name="tab_3">
<attribute name="title"> <attribute name="title">
<string>Settings</string> <string>Settings</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_6"> <layout class="QVBoxLayout" name="verticalLayout_9">
<item row="2" column="0"> <item>
<spacer name="verticalSpacer"> <layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>386</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
<layout class="QFormLayout" name="formLayout"> <layout class="QVBoxLayout" name="verticalLayout_6">
<item row="0" column="0"> <item>
<widget class="QLabel" name="label"> <layout class="QHBoxLayout" name="horizontalLayout_11">
<property name="text">
<string>Graphics</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBox_gfx">
<item> <item>
<property name="text"> <layout class="QVBoxLayout" name="verticalLayout">
<string>Ultra</string> <item>
</property> <widget class="QLabel" name="label_threads">
<property name="text">
<string>Threads: </string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSlider" name="threadSlider">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item> </item>
<item> <item>
<property name="text"> <spacer name="horizontalSpacer_8">
<string>Potato</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Executable</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="lineEdit_path">
<property name="placeholderText">
<string>Path to wownerod...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_browse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_threads">
<property name="text">
<string>CPU threads</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QSlider" name="threadSlider">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="pathFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="check_tls">
<property name="text">
<string>TLS</string>
</property>
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="horizontalSpacer_3"> <widget class="QCheckBox" name="relayTor">
<property name="text">
<string>Tor</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="check_solo">
<property name="text">
<string>Solo mine</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
@@ -257,32 +231,209 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QFrame" name="poolFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Pool</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="combo_pools">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="soloFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Node address</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_solo">
<property name="text">
<string>127.0.0.1:18081</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Receiving address</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_address"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Password (optional)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_password"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>XMRig executable</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLineEdit" name="lineEdit_path">
<property name="placeholderText">
<string>/path/to/xmrig</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_browse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout> </layout>
</item> </item>
<item> <item>
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer_4">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>40</width> <width>24</width>
<height>20</height> <height>20</height>
</size> </size>
</property> </property>
</spacer> </spacer>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout_5">
<item> <item>
<widget class="QLabel" name="lbl_logo"> <widget class="QLabel" name="lbl_logo">
<property name="text"> <property name="text">
<string>img</string> <string>logoimg</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="verticalSpacer_2"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
@@ -298,70 +449,30 @@
</item> </item>
</layout> </layout>
</item> </item>
</layout> <item>
</widget> <spacer name="verticalSpacer_3">
<widget class="QWidget" name="tab_4"> <property name="orientation">
<attribute name="title"> <enum>Qt::Vertical</enum>
<string>wownerod</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="label_latest_version_wownerod">
<property name="text">
<string>Latest version:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_version_2">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>(right-click to download)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QTableView" name="tableWownerod">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property> </property>
<property name="editTriggers"> <property name="sizeHint" stdset="0">
<set>QAbstractItemView::NoEditTriggers</set> <size>
<width>20</width>
<height>0</height>
</size>
</property> </property>
<property name="selectionMode"> </spacer>
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_2"> <widget class="QWidget" name="tab_2">
<attribute name="title"> <attribute name="title">
<string>XMRig</string> <string>Downloads</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_7"> <layout class="QHBoxLayout" name="horizontalLayout_7">
<item> <item>
<widget class="QLabel" name="label_latest_version_rig"> <widget class="QLabel" name="label_latest_version">
<property name="text"> <property name="text">
<string>Latest version:</string> <string>Latest version:</string>
</property> </property>
@@ -383,7 +494,7 @@
</layout> </layout>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QTableView" name="tableRig"> <widget class="QTableView" name="tableView">
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum> <enum>Qt::CustomContextMenu</enum>
</property> </property>