Compare commits

...

40 Commits
master ... chat

Author SHA1 Message Date
Duke Leto aed5e373f6 fix json compile issues 4 years ago
Duke Leto f45d208ea2 Merge branch 'duke' into chat 4 years ago
Duke Leto efc00392f4 Fix wrong type of comments in our project file 4 years ago
Duke Leto ea495c9f69 Add a bunch of debug statements 4 years ago
Duke Leto c54b3114d7 No need to validate our own zaddrs, logging + copyright headers 4 years ago
Duke Leto 009a7b93c2 Merge stuff 4 years ago
Duke Leto efa3a04c88 Merge branch 'duke' into chat 4 years ago
Duke Leto c9d919c62e Merge branch 'duke' into chat 4 years ago
Duke Leto 6c8e262eb4 Bless Satoshi 4 years ago
Duke Leto 5496ae4e41 Create new zaddrs at run-time for new HushContacts 4 years ago
Duke Leto 676f75e2c8 Remove incorrect comment 4 years ago
Duke Leto 9b0510da50 Add some debug 4 years ago
Duke Leto 603e0298d0 Header memos should get their zaddr from the contact object; dynamic zaddr generation not working just yet 4 years ago
Duke Leto cd729c56c8 Find or create our custom HushChat zaddr for each contact when sending a memo 4 years ago
Duke Leto ad78533fc8 Forgive me for writing this code, but it does seem to upgrade v1=>v2 correctly 4 years ago
Duke Leto 8636754703 Large addressbook refactor to use QList, to support contacts having more than 2 data fields 4 years ago
Duke Leto 3960c7e906 copyright 4 years ago
Duke Leto 1b3147118f Use a fixed reply zaddr to enable more testing 4 years ago
Duke Leto 076c2221e4 Correctly set the zaddr for Bob the recipient, we must still set Alice's from zaddr correctly 4 years ago
Duke Leto 9a1ab5babf Convert conversation id to a UUID 4 years ago
Duke Leto 707d858601 Find the current HushContact when sendMemo is clicked 4 years ago
Duke Leto 30dfaf5ce8 Figure out a different way to find out the currently selected HushContact in sendMemo 4 years ago
Duke Leto 9d583e69b7 Prevent editing of contact list and chat list 4 years ago
Duke Leto 6e1fd225f4 Make build fail correctly when there is an error 4 years ago
Duke Leto fec7346a58 Add file upload button 4 years ago
Duke Leto 600462d4a3 Set input text color to red, labels on both columns and stretching options 4 years ago
Duke Leto 51cc069812 Grab the input text for sending a memo 4 years ago
Duke Leto b47180ac0b Try to setup slot+signals but they are not working yet 4 years ago
Duke Leto 50f44ac221 Push checking for updates to be last, give the user data first 4 years ago
Duke Leto 3c42c28db8 Fix a small bug where a rare exception could set default currency to USD (old default) instead of BTC (new default) 4 years ago
Duke Leto 58a8aacd80 copyright 4 years ago
Duke Leto 0466e9ab55 Method to create header memos and updates to sendMemo() 4 years ago
Duke Leto 84cf85bf49 Log the object which gets a mouse event 4 years ago
Duke Leto 130e5aaf66 Detect left vs right button clicks 4 years ago
Duke Leto dd6086496e Add code to detect mouse clicks and fill out sendMemo and HushContact 4 years ago
Duke Leto d76aa8b3dc Fill out HushChat class a bit more 4 years ago
Duke Leto 1c64548bb0 do qr code stuff before slower z operations 4 years ago
Duke Leto 0b22f10b13 Start a c++ class for hush chat objects 4 years ago
Duke Leto 41b17cdd5a Start creating the hushchat memo our new way 4 years ago
Duke Leto 3df6f0d1c2 Hook up the Send button to send an xtn 4 years ago
  1. 1
      build.sh
  2. 4
      silentdragon.pro
  3. 88
      src/addressbook.cpp
  4. 17
      src/addressbook.h
  5. 20
      src/connection.h
  6. 238
      src/mainwindow.cpp
  7. 43
      src/mainwindow.h
  8. 64
      src/mainwindow.ui
  9. 29
      src/rpc.cpp
  10. 2
      src/rpc.h
  11. 3
      src/sendtab.cpp
  12. 4
      src/senttxstore.cpp
  13. 2
      src/txtablemodel.cpp

1
build.sh

@ -3,6 +3,7 @@
# Released under the GPLv3
set -e
set -x
UNAME=$(uname)
if [ "$UNAME" == "Linux" ] ; then

4
silentdragon.pro

@ -1,6 +1,9 @@
# Copyright 2019-2020 The Hush developers
# Released under the GPLv3
#-------------------------------------------------
#
# Project created by QtCreator 2018-10-05T09:54:45
# Originally from zecwallet
#
#-------------------------------------------------
@ -14,7 +17,6 @@ QT += widgets
QT += websockets
TARGET = silentdragon
TEMPLATE = app
# The following define makes your compiler emit warnings if you use

88
src/addressbook.cpp

