diff --git a/CMakeLists.txt b/CMakeLists.txt index 8becdef..2274535 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ option(DONATE_BEG "Prompt donation window every once in a while" OFF) option(WITH_SCANNER "Enable webcam QR scanner" ON) option(STACK_TRACE "Dump stack trace on crash (Linux only)" OFF) -# Plugins +# option(WITH_PLUGIN_HOME "Include Home tab plugin" ON) option(WITH_PLUGIN_TICKERS "Include Tickers Home plugin" ON) option(WITH_PLUGIN_CROWDFUNDING "Include Crowdfunding Home plugin" ON) @@ -117,7 +117,7 @@ if(WITH_SCANNER) endif() # libzip -if(CHECK_UPDATES) +if(CHECK_UPDATES OR WITH_PLUGIN_ATOMIC) set(ZLIB_USE_STATIC_LIBS "ON") message("libzip inclueded") find_package(ZLIB REQUIRED) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 416e56e..8a9410c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -301,11 +301,11 @@ if (WITH_SCANNER) ) endif() - +if (WITH_PLUGIN_ATOMIC) FIND_PACKAGE(LibArchive REQUIRED) INCLUDE_DIRECTORIES(${LibArchive_INCLUDE_DIR}) target_link_libraries(feather PRIVATE ${LibArchive_LIBRARIES}) - +endif() if(STATIC AND APPLE) target_link_libraries(feather PRIVATE Qt6::QDarwinCameraPermissionPlugin) diff --git a/src/plugins/atomic/AtomicPlugin.h b/src/plugins/atomic/AtomicPlugin.h index abdcd2b..10cf4a3 100644 --- a/src/plugins/atomic/AtomicPlugin.h +++ b/src/plugins/atomic/AtomicPlugin.h @@ -6,6 +6,7 @@ #include "plugins/Plugin.h" #include "AtomicWidget.h" +#include "Offer.h" class AtomicPlugin : public Plugin { Q_OBJECT @@ -26,7 +27,6 @@ public: QDialog* configDialog(QWidget *parent) override; void initialize(Wallet *wallet, QObject *parent) override; - static AtomicPlugin* create() { return new AtomicPlugin(); } public slots: diff --git a/src/plugins/atomic/AtomicWidget.cpp b/src/plugins/atomic/AtomicWidget.cpp index e4c5323..5605d30 100644 --- a/src/plugins/atomic/AtomicWidget.cpp +++ b/src/plugins/atomic/AtomicWidget.cpp @@ -5,8 +5,10 @@ #include "ui_AtomicWidget.h" #include +#include #include "AtomicConfigDialog.h" +#include "OfferModel.h" #include "utils/AppData.h" #include "utils/ColorScheme.h" #include "utils/config.h" @@ -15,6 +17,8 @@ AtomicWidget::AtomicWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::AtomicWidget) + , o_model(new OfferModel(this)) + , offerList(new QList>()) { ui->setupUi(this); @@ -30,7 +34,15 @@ AtomicWidget::AtomicWidget(QWidget *parent) QValidator *validator = new QRegularExpressionValidator(rx, this); ui->lineFrom->setValidator(validator); ui->lineTo->setValidator(validator); + ui->offerBookTable->setModel(o_model); + ui->offerBookTable->setSortingEnabled(true); + ui->offerBookTable->sortByColumn(0, Qt::SortOrder::AscendingOrder); + ui->offerBookTable->verticalHeader()->setVisible(false); + ui->offerBookTable->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->offerBookTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui->offerBookTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); + //ui->offerBookTable-> connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &AtomicWidget::onPricesReceived); connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &AtomicWidget::onPricesReceived); @@ -42,6 +54,40 @@ AtomicWidget::AtomicWidget(QWidget *parent) connect(ui->btn_configure, &QPushButton::clicked, this, &AtomicWidget::showAtomicConfigureDialog); + connect(ui->btn_refreshOffer, &QPushButton::clicked, this, [this]{ + offerList->clear(); + + auto m_instance = Config::instance(); + QStringList pointList = m_instance->get(Config::rendezVous).toStringList(); + for(QString point :pointList) + AtomicWidget::list(point); + + /* + QList> tempList; + for (int i=0; iappend(offer); + } + } + qDebug() << "done"; + + /*for(auto offer: AtomicWidget::list(Config::instance()->get(Config::rendezVous).toStringList()[0])){ + offerList->append(offer); + } + o_model->updateOffers(*offerList); + + */ + }); + QTimer::singleShot(1, [this]{ this->skinChanged(); }); @@ -167,4 +213,57 @@ void AtomicWidget::updateStatus() { } } +void AtomicWidget::list(QString rendezvous) { + QStringList arguments; + QList> list; + auto m_instance = Config::instance(); + arguments << "--data-base-dir"; + arguments << Config::defaultConfigDir().absolutePath(); + // Remove after testing + //arguments << "--testnet"; + arguments << "-j"; + arguments << "list-sellers"; + arguments << "--tor-socks5-port"; + arguments << m_instance->get(Config::socks5Port).toString(); + arguments << "--rendezvous-point"; + arguments << rendezvous; + auto *swap = new QProcess(); + swap->setReadChannel(QProcess::StandardOutput); + //swap->start(m_instance->get(Config::swapPath).toString(), arguments); + connect(swap, &QProcess::finished, this, [this, swap]{ + QJsonDocument parsedLine; + QJsonParseError parseError; + QList> list; + qDebug() << "Subprocess has finished"; + auto output = QString::fromLocal8Bit(swap->readAllStandardError()); + qDebug() << "Crashes before splitting"; + auto lines = output.split(QRegularExpression("[\r\n]"),Qt::SkipEmptyParts); + qDebug() << lines.size(); + qDebug() << "parsing Output"; + + + for(auto line : lines){ + qDebug() << line; + if(line.contains("status")){ + qDebug() << "status contained"; + parsedLine = QJsonDocument::fromJson(line.toLocal8Bit(), &parseError ); + if (parsedLine["fields"]["status"].toString().contains("Online")){ + OfferEntry entry = {parsedLine["fields"]["price"].toDouble(),parsedLine["fields"]["min_quantity"].toDouble(),parsedLine["fields"]["max_quantity"].toDouble(), parsedLine["fields"]["address"].toString()}; + offerList->append(QSharedPointer(&entry)); + qDebug() << &entry; + } + } + qDebug() << "next line"; + } + qDebug() << "exits fine"; + swap->close(); + return list; + }); + swap->start("/home/dev/.config/feather/swap", arguments); + //swap->waitForFinished(120000); + + + +} + AtomicWidget::~AtomicWidget() = default; \ No newline at end of file diff --git a/src/plugins/atomic/AtomicWidget.h b/src/plugins/atomic/AtomicWidget.h index da65c29..aaf1b9b 100644 --- a/src/plugins/atomic/AtomicWidget.h +++ b/src/plugins/atomic/AtomicWidget.h @@ -7,6 +7,10 @@ #include #include #include +#include +#include + +#include "OfferModel.h" namespace Ui { class AtomicWidget; @@ -19,6 +23,7 @@ Q_OBJECT public: explicit AtomicWidget(QWidget *parent = nullptr); ~AtomicWidget() override; + void list(QString rendezvous); public slots: void skinChanged(); @@ -36,6 +41,8 @@ private: QScopedPointer ui; bool m_comboBoxInit = false; QTimer m_statusTimer; + OfferModel *o_model; + QList> *offerList; }; #endif // FEATHER_ATOMICWIDGET_H diff --git a/src/plugins/atomic/AtomicWidget.ui b/src/plugins/atomic/AtomicWidget.ui index 2f3236f..aa5a21e 100644 --- a/src/plugins/atomic/AtomicWidget.ui +++ b/src/plugins/atomic/AtomicWidget.ui @@ -1,187 +1,191 @@ - AtomicWidget - - - - 0 - 0 - 800 - 366 - + AtomicWidget + + + + 0 + 0 + 800 + 366 + + + + MainWindow + + + + + + QFrame::Shape::StyledPanel + + + QFrame::Shadow::Raised + + + + + + + 0 + 0 + - - MainWindow + + icon - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 0 - 0 - - - - icon - - - - - - - Qt::Horizontal - - - QSizePolicy::Maximum - - - - 10 - 20 - - - - - - - - Warning text - - - - - - - - - - 18 - - - - - 0 - - - 0 - - - - - - 0 - 0 - - - - true - - - From... - - - - - - - - - - - - exchange image - - - - - - - 0 - - - - - - 0 - 0 - - - - false - - - To... - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Configure - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Maximum + + + + 10 + 20 + + + + + + + + Warning text + + + + - - - DoublePixmapLabel - QLabel -
components.h
-
-
- - - - fromChanged(QString) - toChanged(QString) - toComboChanged(QString) - +
+ + + + 18 + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + From... + + + + + + + + + + + + exchange image + + + + + + + 0 + + + + + + 0 + 0 + + + + false + + + To... + + + + + + + + + + + + + + + + + + + Refresh Offer Book + + + + + + + Add Rendezvous Point + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Configure + + + + + +
+
+ + + DoublePixmapLabel + QLabel +
components.h
+
+
+ + + + fromChanged(QString) + toChanged(QString) + toComboChanged(QString) +
diff --git a/src/plugins/atomic/Offer.h b/src/plugins/atomic/Offer.h new file mode 100644 index 0000000..0940041 --- /dev/null +++ b/src/plugins/atomic/Offer.h @@ -0,0 +1,20 @@ +// +// Created by dev on 5/23/24. +// + +#ifndef FEATHER_OFFER_H +#define FEATHER_OFFER_H + +#include + +struct OfferEntry { + OfferEntry(double price, double min, double max, QString address ) + : price(price), min(min), max(max), address(std::move(address)) {}; + + double price; + double min; + double max; + QString address; +}; + +#endif //FEATHER_OFFER_H \ No newline at end of file diff --git a/src/plugins/atomic/OfferModel.cpp b/src/plugins/atomic/OfferModel.cpp new file mode 100644 index 0000000..e4092c8 --- /dev/null +++ b/src/plugins/atomic/OfferModel.cpp @@ -0,0 +1,124 @@ +// +// Created by dev on 5/23/24. +// + +#include "OfferModel.h" + + +OfferModel::OfferModel(QObject *parent) + : QAbstractTableModel(parent) +{ + +} + +void OfferModel::clear() { + beginResetModel(); + + m_offers.clear(); + + endResetModel(); +} + +void OfferModel::updateOffers(const QList> &posts) { + beginResetModel(); + qDebug() << "updating Offers"; + m_offers.clear(); + for (const auto& post : posts) { + m_offers.push_back(post); + } + + endResetModel(); +} + +int OfferModel::rowCount(const QModelIndex &parent) const{ + if (parent.isValid()) { + return 0; + } + return m_offers.count(); +} + +int OfferModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return OfferModel::ModelColumn::COUNT; +} + +QVariant OfferModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= m_offers.count()) + return {}; + + QSharedPointer post = m_offers.at(index.row()); + + if(role == Qt::DisplayRole || role == Qt::UserRole) { + switch(index.column()) { + case Price: { + if (role == Qt::UserRole) { + return post->price; + } + return QString::number(post->price); + } + case Address: + return post->address; + case Min_Amount:{ + if (role == Qt::UserRole) { + return post->min; + } + return QString::number(post->min); + } + case Max_Amount: { + if (role == Qt::UserRole) { + return post->max; + } + return QString::number(post->max); + } + default: + return {}; + } + } + else if (role == Qt::TextAlignmentRole) { + switch(index.column()) { + case Price: + case Min_Amount: + case Max_Amount: + return Qt::AlignRight; + default: + return {}; + } + } + return {}; +} + +QVariant OfferModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) + { + switch(section) { + case Price: + return QString("Price (BTC) "); + case Min_Amount: + return QString("Min Amount (BTC)"); + case Max_Amount: + return QString("Max Amount (BTC)"); + case Address: + return QString("P2P Vendor Address"); + default: + return QVariant(); + } + } + return QVariant(); +} + +QSharedPointer OfferModel::post(int row) { + if (row < 0 || row >= m_offers.size()) { + qCritical("%s: no reddit post for index %d", __FUNCTION__, row); + return QSharedPointer(); + } + + return m_offers.at(row); +} \ No newline at end of file diff --git a/src/plugins/atomic/OfferModel.h b/src/plugins/atomic/OfferModel.h new file mode 100644 index 0000000..d6aded3 --- /dev/null +++ b/src/plugins/atomic/OfferModel.h @@ -0,0 +1,42 @@ +// +// Created by dev on 5/23/24. +// + +#ifndef FEATHER_OFFERMODEL_H +#define FEATHER_OFFERMODEL_H +#include + +#include "Offer.h" + +class OfferModel : public QAbstractTableModel +{ +Q_OBJECT + +public: + enum ModelColumn + { + Price = 0, + Min_Amount, + Max_Amount, + Address, + COUNT + }; + + explicit OfferModel(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 updateOffers(const QList>& posts); + + QSharedPointer post(int row); + +private: + QList> m_offers; +}; + + +#endif //FEATHER_OFFERMODEL_H diff --git a/src/plugins/atomic/README.md b/src/plugins/atomic/README.md index cb18983..00ebe75 100644 --- a/src/plugins/atomic/README.md +++ b/src/plugins/atomic/README.md @@ -4,8 +4,13 @@ Built in xmr-btc atomic swap ## Installation ## Hacking -sudo apt install -Install KArchive +sudo apt install libarchive-dev + +Functions used to control swap (AtomicPlugin.cpp) + +withdraw(btcaddress) - withdraw btc +list(rendezvous point) - list sellers at rendezvous + ## Usage Navigate to the Atomic tab after opening your wallet. Click the configure button. diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 3ad5eb3..e7878dc 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -142,11 +142,10 @@ static const QHash configStrings = { {Config::tickersShowFiatBalance, {QS("tickersShowFiatBalance"), true}}, // Atomic - {Config::rendezVous, {QS("rendezVous"), QStringList{"/dns4/xmr-btc-asb.coblox.tech/tcp/9939/p2p/12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi", - "/dnsaddr/atomic.money/p2p/12D3KooWNfiwKyDpAbW7XSgw5xmoMJzMXsJxR91FbUJiuWU1vBGb", - "/dnsaddr/xmr.darkness.su/p2p/12D3KooWLWpQtmuPoQvMJxs6KRGMrc39ohkNbRNaXWJhW3DfQD6e", - "/dnsaddr/swapanarchy.cfd/p2p/12D3KooWMgGjeW7ErQxCQzaeHiXxJn42wegCPFepixEXfBJT1PNS", - "/onion3/spqfqxirmlrhq7gbiwn4jn35c77gu2kof26i6psoc6bbyduol3zty6qd:9841/p2p/12D3KooWM9ipr33nEtxyCBF7fdbHsMrRzHaSf1bEVYzV8XSBSMet"}}}, + {Config::rendezVous, {QS("rendezVous"), QStringList{"/dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE", + "/dns4/eratosthen.es/tcp/7798/p2p/12D3KooWAh7EXXa2ZyegzLGdjvj1W4G3EXrTGrf6trraoT1MEobs", + "/dnsaddr/rendezvous.coblox.tech/p2p/12D3KooWQUt9DkNZxEn2R5ymJzWj15MpG6mTW84kyd8vDaRZi46o", + "/dns4/swap.sethforprivacy.com/tcp/8888/p2p/12D3KooWCULyZKuV9YEkb6BX8FuwajdvktSzmMg4U5ZX2uYZjHeu"}}}, {Config::swapPath, {QS("swapPath"), ""}}, {Config::operatingSystem, {QS("operatingSystem"), OS}}, };