mirror of
https://github.com/wownero/wowlet.git
synced 2026-10-30 12:48:55 +01:00
Compare commits
11
Commits
v3
...
hide-on-close
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96295a52de | ||
|
|
ccd0e8e64b | ||
|
|
3b3ec89306 | ||
|
|
373fe8e02a | ||
|
|
14d9793193 | ||
|
|
65ceab6323 | ||
|
|
6b2118ecf6 | ||
|
|
ca78025735 | ||
|
|
c5eb13145f | ||
|
|
946443bf8c | ||
|
|
ae33c2f1b0 |
+1
-1
@@ -262,7 +262,7 @@ RUN git clone -b release-64-2 --depth 1 https://github.com/unicode-org/icu && \
|
|||||||
make -j$THREADS install && \
|
make -j$THREADS install && \
|
||||||
rm -rf $(pwd)
|
rm -rf $(pwd)
|
||||||
|
|
||||||
RUN wget https://dl.bintray.com/boostorg/release/1.73.0/source/boost_1_73_0.tar.gz && \
|
RUN wget https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.gz && \
|
||||||
echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" | sha256sum -c && \
|
echo "9995e192e68528793755692917f9eb6422f3052a53c5e13ba278a228af6c7acf boost_1_73_0.tar.gz" | sha256sum -c && \
|
||||||
tar -xzf boost_1_73_0.tar.gz && \
|
tar -xzf boost_1_73_0.tar.gz && \
|
||||||
rm boost_1_73_0.tar.gz && \
|
rm boost_1_73_0.tar.gz && \
|
||||||
|
|||||||
+19
-4
@@ -96,13 +96,28 @@ Clone the repository.
|
|||||||
```bash
|
```bash
|
||||||
git clone --recursive https://git.wownero.com/wowlet/wowlet.git
|
git clone --recursive https://git.wownero.com/wowlet/wowlet.git
|
||||||
```
|
```
|
||||||
|
Download Qt5.15.1 from here:
|
||||||
|
https://download.qt.io/archive/qt/5.15/5.15.1/single/
|
||||||
|
and build Qt 5.15.1:
|
||||||
|
|
||||||
Get the latest LTS from here: https://www.qt.io/offline-installers and install.
|
Qt build on Mac OS:
|
||||||
|
|
||||||
Build WOWlet.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
CMAKE_PREFIX_PATH=~/Qt5.15.1/5.15.1/clang_64 make mac-release
|
cd ~/Downloads/qt-everywhere-src-5.15.1
|
||||||
|
./configure -prefix $PWD/qtbase -release -nomake examples -nomake tests -skip qtwebchannel -skip qtpurchasing -skip webengine -skip qtwebview
|
||||||
|
make -j 4
|
||||||
|
```
|
||||||
|
|
||||||
|
Build WOWlet:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CMAKE_PREFIX_PATH=/Users/$username/Downloads/qt-everywhere-src-5.15.1/qtbase/ make mac-release
|
||||||
|
```
|
||||||
|
|
||||||
|
Install and start tor service for ticker/forums:
|
||||||
|
```bash
|
||||||
|
brew install tor
|
||||||
|
brew services start tor
|
||||||
```
|
```
|
||||||
|
|
||||||
The resulting Mac OS application can be found `build/bin/wowlet.app` and will **not** have Tor embedded.
|
The resulting Mac OS application can be found `build/bin/wowlet.app` and will **not** have Tor embedded.
|
||||||
|
|||||||
+26
-4
@@ -100,8 +100,21 @@ 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);
|
||||||
|
|
||||||
// Tor & socks proxy
|
// init backend URLs
|
||||||
this->ws = new WSClient(this, wsUrl);
|
if(cmdargs->isSet("backend-host"))
|
||||||
|
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);
|
||||||
@@ -171,13 +184,19 @@ 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 && wsUrl.contains(".onion")) {
|
if (!isWhonix && backendHost.contains(".onion")) {
|
||||||
|
qDebug() << "'backend-host' did not contain '.onion' - running without Tor proxy.";
|
||||||
this->networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
|
this->networkProxy = new QNetworkProxy(QNetworkProxy::Socks5Proxy, Tor::torHost, Tor::torPort);
|
||||||
this->network->setProxy(*networkProxy);
|
this->network->setProxy(*networkProxy);
|
||||||
this->ws->webSocket.setProxy(*networkProxy);
|
this->ws->webSocket.setProxy(*networkProxy);
|
||||||
@@ -421,7 +440,10 @@ 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());
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -66,7 +66,13 @@ 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 = "";
|
||||||
@@ -106,6 +112,7 @@ 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
|
||||||
@@ -205,6 +212,7 @@ 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 pinLookupReceived(QString address, QString pin);
|
void pinLookupReceived(QString address, QString pin);
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 148 KiB |
+74
-7
@@ -32,17 +32,22 @@ 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));
|
||||||
@@ -52,6 +57,68 @@ 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);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ 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:
|
||||||
@@ -30,9 +31,11 @@ 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);
|
||||||
@@ -50,6 +53,8 @@ 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
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ 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);
|
||||||
@@ -101,6 +102,7 @@ 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());
|
||||||
|
|||||||
@@ -183,14 +183,14 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="12" column="0">
|
<item row="13" 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="12" column="1">
|
<item row="13" 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="13" column="1">
|
<item row="14" 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="14" column="0">
|
<item row="15" 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="14" column="1">
|
<item row="15" 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="15" column="0">
|
<item row="16" 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="15" column="1">
|
<item row="16" 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="16" column="0">
|
<item row="17" 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="16" column="1">
|
<item row="17" 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="20" column="0">
|
<item row="21" 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="20" column="1">
|
<item row="21" 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="19" column="0">
|
<item row="20" 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="19" column="1">
|
<item row="20" 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="18" column="1">
|
<item row="19" 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,20 +316,34 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="17" column="1">
|
<item row="18" 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="17" column="0">
|
<item row="18" 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>
|
||||||
|
|||||||
@@ -107,6 +107,15 @@ 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();
|
||||||
|
|||||||
+26
-3
@@ -108,11 +108,14 @@ 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 WOW payment");
|
m_trayActionSend->setStatusTip("Send a 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");
|
||||||
@@ -120,6 +123,7 @@ 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);
|
||||||
@@ -127,6 +131,7 @@ 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);
|
||||||
@@ -303,6 +308,7 @@ 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);
|
||||||
@@ -632,6 +638,7 @@ 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());
|
||||||
@@ -966,7 +973,6 @@ void MainWindow::menuNewRestoreClicked() {
|
|||||||
|
|
||||||
void MainWindow::menuQuitClicked() {
|
void MainWindow::menuQuitClicked() {
|
||||||
cleanupBeforeClose();
|
cleanupBeforeClose();
|
||||||
|
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1036,9 +1042,16 @@ void MainWindow::skinChanged(const QString &skinName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent *event) {
|
void MainWindow::closeEvent(QCloseEvent *event) {
|
||||||
cleanupBeforeClose();
|
auto hideOnClose = config()->get(Config::hideOnClose).toBool();
|
||||||
|
if(hideOnClose && !this->isHidden()) {
|
||||||
|
this->hide();
|
||||||
|
event->ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupBeforeClose();
|
||||||
QWidget::closeEvent(event);
|
QWidget::closeEvent(event);
|
||||||
|
QApplication::exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::donateButtonClicked() {
|
void MainWindow::donateButtonClicked() {
|
||||||
@@ -1052,15 +1065,25 @@ void MainWindow::donateButtonClicked() {
|
|||||||
|
|
||||||
void MainWindow::showHistoryTab() {
|
void MainWindow::showHistoryTab() {
|
||||||
this->raise();
|
this->raise();
|
||||||
|
this->show();
|
||||||
ui->tabWidget->setCurrentIndex(Tabs::HISTORY);
|
ui->tabWidget->setCurrentIndex(Tabs::HISTORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::showSendTab() {
|
void MainWindow::showSendTab() {
|
||||||
this->raise();
|
this->raise();
|
||||||
|
this->show();
|
||||||
ui->tabWidget->setCurrentIndex(Tabs::SEND);
|
ui->tabWidget->setCurrentIndex(Tabs::SEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::showHomeWindow() {
|
||||||
|
this->raise();
|
||||||
|
this->show();
|
||||||
|
ui->tabWidget->setCurrentIndex(Tabs::HOME);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::showCalcWindow() {
|
void MainWindow::showCalcWindow() {
|
||||||
|
this->raise();
|
||||||
|
this->show();
|
||||||
m_windowCalc->show();
|
m_windowCalc->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ 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();
|
||||||
@@ -200,6 +201,7 @@ 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;
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ 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
|
||||||
@@ -40,6 +45,7 @@ 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();
|
||||||
|
|||||||
@@ -198,6 +198,13 @@
|
|||||||
</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">
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
|||||||
{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::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}},
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ public:
|
|||||||
firstRun,
|
firstRun,
|
||||||
hideBalance,
|
hideBalance,
|
||||||
hideFiatBalance,
|
hideFiatBalance,
|
||||||
|
hideOnClose,
|
||||||
redditFrontend,
|
redditFrontend,
|
||||||
showHistorySyncNotice,
|
showHistorySyncNotice,
|
||||||
ignoreUpdateWarning,
|
ignoreUpdateWarning,
|
||||||
|
|||||||
@@ -8,18 +8,18 @@
|
|||||||
#include "wsclient.h"
|
#include "wsclient.h"
|
||||||
#include "appcontext.h"
|
#include "appcontext.h"
|
||||||
|
|
||||||
WSClient::WSClient(AppContext *ctx, const QString &url, QObject *parent) :
|
WSClient::WSClient(AppContext *ctx, 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 = url.contains(".onion");
|
m_tor = m_ctx->backendHost.contains(".onion");
|
||||||
this->url = QString("ws://%1/ws").arg(url);
|
|
||||||
|
|
||||||
// Keep websocket connection alive
|
// keep-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(QUrl(this->url));
|
this->webSocket.open(QString("%1/ws").arg(m_ctx->backendWSUrl));
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -14,11 +14,10 @@ class WSClient : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit WSClient(AppContext *ctx, const QString &url, QObject *parent = nullptr);
|
explicit WSClient(AppContext *ctx, 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();
|
||||||
|
|||||||
@@ -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("http://%1/suchwow").arg(this->m_ctx->wsUrl);
|
m_weburl = QString("%1/suchwow").arg(this->m_ctx->backendHTTPUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuchWowPost::onThumbReceived(QByteArray data) {
|
void SuchWowPost::onThumbReceived(QByteArray data) {
|
||||||
|
|||||||
Reference in New Issue
Block a user