@ -1,3 +1,5 @@
// Copyright 2019-2020 The Hush Developers
// Released under the GPLv3
#include "addressbook.h"
#include "ui_addressbook.h"
#include "ui_mainwindow.h"
@ -30,9 +32,9 @@ void AddressBookModel::loadData() {
parent->horizontalHeader()->restoreState(QSettings().value("addresstablegeometry").toByteArray());
}
void AddressBookModel::addNewLabel(QString label, QString addr) {
void AddressBookModel::addNewLabel(QString label, QString addr, QString myZaddr) {
//labels.push_back(QPair<QString, QString>(label, addr));
AddressBook::getInstance()->addAddressLabel(label, addr);
AddressBook::getInstance()->addAddressLabel(label, addr, myZaddr);
labels.clear();
labels = AddressBook::getInstance()->getAllAddressLabels();
@ -45,7 +47,7 @@ void AddressBookModel::removeItemAt(int row) {
if (row >= labels.size())
return;
AddressBook::getInstance()->removeAddressLabel(labels[row].first, labels[row].second);
AddressBook::getInstance()->removeAddressLabel(labels[row][0], labels[row][1]);
labels.clear();
labels = AddressBook::getInstance()->getAllAddressLabels();
@ -54,8 +56,8 @@ void AddressBookModel::removeItemAt(int row) {
layoutChanged();
}
QPair<QString, QString> AddressBookModel::itemAt(int row) {
if (row >= labels.size()) return QPair<QString, QString>();
QList<QString> AddressBookModel::itemAt(int row) {
if (row >= labels.size()) return QList<QString>();
return labels.at(row);
}
@ -73,8 +75,8 @@ int AddressBookModel::columnCount(const QModelIndex&) const {
QVariant AddressBookModel::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) {
switch(index.column()) {
case 0: return labels.at(index.row()).first;
case 1: return labels.at(index.row()).second;
case 0: return labels.at(index.row())[0];
case 1: return labels.at(index.row())[1];
}
}
return QVariant();
@ -147,7 +149,7 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
return;
}
model.addNewLabel(newLabel, ab.addr->text());
model.addNewLabel(newLabel, ab.addr->text(),"");
});
// Import Button
@ -176,7 +178,8 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
continue;
// Add label, address.
model.addNewLabel(items.at(1), items.at(0));
//TODO: myzaddr
model.addNewLabel(items.at(1), items.at(0), "");
numImported++;
}
@ -196,8 +199,8 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
if (index.row() < 0) return;
QString lbl = model.itemAt(index.row()).first;
QString addr = model.itemAt(index.row()).second;
QString lbl = model.itemAt(index.row())[0];
QString addr = model.itemAt(index.row())[1];
d.accept();
fnSetTargetLabelAddr(target, lbl, addr);
});
@ -209,8 +212,8 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
if (index.row() < 0) return;
QString lbl = model.itemAt(index.row()).first;
QString addr = model.itemAt(index.row()).second;
QString lbl = model.itemAt(index.row())[0];
QString addr = model.itemAt(index.row())[1];
QMenu menu(parent);
@ -237,7 +240,7 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
auto selection = ab.addresses->selectionModel();
if (selection && selection->hasSelection() && selection->selectedRows().size() > 0) {
auto item = model.itemAt(selection->selectedRows().at(0).row());
fnSetTargetLabelAddr(target, item.first, item.second);
fnSetTargetLabelAddr(target, item[0], item[1]);
}
};
@ -267,26 +270,44 @@ void AddressBook::readFromStorage() {
file.open(QIODevice::ReadOnly);
QDataStream in(&file); // read the data serialized from the file
QString version;
in >> version >> allLabels;
in >> version;
if (version == "v1") {
qDebug() << "Detected old addressbook format";
// Convert old addressbook format v1 to v2
QList<QPair<QString,QString>> stuff;
in >> stuff;
qDebug() << "Stuff: " << stuff;
for (int i=0; i < stuff.size(); i++) {
QList<QString> contact = { stuff[i].first, stuff[i].second, "" };
qDebug() << "contact=" << contact;
allLabels.push_back(contact);
}
} else {
in >> allLabels;
}
qDebug() << "Read " << version << " Hush contacts from disk...";
file.close();
} else {
qDebug() << "No Hush contacts found on disk!";
}
// Special.
// Add the default ZecWallet donation address if it isn't already present
// QList<QString> allAddresses;
// std::transform(allLabels.begin(), allLabels.end(),
// std::back_inserter(allAddresses), [=] (auto i) { return i.second; });
// std::back_inserter(allAddresses), [=] (auto i) { return i[1]; });
// if (!allAddresses.contains(Settings::getDonationAddr())) {
// allLabels.append(QPair<QString, QString>("ZecWallet donation", Settings::getDonationAddr()));
// }
}
void AddressBook::writeToStorage() {
//TODO: we probably should do more exception-handling here
QFile file(AddressBook::writeableFile());
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
QDataStream out(&file); // we will serialize the data into the file
out << QString("v1") << allLabels;
out << QString("v2") << allLabels;
file.close();
}
@ -306,18 +327,25 @@ QString AddressBook::writeableFile() {
// Add a new address/label to the database
void AddressBook::addAddressLabel(QString label, QString address) {
Q_ASSERT(Settings::isValidAddress(address));
// TODO: return bool for success/fail
void AddressBook::addAddressLabel(QString label, QString address, QString myzaddr) {
qDebug() << "Adding " << label << "=" << address << "," << myzaddr;
if(!Settings::isValidAddress(address)) {
qDebug() << "Invalid zaddr:" << address;
//return;
}
// First, remove any existing label
// Iterate over the list and remove the label/address
for (int i=0; i < allLabels.size(); i++) {
if (allLabels[i].first == label) {
removeAddressLabel(allLabels[i].first, allLabels[i].second);
if (allLabels[i][0] == label) {
removeAddressLabel(allLabels[i][0], allLabels[i][1]);
}
}
allLabels.push_back(QPair<QString, QString>(label, address));
QList<QString> contact = { label, address, myzaddr };
allLabels.push_back(contact);
writeToStorage();
}
@ -325,7 +353,7 @@ void AddressBook::addAddressLabel(QString label, QString address) {
void AddressBook::removeAddressLabel(QString label, QString address) {
// Iterate over the list and remove the label/address
for (int i=0; i < allLabels.size(); i++) {
if (allLabels[i].first == label && allLabels[i].second == address) {
if (allLabels[i][0] == label && allLabels[i][1] == address) {
allLabels.removeAt(i);
writeToStorage();
return;
@ -336,8 +364,8 @@ void AddressBook::removeAddressLabel(QString label, QString address) {
void AddressBook::updateLabel(QString oldlabel, QString address, QString newlabel) {
// Iterate over the list and update the label/address
for (int i = 0; i < allLabels.size(); i++) {
if (allLabels[i].first == oldlabel && allLabels[i].second == address) {
allLabels[i].first = newlabel;
if (allLabels[i][0] == oldlabel && allLabels[i][1] == address) {
allLabels[i][0] = newlabel;
writeToStorage();
return;
}
@ -345,7 +373,7 @@ void AddressBook::updateLabel(QString oldlabel, QString address, QString newlabe
}
// Read all addresses
const QList<QPair<QString, QString>>& AddressBook::getAllAddressLabels() {
const QList<QList<QString>>& AddressBook::getAllAddressLabels() {
if (allLabels.isEmpty()) {
readFromStorage();
}
@ -355,8 +383,8 @@ const QList<QPair<QString, QString>>& AddressBook::getAllAddressLabels() {
// Get the label for an address
QString AddressBook::getLabelForAddress(QString addr) {
for (auto i : allLabels) {
if (i.second == addr)
return i.first;
if (i[1] == addr)
return i[0];
}
return "";
@ -365,8 +393,8 @@ QString AddressBook::getLabelForAddress(QString addr) {
// Get the address for a label
QString AddressBook::getAddressForLabel(QString label) {
for (auto i: allLabels) {
if (i.first == label)
return i.second;
if (i[0] == label)
return i[1];
}
return "";

17
src/addressbook.h

@ -1,3 +1,5 @@
// Copyright 2019-2020 The Hush Developers
// Released under the GPLv3
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
@ -11,9 +13,9 @@ public:
AddressBookModel(QTableView* parent);
~AddressBookModel();
void addNewLabel(QString label, QString addr);
void addNewLabel(QString label, QString addr, QString myzaddr);
void removeItemAt(int row);
QPair<QString, QString> itemAt(int row);
QList<QString> itemAt(int row);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
@ -25,7 +27,7 @@ private:
void saveData();
QTableView* parent;
QList<QPair<QString, QString>> labels;
QList<QList<QString>> labels;
QStringList headers;
};
@ -39,7 +41,7 @@ public:
static QString addressFromAddressLabel(const QString& lblAddr);
// Add a new address/label to the database
void addAddressLabel(QString label, QString address);
void addAddressLabel(QString label, QString address, QString myZaddr);
// Remove a new address/label from the database
void removeAddressLabel(QString label, QString address);
@ -48,7 +50,7 @@ public:
void updateLabel(QString oldlabel, QString address, QString newlabel);
// Read all addresses
const QList<QPair<QString, QString>>& getAllAddressLabels();
const QList<QList<QString>>& getAllAddressLabels();
// Get an address's first label
QString getLabelForAddress(QString address);
@ -61,9 +63,10 @@ private:
void writeToStorage();
QString writeableFile();
QList<QPair<QString, QString>> allLabels;
// contact name, contact address, myzaddr (the zaddr we use to receive from this contact)
QList<QList<QString>> allLabels;
static AddressBook* instance;
};
#endif // ADDRESSBOOK_H
#endif // ADDRESSBOOK_H

20
src/connection.h

@ -1,3 +1,5 @@
// Copyright 2019-2020 The Hush developers
// Released under the GPLv3
#ifndef CONNECTION_H
#define CONNECTION_H
@ -82,7 +84,7 @@ private:
};
/**
* Represents a connection to a zcashd. It may even start a new zcashd if needed.
* Represents a connection to a hushd. It may even start a new hushd if needed.
* This is also a UI class, so it may show a dialog waiting for the connection.
*/
class Connection {
@ -118,8 +120,10 @@ public:
// any overlapping calls
static QMap<QString, bool> inProgress;
//QString method = QString::fromStdString(payloadGenerator(payloads[0])["method"]);
//QString method = QString::fromStdString(payloadGenerator(payloads[0])["method"]);
QString method = payloadGenerator(payloads[0])["method"].toString();
qDebug() << __func__ << " with method=" << method << " and totalSize=" << totalSize;
//if (inProgress.value(method, false)) {
// qDebug() << "In progress batch, skipping";
// return;
@ -137,11 +141,12 @@ public:
QObject::connect(reply, &QNetworkReply::finished, [=] {
reply->deleteLater();
if (shutdownInProgress) {
// Ignoring callback because shutdown in progress
qDebug() << "Ignoring callback because shutdown in progress";
return;
}
auto all = reply->readAll();
auto all = reply->readAll();
qDebug() << "Parsing JSON...";
auto parsed = QJsonDocument::fromJson(all);
if (reply->error() != QNetworkReply::NoError) {
@ -150,9 +155,12 @@ public:
(*responses)[item] = {}; // Empty object
} else {
//if (parsed.is_discarded()) {
// qDebug() << "Discarded response!";
if (parsed.isEmpty()) {
(*responses)[item] = {}; // Empty object
} else {
qDebug() << "Parsed valid JSON";
(*responses)[item] = parsed["result"];
}
}
@ -160,8 +168,10 @@ public:
}
auto waitTimer = new QTimer(main);
qDebug() << "Created timer...";
QObject::connect(waitTimer, &QTimer::timeout, [=]() {
if (shutdownInProgress) {
qDebug() << "Shutdown in progress, removing timer";
waitTimer->stop();
waitTimer->deleteLater();
return;
@ -169,6 +179,7 @@ public:
// If all responses have arrived, return
if (responses->size() == totalSize) {
qDebug() << "Response arrived, removing timer...";
waitTimer->stop();
@ -178,6 +189,7 @@ public:
waitTimer->deleteLater();
}
});
qDebug() << "Starting timer...";
waitTimer->start(100);
}

238
src/mainwindow.cpp

@ -23,6 +23,18 @@
#include "websockets.h"
QString MainWindow::getZaddrForContact(QString contact) {
QList<QList<QString>> addressLabels = AddressBook::getInstance()->getAllAddressLabels();
for (int i = 0; i < addressLabels.size(); ++i) {
QList<QString> thisContact = addressLabels.at(i);
if (thisContact[0] == contact) {
qDebug() << "Found contact " << thisContact[0] << " " << thisContact[1];
return thisContact[1];
}
}
return "";
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
@ -48,23 +60,15 @@ MainWindow::MainWindow(QWidget *parent) :
// Settings editor
setupSettingsModal();
// Set up exit action
// Set up actions
QObject::connect(ui->actionExit, &QAction::triggered, this, &MainWindow::close);
// Set up feedback action
QObject::connect(ui->actionDonate, &QAction::triggered, this, &MainWindow::donate);
QObject::connect(ui->actionDiscord, &QAction::triggered, this, &MainWindow::discord);
QObject::connect(ui->actionReportBug, &QAction::triggered, this, &MainWindow::reportbug);
QObject::connect(ui->actionWebsite, &QAction::triggered, this, &MainWindow::website);
// Set up check for updates action
QObject::connect(ui->actionCheck_for_Updates, &QAction::triggered, [=] () {
// Silent is false, so show notification even if no update was found
rpc->checkForUpdate(false);
});
// Send button
QObject::connect(ui->sendMemo, &QPushButton::clicked, this, &MainWindow::sendMemo);
// Request hush
QObject::connect(ui->actionRequest_zcash, &QAction::triggered, [=]() {
@ -118,29 +122,180 @@ MainWindow::MainWindow(QWidget *parent) :
// Initialize to the balances tab
ui->tabWidget->setCurrentIndex(0);
if (AppDataServer::getInstance()->isAppConnected()) {
auto ads = AppDataServer::getInstance();
QString wormholecode = "";
if (ads->getAllowInternetConnection())
wormholecode = ads->getWormholeCode(ads->getSecretHex());
qDebug() << "MainWindow: createWebsocket with wormholecode=" << wormholecode;
createWebsocket(wormholecode);
}
//TODO: allow user to set this
ui->textEdit->setTextColor( QColor("red") );
QItemSelectionModel* qsm = ui->chatView->selectionModel();
QObject::connect(qsm, SIGNAL(itemSelectionChanged(const QItemSelection&, const QItemSelection&)),this, SLOT(itemSelectionChanged()));
// Contacts and chat views should not be editable
ui->chatView->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->contactsView->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->contactsView->setViewMode(QListView::ListMode);
// This works but doesn't take into account dark theme and is unreadable
//ui->contactsView->setAlternatingRowColors(true);
setupSendTab();
setupTransactionsTab();
setupReceiveTab();
setupBalancesTab();
setupMarketTab();
//setupChatTab();
setupChatTab();
setupHushTab();
// Set up check for updates action
QObject::connect(ui->actionCheck_for_Updates, &QAction::triggered, [=] () {
// Silent is false, so show notification even if no update was found
rpc->checkForUpdate(false);
});
rpc = new RPC(this);
qDebug() << "Created RPC";
restoreSavedStates();
if (AppDataServer::getInstance()->isAppConnected()) {
auto ads = AppDataServer::getInstance();
}
QString wormholecode = "";
if (ads->getAllowInternetConnection())
wormholecode = ads->getWormholeCode(ads->getSecretHex());
QString MainWindow::createHeaderMemo(QString cid, QString zaddr, int version=0, int headerNumber=1)
{
QString header="";
QJsonDocument j;
QJsonObject h;
version = -1; // This is unstable v=-1 until we launch with v=0
// We use short keynames to use less space for metadata and so allow
// the user to send more actual data in memos
h["h"] = headerNumber; // header number
h["v"] = version; // HushChat version
h["z"] = zaddr; // zaddr to respond to
h["cid"] = cid; // conversation id
j.setObject(h);
//TODO: how do we remove newlines?
header = j.toJson();
qDebug() << "made header=" << header;
return header;
}
qDebug() << "MainWindow: createWebsocket with wormholecode=" << wormholecode;
createWebsocket(wormholecode);
QString MainWindow::getZaddrForCurrentContact() {
QString zaddr;
QModelIndex qmi = ui->contactsView->currentIndex();
if (qmi.isValid()) {
qDebug() << "Current (row,col) index: " << qmi.row() << "," << qmi.column();
// we seem to get duplicates due to QT internals shenanigans, just pick the first
QMap <int, QVariant> currentContacts = ui->contactsView->model()->itemData(qmi);
QString contact = currentContacts[0].toString();
qDebug() << "Current HushContact: " << contact;
zaddr = getZaddrForContact(contact);
} else {
qDebug() << "Invalid current index, no contacts selected";
}
return zaddr;
}
QString MainWindow::getNameForCurrentContact() {
QString name;
QModelIndex qmi = ui->contactsView->currentIndex();
if (qmi.isValid()) {
qDebug() << "Current (row,col) index: " << qmi.row() << "," << qmi.column();
// we seem to get duplicates due to QT internals shenanigans, just pick the first
QMap <int, QVariant> currentContacts = ui->contactsView->model()->itemData(qmi);
QString name = currentContacts[0].toString();
} else {
qDebug() << "Invalid current index, no contacts selected";
}
return name;
}
// Send button clicked
void MainWindow::sendMemo() {
HushChat thisChat = MainWindow::getHushChat();
// Either we made a custom zaddr for this contact in the past, or we make a new one now
if(thisChat.getContact().getMyZaddr().isEmpty()) {
QString newzaddr;
rpc->newZaddr( [=] (QJsonValue reply) {
Tx tx;
tx.fee = Settings::getMinerFee();
//TODO: verify we currently own the private key to this zaddr via z_validateaddress
HushChat chat = MainWindow::getHushChat();
HushContact contact = chat.getContact();
QString myZaddr = reply.toString();
QString addr = getZaddrForCurrentContact();
QString name = getNameForCurrentContact();
qDebug() << "created new myZaddr="<< myZaddr << " for " << name;
contact.setName(name);
contact.setMyZaddr(myZaddr);
contact.setZaddr(addr);
AddressBook::getInstance()->addAddressLabel(contact.getName(), contact.getZaddr(), contact.getMyZaddr());
qDebug() << "Wrote new myZaddr for " << contact.getName() << " to storage";
qDebug() << "Using " << myZaddr << " as from address for " << contact.getName();
double amount = 0;
QString cid = QUuid::createUuid().toString(QUuid::WithoutBraces);
QString hmemo = createHeaderMemo(cid,myZaddr);
QString memo = ui->textEdit->toPlainText();
// we send a header memo plus actual memo
tx.toAddrs.push_back( ToFields{addr, amount, hmemo, hmemo.toUtf8().toHex()} );
tx.toAddrs.push_back( ToFields{addr, amount, memo, memo.toUtf8().toHex()} );
tx.fromAddr = contact.getMyZaddr();
qDebug() << "Sending "<< name << "(" << addr << ") a memo: " << memo;
QString error = doSendTxValidations(tx);
if (!error.isEmpty()) {
// Something went wrong, so show an error and exit
QMessageBox msg(QMessageBox::Critical, tr("Transaction Error"), error,
QMessageBox::Ok, this);
msg.exec();
// abort the Tx
return;
}
// Show a dialog to confirm the Tx
if (confirmTx(tx)) {
// And send the Tx
rpc->executeTransaction(tx,
[=] (QString opid) {
ui->statusBar->showMessage(tr("Computing transaction: ") % opid);
qDebug() << "Computing opid: " << opid;
},
[=] (QString, QString txid) {
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
},
[=] (QString opid, QString errStr) {
ui->statusBar->showMessage(QObject::tr(" Transaction ") % opid % QObject::tr(" failed"), 15 * 1000);
if (!opid.isEmpty())
errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr;
QMessageBox::critical(this, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok);
}
);
}
}); // newZaddr
} else {
// this contact already has a myZaddr
}
}
void MainWindow::createWebsocket(QString wormholecode) {
@ -705,14 +860,27 @@ void MainWindow::balancesReady() {
}
// Event filter for MacOS specific handling of payment URIs
bool MainWindow::eventFilter(QObject *object, QEvent *event) {
// Event filter for MacOS specific handling of payment URIs
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent *fileEvent = static_cast<QFileOpenEvent*>(event);
if (!fileEvent->url().isEmpty())
payZcashURI(fileEvent->url().toString());
return true;
} else if (event->type() == QEvent::MouseButtonPress) {
qDebug() << __func__ <<": "<<" mouse button event on " << object->objectName();
QMouseEvent *ev = static_cast<QMouseEvent *>(event);
if (ev->buttons() & Qt::RightButton)
{
//qDebug()<< "RightButton clicked";
}
if (ev->buttons() & Qt::LeftButton)
{
//qDebug()<< "LeftButton clicked";
//TODO: if this was a HushContact object in chatView, update MainWindow::contact
}
//return false;
}
return QObject::eventFilter(object, event);
@ -1136,26 +1304,31 @@ void MainWindow::setupBalancesTab() {
void MainWindow::setupHushTab() {
ui->hushlogo->setBasePixmap(QPixmap(":/img/res/zcashdlogo.gif"));
}
/*
void MainWindow::setupChatTab() {
qDebug() << __FUNCTION__;
QList<QPair<QString,QString>> addressLabels = AddressBook::getInstance()->getAllAddressLabels();
QList<QList<QString>> addressLabels = AddressBook::getInstance()->getAllAddressLabels();
QStringListModel *chatModel = new QStringListModel();
QStringList contacts;
//contacts << "Alice" << "Bob" << "Charlie" << "Eve";
for (int i = 0; i < addressLabels.size(); ++i) {
QPair<QString,QString> pair = addressLabels.at(i);
qDebug() << "Found contact " << pair.first << " " << pair.second;
contacts << pair.first;
QList<QString> thisContact = addressLabels.at(i);
qDebug() << "Found contact " << thisContact[0] << " " << thisContact[1];
contacts << thisContact[0];
}
chatModel->setStringList(contacts);
QStringListModel *conversationModel = new QStringListModel();
QStringList conversations;
conversations << "Bring home some milk" << "Markets look rough" << "How's the weather?" << "Is this on?";
conversations << "The Bitcoin network might actually reduce spam by diverting zombie farms to generating bitcoins instead.";
conversationModel->setStringList(conversations);
//conversationModel[0].setItemAlignment(Qt::AlignRight);
// iterate on all elements in chat view and set alignment
// ui->chatView->
//Ui_addressBook ab;
//AddressBookModel model(ab.addresses);
@ -1166,8 +1339,9 @@ void MainWindow::setupChatTab() {
ui->contactsView->setModel(chatModel);
ui->chatView->setModel( conversationModel );
ui->chatGridLayout->setColumnStretch(1,1);
ui->chatGridLayout->setRowStretch(1,2);
}
*/
void MainWindow::setupMarketTab() {
qDebug() << "Setting up market tab";
@ -1486,14 +1660,12 @@ void MainWindow::setupReceiveTab() {
if (!curLabel.isEmpty() && label.isEmpty()) {
info = "Removed Label '" % curLabel % "'";
AddressBook::getInstance()->removeAddressLabel(curLabel, addr);
}
else if (!curLabel.isEmpty() && !label.isEmpty()) {
} else if (!curLabel.isEmpty() && !label.isEmpty()) {
info = "Updated Label '" % curLabel % "' to '" % label % "'";
AddressBook::getInstance()->updateLabel(curLabel, addr, label);
}
else if (curLabel.isEmpty() && !label.isEmpty()) {
} else if (curLabel.isEmpty() && !label.isEmpty()) {
info = "Added Label '" % label % "'";
AddressBook::getInstance()->addAddressLabel(label, addr);
AddressBook::getInstance()->addAddressLabel(label, addr,"");
}
// Update labels everywhere on the UI
@ -1561,7 +1733,7 @@ void MainWindow::slot_change_currency(const QString& currency_name)
saved_currency_name = Settings::getInstance()->get_currency_name();
} catch (const std::exception& e) {
qDebug() << QString("Ignoring currency change Exception! : ");
saved_currency_name = "USD";
saved_currency_name = "BTC";
}
}

43
src/mainwindow.h

@ -29,6 +29,41 @@ namespace Ui {
class MainWindow;
}
class HushContact
{
public:
void setName(QString newname) { name = newname; }
QString getName() { return name; }
QString getZaddr() { return zaddr; }
void setZaddr(QString z) { zaddr = z; }
QString getMyZaddr() { return myZaddr; }
void setMyZaddr(QString z) { myZaddr = z; }
private:
QString name;
QString nickname;
QString zaddr;
QString myZaddr;
//int64_t lastSentTime;
//int64_t lastReceivedTime;
};
class HushChat
{
public:
void setContact(HushContact newcontact) { contact = newcontact; }
HushContact getContact() { return contact; }
QString getMyZaddr() { return myZaddr; }
void setMyZaddr(QString z) { myZaddr = z; }
private:
QString myZaddr;
HushContact contact;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
@ -43,6 +78,9 @@ public:
QCompleter* getLabelCompleter() { return labelCompleter; }
QRegExpValidator* getAmountValidator() { return amtValidator; }
QString getZaddrForContact(QString contact);
QString getZaddrForCurrentContact();
QString getNameForCurrentContact();
QString doSendTxValidations(Tx tx);
void setDefaultPayFrom();
@ -70,6 +108,9 @@ public:
Logger* logger;
void doClose();
HushChat getHushChat() { return hushChat; }
void setHushChat(HushChat chat) { hushChat = chat; }
QString createHeaderMemo(QString cid, QString zaddr, int version, int headerNumnber);
private:
void closeEvent(QCloseEvent* event);
@ -98,6 +139,7 @@ private:
void cancelButton();
void sendButton();
void sendMemo();
void inputComboTextChanged(int index);
void addAddressSection();
void maxAmountChecked(int checked);
@ -137,6 +179,7 @@ private:
WSServer* wsserver = nullptr;
WormholeClient* wormhole = nullptr;
HushChat hushChat;
RPC* rpc = nullptr;
QCompleter* labelCompleter = nullptr;

64
src/mainwindow.ui

@ -1019,27 +1019,67 @@
<attribute name="title">
<string>Chat</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<layout class="QVBoxLayout" name="chatVBoxLayout">
<item>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QGridLayout" name="chatGridLayout">
<item row="1" column="0">
<widget class="QListView" name="contactsView"/>
</item>
<item row="1" column="1">
<widget class="QTextEdit" name="textEdit"/>
<widget class="QListView" name="chatView"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="tmp2">
<property name="text">
<string>Hush Contacts</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QListView" name="chatView"/>
<widget class="QLabel" name="tmp3">
<property name="text">
<string>XXX and YYY metadata about this HushChat</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Send</string>
</property>
<item row="2" column="1">
<widget class="QTextEdit" name="textEdit">
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="pushButton_2">
<item row="3" column="1">
<layout class="QGridLayout" name="chatButtonLayout">
<item row="0" column="0">
<widget class="QPushButton" name="fileUpload">
<property name="text">
<string>Upload</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="sendMemo">
<property name="sizeHint" stdset="0">
<size>
<width>50</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>Send Memo!</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="newHushChat">
<property name="text">
<string>New HushChat</string>
</property>

29
src/rpc.cpp

@ -32,7 +32,7 @@ RPC::RPC(MainWindow* main) {
QObject::connect(priceTimer, &QTimer::timeout, [=]() {
refreshPrice();
});
priceTimer->start(Settings::priceRefreshSpeed); // Every hour
priceTimer->start(Settings::priceRefreshSpeed);
// Set up a timer to refresh the UI every few seconds
timer = new QTimer(main);
@ -429,6 +429,7 @@ void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
// We'll only refresh the received Z txs if settings allows us.
if (!Settings::getInstance()->getSaveZtxs()) {
qDebug() << "Settings have saved zaddr transactions OFF, showing empty list";
QList<TransactionItem> emptylist;
transactionsTableModel->addZRecvData(emptylist);
return;
@ -456,6 +457,7 @@ void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
// appears multiple times in a single tx's outputs.
QSet<QString> txids;
QMap<QString, QString> memos;
qDebug() << "Processing zaddrs...";
for (auto it = zaddrTxids->constBegin(); it != zaddrTxids->constEnd(); it++) {
auto zaddr = it.key();
for (const auto& i : it.value().toArray()) {
@ -468,17 +470,23 @@ void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
txids.insert(txid);
// Check for Memos
QString memoBytes = QString::fromStdString(i["memo"].get<json::string_t>());
//TODO: This should check for valid utf8!
QString memoBytes = i.toObject()["memo"].toString();
if (!memoBytes.startsWith("f600")) {
//QString memo(QByteArray::fromHex(
// QByteArray::fromStdString(i["memo"].get<json::string_t>())));
QString memo(QByteArray::fromHex(
i.toObject()["memo"].toString().toUtf8()));
if (!memo.trimmed().isEmpty())
qDebug() << "Found a memo for txid=" << txid;
memos[zaddr + txid] = memo;
}
}
}
}
qDebug() << "Processing all txids...";
// 2. For all txids, go and get the details of that txid.
conn->doBatchRPC<QString>(txids.toList(),
[=] (QString txid) {
@ -536,6 +544,7 @@ void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
/// This will refresh all the balance data from hushd
void RPC::refresh(bool force) {
qDebug() << __func__;
if (conn == nullptr)
return noConnection();
@ -696,6 +705,8 @@ void RPC::getInfoThenRefresh(bool force) {
price = QString(", ") % "HUSH" % "=" % QString::number( (double)ticker_price,'f',8) % " " % ticker % " " % extra;
}
qDebug() << "Updating status bar";
// Update the status bar
QString statusText = QString() %
(isSyncing ? QObject::tr("Syncing") : QObject::tr("Connected")) %
@ -711,8 +722,8 @@ void RPC::getInfoThenRefresh(bool force) {
QString tooltip;
if (connections > 0) {
tooltip = QObject::tr("Connected to hushd");
}
else {
} else {
qDeug() << "No connections!";
tooltip = QObject::tr("hushd has no peer connections! Network issues?");
}
tooltip = tooltip % "(v" % QString::number(Settings::getInstance()->getZcashdVersion()) % ")";
@ -722,9 +733,11 @@ void RPC::getInfoThenRefresh(bool force) {
}
main->statusLabel->setToolTip(tooltip);
main->statusIcon->setToolTip(tooltip);
qDebug() << "Set tooltip";
});
}, [=](QNetworkReply* reply, const QJsonValue&) {
qDebug() << "hushd is gone!";
// hushd has probably disappeared.
this->noConnection();
@ -742,6 +755,7 @@ void RPC::getInfoThenRefresh(bool force) {
}
void RPC::refreshAddresses() {
qDebug() << __func__;
if (conn == nullptr)
return noConnection();
@ -807,6 +821,7 @@ bool RPC::processUnspent(const QJsonValue& reply, QMap<QString, double>* balance
};
void RPC::refreshBalances() {
qDebug() << "Updating balances";
if (conn == nullptr)
return noConnection();
@ -836,10 +851,12 @@ void RPC::refreshBalances() {
auto newUtxos = new QList<UnspentOutput>();
auto newBalances = new QMap<QString, double>();
qDebug() << "Updating taddr balances";
// Call the Transparent and Z unspent APIs serially and then, once they're done, update the UI
getTransparentUnspent([=] (QJsonValue reply) {
auto anyTUnconfirmed = processUnspent(reply, newBalances, newUtxos);
qDebug() << "Updating zaddr balances";
getZUnspent([=] (QJsonValue reply) {
auto anyZUnconfirmed = processUnspent(reply, newBalances, newUtxos);
@ -893,6 +910,7 @@ void RPC::refreshTransactions() {
// Read sent Z transactions from the file.
void RPC::refreshSentZTrans() {
qDebug() << __func__;
if (conn == nullptr)
return noConnection();
@ -946,6 +964,7 @@ void RPC::refreshSentZTrans() {
void RPC::addNewTxToWatch(const QString& newOpid, WatchedTx wtx) {
watchingOps.insert(newOpid, wtx);
qDebug() << "Watched new opid " << opid;
watchTxStatus();
}
@ -1286,8 +1305,8 @@ void RPC::shutdownZcashd() {
*/
QString RPC::getDefaultSaplingAddress() {
for (QString addr: *zaddresses) {
if (Settings::getInstance()->isSaplingAddress(addr))
return addr;
//if (Settings::getInstance()->isSaplingAddress(addr))
return addr;
}
return QString();

2
src/rpc.h

@ -1,3 +1,5 @@
// Copyright 2019-2020 The Hush Developers
// Released under the GPLv3
#ifndef RPCCLIENT_H
#define RPCCLIENT_H

3
src/sendtab.cpp

@ -1,4 +1,5 @@
// Copyright 2019-2020 Hush developers
// Released under the GPLv3
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "addressbook.h"
@ -123,7 +124,7 @@ void MainWindow::updateLabelsAutoComplete() {
auto labels = AddressBook::getInstance()->getAllAddressLabels();
std::transform(labels.begin(), labels.end(), std::back_inserter(list), [=] (auto la) -> QString {
return la.first % "/" % la.second;
return la[0] % "/" % la[1];
});
delete labelCompleter;

4
src/senttxstore.cpp

@ -1,3 +1,5 @@
// Copyright 2019-2020 The Hush Developers
// Released under the GPLv3
#include "senttxstore.h"
#include "settings.h"
@ -103,7 +105,7 @@ void SentTxStore::addToSentTx(Tx tx, QString txid) {
txItem["txid"] = txid;
txItem["amount"] = -totalAmount;
txItem["fee"] = -tx.fee;
// TODO: store all outgoing memos
// TODO: store all outgoing memos, after encryption
txItem["memo"] = tx.toAddrs[0].txtMemo;
list.append(txItem);

2
src/txtablemodel.cpp

@ -1,3 +1,5 @@
// Copyright 2019-2020 The Hush Developers
// Released under the GPLv3
#include "txtablemodel.h"
#include "settings.h"
#include "rpc.h"

Loading…
Cancel
Save