From: tobtoht Date: Thu, 23 Jun 2022 17:48:30 +0000 (+0200) Subject: Home: bounties.monero.social X-Git-Url: https://git.nutra.tk/v2?a=commitdiff_plain;h=3c7f1800c2ba3ee291f71b1442fcd0521efe5997;p=gamesguru%2Ffeather.git Home: bounties.monero.social --- diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index a477f388..302b0bef 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -62,6 +62,7 @@ MainWindow::MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *pa // Websocket notifier connect(websocketNotifier(), &WebsocketNotifier::CCSReceived, ui->ccsWidget->model(), &CCSModel::updateEntries); + connect(websocketNotifier(), &WebsocketNotifier::BountyReceived, ui->bountiesWidget->model(), &BountiesModel::updateBounties); connect(websocketNotifier(), &WebsocketNotifier::RedditReceived, ui->redditWidget->model(), &RedditModel::updatePosts); connect(websocketNotifier(), &WebsocketNotifier::RevuoReceived, ui->revuoWidget, &RevuoWidget::updateItems); connect(websocketNotifier(), &WebsocketNotifier::UpdatesReceived, this, &MainWindow::onUpdatesAvailable); @@ -373,6 +374,7 @@ void MainWindow::initHome() { ui->fiatTickerLayout->addWidget(m_balanceTickerWidget); connect(ui->ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen); + connect(ui->bountiesWidget, &BountiesWidget::donate, this, &MainWindow::fillSendTab); connect(ui->redditWidget, &RedditWidget::setStatusText, this, &MainWindow::setStatusText); connect(ui->revuoWidget, &RevuoWidget::donate, [this](const QString &address, const QString &description){ m_sendWidget->fill(address, description); @@ -935,6 +937,11 @@ void MainWindow::showSendTab() { ui->tabWidget->setCurrentIndex(Tabs::SEND); } +void MainWindow::fillSendTab(const QString &address, const QString &description) { + m_sendWidget->fill(address, description); + ui->tabWidget->setCurrentIndex(Tabs::SEND); +} + void MainWindow::showCalcWindow() { m_windowCalc->show(); } diff --git a/src/MainWindow.h b/src/MainWindow.h index cdfe795b..b8fdfa2f 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -215,6 +215,7 @@ private: void updateWidgetIcons(); bool verifyPassword(); void patchStylesheetMac(); + void fillSendTab(const QString &address, const QString &description); void userActivity(); void checkUserActivity(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 035666ec..513a251f 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -123,6 +123,28 @@ + + + Bounties + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + /r/Monero @@ -899,6 +921,12 @@
widgets/RevuoWidget.h
1 + + BountiesWidget + QWidget +
widgets/BountiesWidget.h
+ 1 +
diff --git a/src/model/BountiesModel.cpp b/src/model/BountiesModel.cpp new file mode 100644 index 00000000..8f999bff --- /dev/null +++ b/src/model/BountiesModel.cpp @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include "BountiesModel.h" + +BountiesModel::BountiesModel(QObject *parent) + : QAbstractTableModel(parent) +{ + +} + +void BountiesModel::clear() { + beginResetModel(); + + m_bounties.clear(); + + endResetModel(); +} + +void BountiesModel::updateBounties(const QList> &posts) { + beginResetModel(); + + m_bounties.clear(); + for (const auto& post : posts) { + m_bounties.push_back(post); + } + + endResetModel(); +} + +int BountiesModel::rowCount(const QModelIndex &parent) const{ + if (parent.isValid()) { + return 0; + } + return m_bounties.count(); +} + +int BountiesModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return ModelColumn::COUNT; +} + +QVariant BountiesModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= m_bounties.count()) + return {}; + + QSharedPointer post = m_bounties.at(index.row()); + + if(role == Qt::DisplayRole) { + switch(index.column()) { + case Votes: + return QString::number(post->votes); + case Title: + return post->title; + case Status: + return post->status; + case Bounty: { + if (post->bountyAmount > 0) { + return QString("%1 XMR").arg(QString::number(post->bountyAmount, 'f', 5)); + } + return "None"; + } + default: + return {}; + } + } + else if (role == Qt::TextAlignmentRole) { + switch(index.column()) { + case Votes: + case Status: + case Bounty: + return Qt::AlignRight; + default: + return {}; + } + } + return {}; +} + +QVariant BountiesModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) + { + switch(section) { + case Votes: + return QString("🡅"); + case Title: + return QString("Title"); + case Status: + return QString("Status"); + case Bounty: + return QString("Bounty"); + default: + return QVariant(); + } + } + return QVariant(); +} + +QSharedPointer BountiesModel::post(int row) { + if (row < 0 || row >= m_bounties.size()) { + qCritical("%s: no reddit post for index %d", __FUNCTION__, row); + return QSharedPointer(); + } + + return m_bounties.at(row); +} \ No newline at end of file diff --git a/src/model/BountiesModel.h b/src/model/BountiesModel.h new file mode 100644 index 00000000..21aecb73 --- /dev/null +++ b/src/model/BountiesModel.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef FEATHER_BOUNTIESMODEL_H +#define FEATHER_BOUNTIESMODEL_H + +#include +#include + +#include "widgets/Bounty.h" + +class BountiesModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + enum ModelColumn + { + Title = 0, + Votes, + Status, + Bounty, + COUNT + }; + + explicit BountiesModel(QObject *parent); + + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + void clear(); + void updateBounties(const QList>& posts); + + QSharedPointer post(int row); + +private: + QList> m_bounties; +}; + + +#endif //FEATHER_BOUNTIESMODEL_H diff --git a/src/utils/WebsocketNotifier.cpp b/src/utils/WebsocketNotifier.cpp index 5ba833ed..6414a70a 100644 --- a/src/utils/WebsocketNotifier.cpp +++ b/src/utils/WebsocketNotifier.cpp @@ -55,6 +55,11 @@ void WebsocketNotifier::onWSMessage(const QJsonObject &msg) { this->onWSCCS(ccs_data); } + else if(cmd == "bounties") { + auto data = msg.value("data").toArray(); + this->onWSBounties(data); + } + else if(cmd == "txFiatHistory") { auto txFiatHistory_data = msg.value("data").toObject(); emit TxFiatHistoryReceived(txFiatHistory_data); @@ -151,10 +156,6 @@ void WebsocketNotifier::onWSReddit(const QJsonArray& reddit_data) { void WebsocketNotifier::onWSCCS(const QJsonArray &ccs_data) { QList> l; - QStringList fonts = {"state", "address", "author", "date", - "title", "target_amount", "raised_amount", - "percentage_funded", "contributions"}; - for (auto &&entry: ccs_data) { auto obj = entry.toObject(); auto c = QSharedPointer(new CCSEntry()); @@ -201,6 +202,24 @@ void WebsocketNotifier::onWSRevuo(const QJsonArray &revuo_data) { emit RevuoReceived(l); } +void WebsocketNotifier::onWSBounties(const QJsonArray &bounties_data) { + QList> l; + + for (const auto& entry : bounties_data) { + QJsonObject obj = entry.toObject(); + auto bounty = new BountyEntry(obj.value("votes").toInt(), + obj.value("title").toString(), + obj.value("amount").toDouble(), + obj.value("link").toString(), + obj.value("address").toString(), + obj.value("status").toString()); + QSharedPointer b = QSharedPointer(bounty); + l.append(b); + } + + emit BountyReceived(l); +} + void WebsocketNotifier::onWSUpdates(const QJsonObject &updates) { emit UpdatesReceived(updates); } diff --git a/src/utils/WebsocketNotifier.h b/src/utils/WebsocketNotifier.h index a0fff999..deeef78a 100644 --- a/src/utils/WebsocketNotifier.h +++ b/src/utils/WebsocketNotifier.h @@ -11,6 +11,7 @@ #include "networktype.h" #include "nodes.h" #include "prices.h" +#include "widgets/Bounty.h" #include "widgets/RedditPost.h" #include "widgets/CCSEntry.h" #include "widgets/RevuoItem.h" @@ -37,6 +38,7 @@ signals: void FiatRatesReceived(const QJsonObject &fiat_rates); void RedditReceived(QList> L); void CCSReceived(QList> L); + void BountyReceived(QList> L); void RevuoReceived(QList> L); void TxFiatHistoryReceived(const QJsonObject &data); void UpdatesReceived(const QJsonObject &updates); @@ -51,6 +53,7 @@ private slots: void onWSNodes(const QJsonArray &nodes); void onWSReddit(const QJsonArray &reddit_data); void onWSCCS(const QJsonArray &ccs_data); + void onWSBounties(const QJsonArray &bounties_data); void onWSRevuo(const QJsonArray &revuo_data); void onWSUpdates(const QJsonObject &updates); void onWSXMRigDownloads(const QJsonObject &downloads); diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 426f96bf..ed44c821 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -79,6 +79,7 @@ static const QHash configStrings = { {Config::blockExplorer,{QS("blockExplorer"), "exploremonero.com"}}, {Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}}, {Config::localMoneroFrontend, {QS("localMoneroFrontend"), "https://localmonero.co"}}, + {Config::bountiesFrontend, {QS("bountiesFrontend"), "https://bounties.monero.social"}}, {Config::fiatSymbols, {QS("fiatSymbols"), QStringList{"USD", "EUR", "GBP", "CAD", "AUD", "RUB"}}}, {Config::cryptoSymbols, {QS("cryptoSymbols"), QStringList{"BTC", "ETH", "LTC", "XMR", "ZEC"}}}, diff --git a/src/utils/config.h b/src/utils/config.h index cc3ca7ff..e85cf5fe 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -83,6 +83,7 @@ public: blockExplorer, redditFrontend, localMoneroFrontend, + bountiesFrontend, fiatSymbols, cryptoSymbols, diff --git a/src/widgets/BountiesWidget.cpp b/src/widgets/BountiesWidget.cpp new file mode 100644 index 00000000..152afd09 --- /dev/null +++ b/src/widgets/BountiesWidget.cpp @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include "BountiesWidget.h" +#include "ui_BountiesWidget.h" + +#include +#include +#include + +#include "model/BountiesModel.h" +#include "utils/Utils.h" +#include "utils/config.h" + +BountiesWidget::BountiesWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::BountiesWidget) + , m_model(new BountiesModel(this)) + , m_contextMenu(new QMenu(this)) +{ + ui->setupUi(this); + ui->tableView->setModel(m_model); + this->setupTable(); + + m_contextMenu->addAction("View Bounty", this, &BountiesWidget::linkClicked); + m_contextMenu->addAction("Donate", this, &BountiesWidget::donateClicked); + connect(ui->tableView, &QHeaderView::customContextMenuRequested, this, &BountiesWidget::showContextMenu); + + connect(ui->tableView, &QTableView::doubleClicked, this, &BountiesWidget::linkClicked); + + ui->tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); +} + +BountiesModel * BountiesWidget::model() { + return m_model; +} + +void BountiesWidget::linkClicked() { + QModelIndex index = ui->tableView->currentIndex(); + auto post = m_model->post(index.row()); + + if (post) + Utils::externalLinkWarning(this, this->getLink(post->link)); +} + +void BountiesWidget::donateClicked() { + QModelIndex index = ui->tableView->currentIndex(); + auto bounty = m_model->post(index.row()); + + if (bounty) { + emit donate(bounty->donationAddress, QString("Bounty: %1").arg(bounty->title)); + } +} + +void BountiesWidget::setupTable() { + ui->tableView->verticalHeader()->setVisible(false); + ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + + ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); +} + +void BountiesWidget::showContextMenu(const QPoint &pos) { + QModelIndex index = ui->tableView->indexAt(pos); + if (!index.isValid()) { + return; + } + + m_contextMenu->exec(ui->tableView->viewport()->mapToGlobal(pos)); +} + +QString BountiesWidget::getLink(const QString &permaLink) { + QString frontend = config()->get(Config::bountiesFrontend).toString(); + return QString("%1/%2").arg(frontend, permaLink); +} + +BountiesWidget::~BountiesWidget() = default; \ No newline at end of file diff --git a/src/widgets/BountiesWidget.h b/src/widgets/BountiesWidget.h new file mode 100644 index 00000000..548e1c21 --- /dev/null +++ b/src/widgets/BountiesWidget.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef FEATHER_BOUNTIESWIDGET_H +#define FEATHER_BOUNTIESWIDGET_H + +#include +#include +#include + +#include "model/BountiesModel.h" + +namespace Ui { + class BountiesWidget; +} + +class BountiesWidget : public QWidget +{ + Q_OBJECT + +public: + explicit BountiesWidget(QWidget *parent = nullptr); + ~BountiesWidget() override; + BountiesModel* model(); + +public slots: + void linkClicked(); + +signals: + void setStatusText(const QString &msg, bool override, int timeout); + void donate(const QString &address, const QString &description); + +private: + void setupTable(); + void showContextMenu(const QPoint &pos); + void donateClicked(); + QString getLink(const QString &permaLink); + + QScopedPointer ui; + BountiesModel *m_model; + QMenu *m_contextMenu; +}; + +#endif //FEATHER_BOUNTIESWIDGET_H diff --git a/src/widgets/BountiesWidget.ui b/src/widgets/BountiesWidget.ui new file mode 100644 index 00000000..d4e985af --- /dev/null +++ b/src/widgets/BountiesWidget.ui @@ -0,0 +1,40 @@ + + + BountiesWidget + + + + 0 + 0 + 566 + 372 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::CustomContextMenu + + + + + + + + diff --git a/src/widgets/Bounty.h b/src/widgets/Bounty.h new file mode 100644 index 00000000..7dfd9edd --- /dev/null +++ b/src/widgets/Bounty.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef FEATHER_BOUNTY_H +#define FEATHER_BOUNTY_H + +#include +#include + +struct BountyEntry { + BountyEntry(int votes, QString title, double bountyAmount, QString link, QString donationAddress, QString status) + : votes(votes), title(std::move(title)), bountyAmount(bountyAmount), link(std::move(link)), + donationAddress(std::move(donationAddress)), status(std::move(status)){}; + + int votes; + QString title; + double bountyAmount; + QString link; + QString donationAddress; + QString status; +}; + +#endif //FEATHER_BOUNTY_H