diff --git a/README.md b/README.md
index 80814b9..bacc211 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,8 @@ Head over to the releases page and grab the latest binary. https://github.com/ad
### Linux
Extract and run the binary
```
-tar -xvf zec-qt-wallet-v0.2.8.tar.gz
-./zec-qt-wallet-v0.2.8/zec-qt-wallet
+tar -xvf zec-qt-wallet-v0.2.9.tar.gz
+./zec-qt-wallet-v0.2.9/zec-qt-wallet
```
### Windows
@@ -24,7 +24,7 @@ There is currently no official zcashd build for Windows so Windows users may eit
Alternatively run zcashd inside [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
-For all installations zcashd needs to run with RPC enabled (`server=1`, which is the default) and with a RPC username/password set. Add the following entries into `~/.zcash/zcash.conf` for Linux or` C:\Users\your-username\AppData\Roaming\Zcash\zcash.conf` on Windows replacing the default values with a strong password. zec-qt-wallet should detect these settings but if that fails you may edit the connection settings manually via the `File->Settings` menu.
+For all installations zcashd needs to run with RPC enabled (`server=1`, which is the default) and with a RPC username/password set. Add the following entries into `~/.zcash/zcash.conf` for Linux or` C:\Users\your-username\AppData\Roaming\Zcash\zcash.conf` on Windows replacing the default values with a strong password. zec-qt-wallet should detect these settings but if that fails you may edit the connection settings manually via the `Edit->Settings` menu.
```
rpcuser=username
@@ -41,7 +41,7 @@ https://z.cash/downloads/sprout-proving.key
https://z.cash/downloads/sprout-verifying.key
```
-If you are running zcashd on WSL, then please set the connection parameters in the `File->Settings` menu.
+If you are running zcashd on WSL, then please set the connection parameters in the `Edit->Settings` menu.
## Compiling from source
zec-qt-wallet is written in C++ 14, and can be compiled with g++/clang++/visual c++. It also depends on Qt5, which you can get from here: https://www.qt.io/download
@@ -49,6 +49,8 @@ zec-qt-wallet is written in C++ 14, and can be compiled with g++/clang++/visual
### Compiling on Linux
```
+sudo apt install libgl1-mesa-dev
+
git clone https://github.com/adityapk00/zec-qt-wallet.git
cd zec-qt-wallet
/path/to/qt5/bin/qmake zec-qt-wallet.pro CONFIG+=debug
@@ -64,7 +66,7 @@ From the VS Tools command prompt
```
git clone https://github.com/adityapk00/zec-qt-wallet.git
cd zec-qt-wallet
-c:\Qt5\bin\qmake.exe zec-qt-wallet.pro CONFIG+=debug
+c:\Qt5\bin\qmake.exe zec-qt-wallet.pro -spec win32-msvc CONFIG+=debug
nmake
debug\zec-qt-wallet.exe
diff --git a/application.qrc b/application.qrc
index 29f23df..0f7de37 100644
--- a/application.qrc
+++ b/application.qrc
@@ -3,7 +3,7 @@
res/Ubuntu-R.ttf
- res/connected.png
+ res/connected.gif
res/loading.gif
res/icon.ico
diff --git a/docs/screenshot-main.png b/docs/screenshot-main.png
index 062037d..f7f37b6 100644
Binary files a/docs/screenshot-main.png and b/docs/screenshot-main.png differ
diff --git a/res/connected.gif b/res/connected.gif
new file mode 100644
index 0000000..a515ed4
Binary files /dev/null and b/res/connected.gif differ
diff --git a/res/connected.png b/res/connected.png
deleted file mode 100644
index 4feefae..0000000
Binary files a/res/connected.png and /dev/null differ
diff --git a/src/addressbook.cpp b/src/addressbook.cpp
index 27f98dc..873eac2 100644
--- a/src/addressbook.cpp
+++ b/src/addressbook.cpp
@@ -10,83 +10,56 @@ AddressBookModel::AddressBookModel(QTableView *parent)
headers << "Label" << "Address";
this->parent = parent;
- loadDataFromStorage();
+ loadData();
}
AddressBookModel::~AddressBookModel() {
- if (labels != nullptr)
- saveDataToStorage();
-
- delete labels;
+ saveData();
}
-void AddressBookModel::saveDataToStorage() {
- QFile file(writeableFile());
- file.open(QIODevice::ReadWrite | QIODevice::Truncate);
- QDataStream out(&file); // we will serialize the data into the file
- out << QString("v1") << *labels;
- file.close();
+void AddressBookModel::saveData() {
+ AddressBook::writeToStorage(labels);
// Save column positions
QSettings().setValue("addresstablegeometry", parent->horizontalHeader()->saveState());
}
-void AddressBookModel::loadDataFromStorage() {
- QFile file(writeableFile());
-
- delete labels;
- labels = new QList>();
-
- file.open(QIODevice::ReadOnly);
- QDataStream in(&file); // read the data serialized from the file
- QString version;
- in >> version >> *labels;
-
- file.close();
+void AddressBookModel::loadData() {
+ labels = AddressBook::readFromStorage();
parent->horizontalHeader()->restoreState(QSettings().value("addresstablegeometry").toByteArray());
}
void AddressBookModel::addNewLabel(QString label, QString addr) {
- labels->push_back(QPair(label, addr));
+ labels.push_back(QPair(label, addr));
+ AddressBook::writeToStorage(labels);
- dataChanged(index(0, 0), index(labels->size()-1, columnCount(index(0,0))-1));
+ dataChanged(index(0, 0), index(labels.size()-1, columnCount(index(0,0))-1));
layoutChanged();
}
void AddressBookModel::removeItemAt(int row) {
- if (row >= labels->size())
+ if (row >= labels.size())
return;
- labels->removeAt(row);
- dataChanged(index(0, 0), index(labels->size()-1, columnCount(index(0,0))-1));
+ labels.removeAt(row);
+ AddressBook::writeToStorage(labels);
+
+
+ dataChanged(index(0, 0), index(labels.size()-1, columnCount(index(0,0))-1));
layoutChanged();
}
QPair AddressBookModel::itemAt(int row) {
- if (row >= labels->size()) return QPair();
+ if (row >= labels.size()) return QPair();
- return labels->at(row);
+ return labels.at(row);
}
-QString AddressBookModel::writeableFile() {
- auto filename = QStringLiteral("addresslabels.dat");
-
- auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
- if (!dir.exists())
- QDir().mkpath(dir.absolutePath());
-
- if (Settings::getInstance()->isTestnet()) {
- return dir.filePath("testnet-" % filename);
- } else {
- return dir.filePath(filename);
- }
-}
int AddressBookModel::rowCount(const QModelIndex&) const {
- if (labels == nullptr) return 0;
- return labels->size();
+ return labels.size();
}
int AddressBookModel::columnCount(const QModelIndex&) const {
@@ -97,12 +70,12 @@ 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()).first;
+ case 1: return labels.at(index.row()).second;
}
}
return QVariant();
-}
+}
QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const {
@@ -117,6 +90,7 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
QDialog d(parent);
Ui_addressBook ab;
ab.setupUi(&d);
+ Settings::saveRestore(&d);
AddressBookModel model(ab.addresses);
ab.addresses->setModel(&model);
@@ -126,6 +100,9 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
ab.buttonBox->button(QDialogButtonBox::Ok)->setText("Pick");
}
+ // Connect the dialog's closing to updating the label address completor
+ QObject::connect(&d, &QDialog::finished, [=] (auto) { parent->updateLabelsAutoComplete(); });
+
// If there is a target then make it the addr for the "Add to" button
if (target != nullptr && Utils::isValidAddress(target->text())) {
ab.addr->setText(target->text());
@@ -145,13 +122,18 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
}
});
+ auto fnSetTargetLabelAddr = [=] (QLineEdit* target, QString label, QString addr) {
+ target->setText(label % "/" % addr);
+ };
+
// Double-Click picks the item
QObject::connect(ab.addresses, &QTableView::doubleClicked, [&] (auto index) {
if (index.row() < 0) return;
+ QString lbl = model.itemAt(index.row()).first;
QString addr = model.itemAt(index.row()).second;
d.accept();
- target->setText(addr);
+ fnSetTargetLabelAddr(target, lbl, addr);
});
// Right-Click
@@ -161,13 +143,15 @@ 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;
QMenu menu(parent);
if (target != nullptr) {
menu.addAction("Pick", [&] () {
- target->setText(addr);
+ d.accept();
+ fnSetTargetLabelAddr(target, lbl, addr);
});
}
@@ -186,7 +170,46 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
if (d.exec() == QDialog::Accepted && target != nullptr) {
auto selection = ab.addresses->selectionModel();
if (selection->hasSelection()) {
- target->setText(model.itemAt(selection->selectedRows().at(0).row()).second);
+ auto item = model.itemAt(selection->selectedRows().at(0).row());
+ fnSetTargetLabelAddr(target, item.first, item.second);
}
};
+}
+
+QList> AddressBook::readFromStorage() {
+ QFile file(AddressBook::writeableFile());
+
+ QList> labels;
+
+ file.open(QIODevice::ReadOnly);
+ QDataStream in(&file); // read the data serialized from the file
+ QString version;
+ in >> version >> labels;
+
+ file.close();
+
+ return labels;
+}
+
+
+void AddressBook::writeToStorage(QList> labels) {
+ QFile file(AddressBook::writeableFile());
+ file.open(QIODevice::ReadWrite | QIODevice::Truncate);
+ QDataStream out(&file); // we will serialize the data into the file
+ out << QString("v1") << labels;
+ file.close();
+}
+
+QString AddressBook::writeableFile() {
+ auto filename = QStringLiteral("addresslabels.dat");
+
+ auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
+ if (!dir.exists())
+ QDir().mkpath(dir.absolutePath());
+
+ if (Settings::getInstance()->isTestnet()) {
+ return dir.filePath("testnet-" % filename);
+ } else {
+ return dir.filePath(filename);
+ }
}
\ No newline at end of file
diff --git a/src/addressbook.h b/src/addressbook.h
index 5fe7666..9aa3f00 100644
--- a/src/addressbook.h
+++ b/src/addressbook.h
@@ -21,19 +21,22 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
- void loadDataFromStorage();
- void saveDataToStorage();
-
- QString writeableFile();
+ void loadData();
+ void saveData();
QTableView* parent;
- QList>* labels = nullptr;
+ QList> labels;
QStringList headers;
};
class AddressBook {
public:
static void open(MainWindow* parent, QLineEdit* target = nullptr);
+
+ static QList> readFromStorage();
+ static void writeToStorage(QList> labels);
+
+ static QString writeableFile();
};
#endif // ADDRESSBOOK_H
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 791a4bd..76fcd14 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -18,7 +18,7 @@ int main(int argc, char *argv[])
qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false));
#endif
- std::srand(std::time(nullptr));
+ std::srand(static_cast(std::time(nullptr)));
Settings::init();
Settings::getInstance()->setExecName(argv[0]);
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 505f209..f02d711 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -109,6 +109,7 @@ void MainWindow::turnstileProgress() {
Ui_TurnstileProgress progress;
QDialog d(this);
progress.setupUi(&d);
+ Settings::saveRestore(&d);
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
progress.msgIcon->setPixmap(icon.pixmap(64, 64));
@@ -189,6 +190,7 @@ void MainWindow::turnstileDoMigration(QString fromAddr) {
Ui_Turnstile turnstile;
QDialog d(this);
turnstile.setupUi(&d);
+ Settings::saveRestore(&d);
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
turnstile.msgIcon->setPixmap(icon.pixmap(64, 64));
@@ -240,8 +242,7 @@ void MainWindow::turnstileDoMigration(QString fromAddr) {
if (!fromAddr.isEmpty())
turnstile.migrateZaddList->setCurrentText(fromAddr);
- fnUpdateSproutBalance(turnstile.migrateZaddList->currentText());
-
+ fnUpdateSproutBalance(turnstile.migrateZaddList->currentText());
// Combo box selection event
QObject::connect(turnstile.migrateZaddList, &QComboBox::currentTextChanged, fnUpdateSproutBalance);
@@ -349,6 +350,7 @@ void MainWindow::setupSettingsModal() {
QDialog settingsDialog(this);
Ui_Settings settings;
settings.setupUi(&settingsDialog);
+ Settings::saveRestore(&settingsDialog);
// Setup save sent check box
QObject::connect(settings.chkSaveTxs, &QCheckBox::stateChanged, [=](auto checked) {
@@ -412,7 +414,7 @@ void MainWindow::setupSettingsModal() {
auto cl = new ConnectionLoader(this, rpc);
cl->loadConnection();
}
- };
+ }
});
}
@@ -449,6 +451,10 @@ void MainWindow::postToZBoard() {
QDialog d(this);
Ui_zboard zb;
zb.setupUi(&d);
+ Settings::saveRestore(&d);
+
+ if (rpc->getConnection() == nullptr)
+ return;
// Fill the from field with sapling addresses.
for (auto i = rpc->getAllBalances()->keyBegin(); i != rpc->getAllBalances()->keyEnd(); i++) {
@@ -457,6 +463,18 @@ void MainWindow::postToZBoard() {
}
}
+ QMap topics;
+ // Insert the main topic automatically
+ topics.insert("#Main_Area", Utils::getZboardAddr());
+ zb.topicsList->addItem(topics.firstKey());
+ // Then call the API to get topics, and if it returns successfully, then add the rest of the topics
+ rpc->getZboardTopics([&](QMap topicsMap) {
+ for (auto t : topicsMap.keys()) {
+ topics.insert(t, topicsMap[t]);
+ zb.topicsList->addItem(t);
+ }
+ });
+
// Testnet warning
if (Settings::getInstance()->isTestnet()) {
zb.testnetWarning->setText("You are on testnet, your post won't actually appear on z-board.net");
@@ -465,10 +483,20 @@ void MainWindow::postToZBoard() {
zb.testnetWarning->setText("");
}
+ QRegExpValidator v(QRegExp("^[a-zA-Z0-9_]{3,20}$"), zb.postAs);
+ zb.postAs->setValidator(&v);
+
zb.feeAmount->setText(Settings::getInstance()->getZECUSDDisplayFormat(Utils::getZboardAmount() + Utils::getMinerFee()));
- QObject::connect(zb.memoTxt, &QPlainTextEdit::textChanged, [=] () {
- QString txt = zb.memoTxt->toPlainText();
+ auto fnBuildNameMemo = [=]() -> QString {
+ auto memo = zb.memoTxt->toPlainText().trimmed();
+ if (!zb.postAs->text().trimmed().isEmpty())
+ memo = zb.postAs->text().trimmed() + ":: " + memo;
+ return memo;
+ };
+
+ auto fnUpdateMemoSize = [=]() {
+ QString txt = fnBuildNameMemo();
zb.memoSize->setText(QString::number(txt.toUtf8().size()) + "/512");
if (txt.toUtf8().size() <= 512) {
@@ -477,14 +505,26 @@ void MainWindow::postToZBoard() {
zb.memoSize->setStyleSheet("");
}
else {
- // Overweight
+ // Overweight
zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
zb.memoSize->setStyleSheet("color: red;");
}
-
- });
+
+ // Disallow blank memos
+ if (zb.memoTxt->toPlainText().trimmed().isEmpty()) {
+ zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ }
+ else {
+ zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+ }
+ };
+
+ // Memo text changed
+ QObject::connect(zb.memoTxt, &QPlainTextEdit::textChanged, fnUpdateMemoSize);
+ QObject::connect(zb.postAs, &QLineEdit::textChanged, fnUpdateMemoSize);
zb.memoTxt->setFocus();
+ fnUpdateMemoSize();
if (d.exec() == QDialog::Accepted) {
// Create a transaction.
@@ -501,7 +541,8 @@ void MainWindow::postToZBoard() {
if (!zb.postAs->text().trimmed().isEmpty())
memo = zb.postAs->text().trimmed() + ":: " + memo;
- tx.toAddrs.push_back(ToFields{ Utils::getZboardAddr(), Utils::getZboardAmount(), memo, memo.toUtf8().toHex() });
+ auto toAddr = topics[zb.topicsList->currentText()];
+ tx.toAddrs.push_back(ToFields{ toAddr, Utils::getZboardAmount(), memo, memo.toUtf8().toHex() });
tx.fee = Utils::getMinerFee();
json params = json::array();
@@ -520,7 +561,6 @@ void MainWindow::postToZBoard() {
}
void MainWindow::doImport(QList* keys) {
- qDebug() << keys->size();
if (keys->isEmpty()) {
delete keys;
ui->statusBar->showMessage("Private key import rescan finished");
@@ -545,6 +585,7 @@ void MainWindow::importPrivKey() {
QDialog d(this);
Ui_PrivKey pui;
pui.setupUi(&d);
+ Settings::saveRestore(&d);
pui.buttonBox->button(QDialogButtonBox::Save)->setVisible(false);
pui.helpLbl->setText(QString() %
@@ -577,11 +618,14 @@ void MainWindow::exportAllKeys() {
QDialog d(this);
Ui_PrivKey pui;
pui.setupUi(&d);
-
+
+ // Make the window big by default
auto ps = this->geometry();
QMargins margin = QMargins() + 50;
d.setGeometry(ps.marginsRemoved(margin));
+ Settings::saveRestore(&d);
+
pui.privKeyTxt->setPlainText("Loading...");
pui.privKeyTxt->setReadOnly(true);
pui.privKeyTxt->setLineWrapMode(QPlainTextEdit::LineWrapMode::NoWrap);
@@ -706,9 +750,19 @@ void MainWindow::setupZcashdTab() {
}
void MainWindow::setupTransactionsTab() {
+ // Double click opens up memo if one exists
+ QObject::connect(ui->transactionsTable, &QTableView::doubleClicked, [=] (auto index) {
+ auto txModel = dynamic_cast(ui->transactionsTable->model());
+ QString memo = txModel->getMemo(index.row());
+
+ if (!memo.isEmpty()) {
+ QMessageBox::information(this, "Memo", memo, QMessageBox::Ok);
+ }
+ });
+
// Set up context menu on transactions tab
ui->transactionsTable->setContextMenuPolicy(Qt::CustomContextMenu);
-
+ // Table right click
QObject::connect(ui->transactionsTable, &QTableView::customContextMenuRequested, [=] (QPoint pos) {
QModelIndex index = ui->transactionsTable->indexAt(pos);
if (index.row() < 0) return;
@@ -877,6 +931,7 @@ MainWindow::~MainWindow()
{
delete ui;
delete rpc;
+ delete labelCompleter;
delete loadingMovie;
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index e634a37..33d8f53 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -36,6 +36,8 @@ public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
+ void updateLabelsAutoComplete();
+
Ui::MainWindow* ui;
QLabel* statusLabel;
@@ -90,9 +92,10 @@ private:
void restoreSavedStates();
- RPC* rpc = nullptr;
+ RPC* rpc = nullptr;
+ QCompleter* labelCompleter = nullptr;
- QMovie* loadingMovie;
+ QMovie* loadingMovie;
};
#endif // MAINWINDOW_H
diff --git a/src/precompiled.h b/src/precompiled.h
index e046d7e..916fb43 100644
--- a/src/precompiled.h
+++ b/src/precompiled.h
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/rpc.cpp b/src/rpc.cpp
index 11ca9ae..a0aa2c5 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -470,7 +470,7 @@ void RPC::getInfoThenRefresh(bool force) {
};
// Connected, so display checkmark.
- QIcon i(":/icons/res/connected.png");
+ QIcon i(":/icons/res/connected.gif");
main->statusIcon->setPixmap(i.pixmap(16, 16));
static int lastBlock = 0;
@@ -899,3 +899,58 @@ void RPC::shutdownZcashd() {
// Wait for the zcash process to exit.
d.exec();
}
+
+
+// Fetch the Z-board topics list
+void RPC::getZboardTopics(std::function)> cb) {
+ if (conn == nullptr)
+ return noConnection();
+
+ QUrl cmcURL("http://z-board.net/listTopics");
+
+ QNetworkRequest req;
+ req.setUrl(cmcURL);
+
+ QNetworkReply *reply = conn->restclient->get(req);
+
+ QObject::connect(reply, &QNetworkReply::finished, [=] {
+ reply->deleteLater();
+
+ try {
+ if (reply->error() != QNetworkReply::NoError) {
+ auto parsed = json::parse(reply->readAll(), nullptr, false);
+ if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) {
+ qDebug() << QString::fromStdString(parsed["error"]["message"]);
+ }
+ else {
+ qDebug() << reply->errorString();
+ }
+ return;
+ }
+
+ auto all = reply->readAll();
+
+ auto parsed = json::parse(all, nullptr, false);
+ if (parsed.is_discarded()) {
+ return;
+ }
+
+ QMap topics;
+ for (const json& item : parsed["topics"].get()) {
+ if (item.find("addr") == item.end() || item.find("topicName") == item.end())
+ return;
+
+ QString addr = QString::fromStdString(item["addr"].get());
+ QString topic = QString::fromStdString(item["topicName"].get());
+
+ topics.insert(topic, addr);
+ }
+
+ cb(topics);
+ }
+ catch (...) {
+ // If anything at all goes wrong, just set the price to 0 and move on.
+ qDebug() << QString("Caught something nasty");
+ }
+ });
+}
diff --git a/src/rpc.h b/src/rpc.h
index 958a733..ae2b1ef 100644
--- a/src/rpc.h
+++ b/src/rpc.h
@@ -38,7 +38,9 @@ public:
void refresh(bool force = false);
void refreshAddresses();
+
void refreshZECPrice();
+ void getZboardTopics(std::function)> cb);
void fillTxJsonParams(json& params, Tx tx);
void sendZTransaction (json params, const std::function& cb);
diff --git a/src/scripts/mkrelease.sh b/src/scripts/mkrelease.sh
index aba3c0e..211dfd8 100755
--- a/src/scripts/mkrelease.sh
+++ b/src/scripts/mkrelease.sh
@@ -29,6 +29,7 @@ echo "[OK]"
echo -n "Cleaning.........."
rm -rf bin/*
+rm -rf artifacts/*
make distclean > /dev/null
echo "[OK]"
@@ -58,6 +59,7 @@ echo "[OK]"
echo -n "Packaging........."
mkdir bin/zec-qt-wallet-v$APP_VERSION > /dev/null
+strip zec-qt-wallet
cp zec-qt-wallet bin/zec-qt-wallet-v$APP_VERSION > /dev/null
cp ../zcash/artifacts/zcashd bin/zec-qt-wallet-v$APP_VERSION > /dev/null
cp README.md bin/zec-qt-wallet-v$APP_VERSION > /dev/null
diff --git a/src/sendtab.cpp b/src/sendtab.cpp
index 146f556..ae4e89e 100644
--- a/src/sendtab.cpp
+++ b/src/sendtab.cpp
@@ -45,6 +45,11 @@ void MainWindow::setupSendTab() {
QObject::connect(ui->Address1, &QLineEdit::textChanged, [=] (auto text) {
this->addressChanged(1, text);
});
+
+ // This is the damnest thing ever. If we do AddressBook::readFromStorage() directly, the whole file
+ // doesn't get read. It needs to run in a timer after everything has finished to be able to read
+ // the file properly.
+ QTimer::singleShot(100, [=]() { updateLabelsAutoComplete(); });
// The first address book button
QObject::connect(ui->AddressBook1, &QPushButton::clicked, [=] () {
@@ -87,6 +92,25 @@ void MainWindow::setupSendTab() {
});
}
+void MainWindow::updateLabelsAutoComplete() {
+ QList list;
+ auto labels = AddressBook::readFromStorage();
+
+ std::transform(labels.begin(), labels.end(), std::back_inserter(list), [=] (auto la) -> QString {
+ return la.first % "/" % la.second;
+ });
+
+ delete labelCompleter;
+ labelCompleter = new QCompleter(list, this);
+ labelCompleter->setCaseSensitivity(Qt::CaseInsensitive);
+
+ // Then, find all the address fields and update the completer.
+ QRegExp re("Address[0-9]+", Qt::CaseInsensitive);
+ for (auto target: ui->sendToWidgets->findChildren(re)) {
+ target->setCompleter(labelCompleter);
+ }
+}
+
void MainWindow::setDefaultPayFrom() {
auto findMax = [=] (QString startsWith) {
double max_amt = 0;
@@ -148,6 +172,7 @@ void MainWindow::addAddressSection() {
QObject::connect(Address1, &QLineEdit::textChanged, [=] (auto text) {
this->addressChanged(itemNumber, text);
});
+ Address1->setCompleter(labelCompleter);
horizontalLayout_12->addWidget(Address1);
@@ -350,6 +375,9 @@ Tx MainWindow::createTxFromSendPage() {
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
for (int i=0; i < totalItems; i++) {
QString addr = ui->sendToWidgets->findChild(QString("Address") % QString::number(i+1))->text().trimmed();
+ // Remove label if it exists
+ addr = addr.split("/").last();
+
double amt = ui->sendToWidgets->findChild(QString("Amount") % QString::number(i+1))->text().trimmed().toDouble();
QString memo = ui->sendToWidgets->findChild(QString("MemoTxt") % QString::number(i+1))->text().trimmed();
diff --git a/src/settings.cpp b/src/settings.cpp
index 38fee88..8ae7502 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -120,3 +120,11 @@ QString Settings::getZECUSDDisplayFormat(double bal) {
else
return getZECDisplayFormat(bal);
}
+
+void Settings::saveRestore(QDialog* d) {
+ d->restoreGeometry(QSettings().value(d->objectName() % "geometry").toByteArray());
+
+ QObject::connect(d, &QDialog::finished, [=](auto) {
+ QSettings().setValue(d->objectName() % "geometry", d->saveGeometry());
+ });
+}
diff --git a/src/settings.h b/src/settings.h
index a19d9fe..b13586f 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -16,6 +16,8 @@ public:
static Settings* init();
static Settings* getInstance();
+ static void saveRestore(QDialog* d);
+
Config getSettings();
void saveSettings(const QString& host, const QString& port, const QString& username, const QString& password);
@@ -48,8 +50,7 @@ public:
void setZECPrice(double p) { zecPrice = p; }
double getZECPrice();
-
-
+
QString getUSDFormat (double bal);
QString getZECDisplayFormat (double bal);
QString getZECUSDDisplayFormat(double bal);
diff --git a/src/txid.ui b/src/txid.ui
deleted file mode 100644
index 18d31ab..0000000
--- a/src/txid.ui
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
-
-
- Dialog
-
-
-
- 0
- 0
- 400
- 300
-
-
-
- Dialog
-
-
-
-
- 30
- 240
- 341
- 32
-
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
-
- buttonBox
- accepted()
- Dialog
- accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- Dialog
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
-
diff --git a/src/utils.cpp b/src/utils.cpp
index bffe3e9..7f638fb 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -30,37 +30,8 @@ const QString Utils::getDevSproutAddr() {
}
// Get the dev fee address based on the transaction
-const QString Utils::getDevAddr(Tx tx) {
- auto testnetAddrLookup = [=] (const QString& addr) -> QString {
- if (addr.startsWith("ztestsapling")) {
- return "ztestsapling1kdp74adyfsmm9838jaupgfyx3npgw8ut63stjjx757pc248cuc0ymzphqeux60c64qe5qt68ygh";
- } else if (addr.startsWith("zt")) {
- return getDevSproutAddr();
- } else {
- return QString();
- }
- };
-
- if (Settings::getInstance()->isTestnet()) {
- auto devAddr = testnetAddrLookup(tx.fromAddr);
- if (!devAddr.isEmpty()) {
- return devAddr;
- }
-
- // t-Addr, find if it is going to a Sprout or Sapling address
- for (const ToFields& to : tx.toAddrs) {
- devAddr = testnetAddrLookup(to.addr);
- if (!devAddr.isEmpty()) {
- return devAddr;
- }
- }
-
- // If this is a t-Addr -> t-Addr transaction, use the Sapling address by default
- return testnetAddrLookup("ztestsapling");
- } else {
- // Mainnet doesn't have a fee yet!
- return QString();
- }
+const QString Utils::getDevAddr(Tx) {
+ return QString();
}
@@ -82,7 +53,7 @@ QString Utils::getZboardAddr() {
}
double Utils::getDevFee() {
if (Settings::getInstance()->isTestnet()) {
- return 0.0001;
+ return 0;
} else {
return 0;
}
diff --git a/src/zboard.ui b/src/zboard.ui
index 7b8e466..8a16047 100644
--- a/src/zboard.ui
+++ b/src/zboard.ui
@@ -82,7 +82,7 @@
-
- <html><head/><body><p>ZBoard: Fully anonymous and untraceable chat messages based on the ZCash blockchain. <a href="http://www.z-board.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.z-board.net/</span></a></p><p>Posting to ZBoard: #Main_Area</p></body></html>
+ <html><head/><body><p>ZBoard: Fully anonymous and untraceable chat messages based on the ZCash blockchain. <a href="http://www.z-board.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.z-board.net/</span></a></p></body></html>
true
@@ -115,6 +115,16 @@
+ -
+
+
+ -
+
+
+ Posting to Board
+
+
+
diff --git a/zec-qt-wallet.pro b/zec-qt-wallet.pro
index b62b9be..be1c031 100644
--- a/zec-qt-wallet.pro
+++ b/zec-qt-wallet.pro
@@ -13,7 +13,7 @@ PRECOMPILED_HEADER = src/precompiled.h
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = zec-qt-wallet
-APP_VERSION=\\\"0.2.8\\\"
+APP_VERSION=\\\"0.2.9\\\"
TEMPLATE = app