From 858861436bfcf1576287f759354b91a7e81d106b Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 14 Mar 2021 22:12:02 +0100 Subject: [PATCH] Misc changes --- CMakeLists.txt | 2 +- Dockerfile | 2 +- Dockerfile.windows | 3 +- README.md | 16 +-- monero | 2 +- src/coinswidget.cpp | 112 +++++++++------------ src/coinswidget.h | 1 + src/dialog/aboutdialog.cpp | 3 +- src/dialog/outputsweepdialog.cpp | 19 +++- src/dialog/outputsweepdialog.h | 5 +- src/dialog/outputsweepdialog.ui | 92 +++++++++++------- src/dialog/transactioninfodialog.cpp | 84 ++++++++++++---- src/dialog/transactioninfodialog.h | 6 ++ src/dialog/transactioninfodialog.ui | 135 ++++++++++---------------- src/dialog/txconfadvdialog.ui | 21 ++++ src/dialog/viewonlydialog.cpp | 2 +- src/historywidget.cpp | 3 + src/libwalletqt/Coins.cpp | 20 ++-- src/libwalletqt/Coins.h | 3 +- src/libwalletqt/Subaddress.cpp | 5 + src/libwalletqt/Subaddress.h | 1 + src/libwalletqt/Wallet.cpp | 13 ++- src/libwalletqt/Wallet.h | 3 + src/mainwindow.cpp | 17 +++- src/model/CoinsModel.cpp | 5 + src/model/CoinsModel.h | 2 + src/model/HistoryView.cpp | 12 +++ src/model/HistoryView.h | 4 + src/model/SubaddressModel.cpp | 5 + src/model/SubaddressModel.h | 2 + src/model/SubaddressProxyModel.cpp | 4 + src/model/SubaddressProxyModel.h | 14 +++ src/model/TransactionHistoryModel.cpp | 5 +- src/receivewidget.cpp | 82 ++++++++++++++-- src/receivewidget.h | 10 +- src/receivewidget.ui | 21 ++++ src/sendwidget.ui | 9 +- src/settings.cpp | 27 ++++++ src/settings.h | 9 +- src/settings.ui | 24 ++++- src/utils/config.cpp | 4 +- src/utils/config.h | 4 +- src/wizard/PageMenu.ui | 3 + src/wizard/PageNetwork.h | 1 - src/wizard/PageWalletRestoreKeys.h | 2 - src/wizard/PageWalletRestoreSeed.cpp | 1 - 46 files changed, 562 insertions(+), 258 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e51abf6..265599a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ if(DEBUG) set(CMAKE_VERBOSE_MAKEFILE ON) endif() -set(MONERO_HEAD "e175e02b9b8d289bccab3ff0f3fd70c4dbf8c71f") +set(MONERO_HEAD "52acbb68c1a4cc67ee539325a8febc2c144596c4") set(BUILD_GUI_DEPS ON) set(ARCH "x86-64") set(BUILD_64 ON) diff --git a/Dockerfile b/Dockerfile index 35294c2..850729d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,7 +42,7 @@ RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \ make -j$THREADS install && \ rm -rf $(pwd) -RUN git clone -b tor-0.4.5.5-rc --depth 1 https://git.torproject.org/tor.git && \ +RUN git clone -b tor-0.4.5.6 --depth 1 https://git.torproject.org/tor.git && \ cd tor && \ git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \ ./autogen.sh && \ diff --git a/Dockerfile.windows b/Dockerfile.windows index 4fadfe6..75b3e0b 100644 --- a/Dockerfile.windows +++ b/Dockerfile.windows @@ -146,8 +146,7 @@ RUN wget https://github.com/libevent/libevent/releases/download/release-2.1.11-s make -j$THREADS install && \ rm -rf $(pwd) -ENV TOR_VERSION=0.4.5.5-rc -RUN git clone -b tor-0.4.5.5-rc --depth 1 https://git.torproject.org/tor.git && \ +RUN git clone -b tor-0.4.5.6 --depth 1 https://git.torproject.org/tor.git && \ cd tor && \ git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \ ./autogen.sh && \ diff --git a/README.md b/README.md index 26d6ebf..1ad5f74 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,19 @@ # Feather - a free Monero desktop wallet -[![Build Status](https://build.featherwallet.org/api/badges/feather/feather/status.svg)](https://build.featherwallet.org/feather/feather) +Feather is a free, open-source Monero wallet for Linux, Tails, macOS and Windows. It is written in C++ with the Qt framework. -Feather is a free, open-source Monero client Linux with ports for Mac OS and Windows written in C++ with the Qt framework. +Copyright (c) 2020-2021, The Monero Project. -## Development resources +## Resources * Web: [featherwallet.org](https://featherwallet.org) * Git: [git.featherwallet.org/feather/feather](https://git.featherwallet.org/feather/feather) * Mail: dev@featherwallet.org * IRC: `#feather` on OFTC * Development builds: [build.featherwallet.org/files](https://build.featherwallet.org/files/) -Copyright (c) 2020-2021 The Monero Project. - ## Compiling Feather from source -Feather uses Monero, as such it requires the same dependencies as outlined in [Monero's README](https://github.com/monero-project/monero#compiling-monero-from-source). Additionally, Feather uses: - -- Qt 5.15.0 -- libqrencode -- openpgp - -See [BUILDING.md](https://git.featherwallet.org/feather/feather/src/branch/master/BUILDING.md) for information on how to compile a build. +See [BUILDING.md](https://git.featherwallet.org/feather/feather/src/branch/master/BUILDING.md) for information on how to build from source. ## Supporting the project diff --git a/monero b/monero index e175e02..52acbb6 160000 --- a/monero +++ b/monero @@ -1 +1 @@ -Subproject commit e175e02b9b8d289bccab3ff0f3fd70c4dbf8c71f +Subproject commit 52acbb68c1a4cc67ee539325a8febc2c144596c4 diff --git a/src/coinswidget.cpp b/src/coinswidget.cpp index 21934a5..042750f 100644 --- a/src/coinswidget.cpp +++ b/src/coinswidget.cpp @@ -89,19 +89,12 @@ void CoinsWidget::showContextMenu(const QPoint &point) { menu->addAction(m_thawAllSelectedAction); } else { - QModelIndex index = ui->coins->indexAt(point); - if (!index.isValid()) { - return; - } + CoinsInfo* c = this->currentEntry(); + if (!c) return; - int row = m_proxyModel->mapToSource(index).row(); - - bool isSpent, isFrozen, isUnlocked; - m_coins->coin(row, [&isSpent, &isFrozen, &isUnlocked](CoinsInfo &c) { - isSpent = c.spent(); - isFrozen = c.frozen(); - isUnlocked = c.unlocked(); - }); + bool isSpent = c->spent(); + bool isFrozen = c->frozen(); + bool isUnlocked = c->unlocked(); menu->addMenu(m_copyMenu); @@ -166,44 +159,28 @@ void CoinsWidget::thawAllSelected() { } void CoinsWidget::viewOutput() { - QModelIndex index = ui->coins->currentIndex(); + CoinsInfo* c = this->currentEntry(); + if (!c) return; - int row = m_proxyModel->mapToSource(index).row(); - QPointer c; - m_coins->coin(row, [&c](CoinsInfo &cInfo) { - c = &cInfo; - }); - - if (c) { - auto * dialog = new OutputInfoDialog(c, this); - dialog->show(); - } + auto * dialog = new OutputInfoDialog(c, this); + dialog->show(); } void CoinsWidget::onSweepOutput() { - QModelIndex index = ui->coins->currentIndex(); - int row = m_proxyModel->mapToSource(index).row(); + CoinsInfo* c = this->currentEntry(); + if (!c) return; - QString keyImage; - bool keyImageKnown; - m_coins->coin(row, [&keyImage, &keyImageKnown](CoinsInfo &c) { - keyImageKnown = c.keyImageKnown(); - keyImage = c.keyImage(); - }); + QString keyImage = c->keyImage(); - qCritical() << "key image: " << keyImage; - - if (!keyImageKnown) { + if (!c->keyImageKnown()) { QMessageBox::warning(this, "Unable to sweep output", "Unable to sweep output: key image unknown"); return; } - auto * dialog = new OutputSweepDialog(this); + auto *dialog = new OutputSweepDialog(this, c); int ret = dialog->exec(); if (!ret) return; - qCritical() << "key image: " << keyImage; - emit sweepOutput(keyImage, dialog->address(), dialog->churn(), dialog->outputs()); dialog->deleteLater(); } @@ -213,39 +190,46 @@ void CoinsWidget::resetModel() { } void CoinsWidget::copy(copyField field) { - QModelIndex index = ui->coins->currentIndex(); - int row = m_proxyModel->mapToSource(index).row(); + CoinsInfo* c = this->currentEntry(); + if (!c) return; QString data; - m_coins->coin(row, [field, &data](CoinsInfo &c) { - switch (field) { - case PubKey: - data = c.pubKey(); - break; - case KeyImage: - data = c.keyImage(); - break; - case TxID: - data = c.hash(); - break; - case Address: - data = c.address(); - break; - case Label: - data = c.addressLabel(); - break; - case Height: - data = QString::number(c.blockHeight()); - break; - case Amount: - data = c.displayAmount(); - break; - } - }); + switch (field) { + case PubKey: + data = c->pubKey(); + break; + case KeyImage: + data = c->keyImage(); + break; + case TxID: + data = c->hash(); + break; + case Address: + data = c->address(); + break; + case Label: + data = c->addressLabel(); + break; + case Height: + data = QString::number(c->blockHeight()); + break; + case Amount: + data = c->displayAmount(); + break; + } Utils::copyToClipboard(data); } +CoinsInfo* CoinsWidget::currentEntry() { + QModelIndexList list = ui->coins->selectionModel()->selectedRows(); + if (list.size() == 1) { + return m_model->entryFromIndex(m_proxyModel->mapToSource(list.first())); + } else { + return nullptr; + } +} + CoinsWidget::~CoinsWidget() { delete ui; } diff --git a/src/coinswidget.h b/src/coinswidget.h index 4ee451f..0a51eed 100644 --- a/src/coinswidget.h +++ b/src/coinswidget.h @@ -73,6 +73,7 @@ private: void showContextMenu(const QPoint & point); void copy(copyField field); + CoinsInfo* currentEntry(); }; diff --git a/src/dialog/aboutdialog.cpp b/src/dialog/aboutdialog.cpp index 671d8f2..a076c0b 100644 --- a/src/dialog/aboutdialog.cpp +++ b/src/dialog/aboutdialog.cpp @@ -9,6 +9,7 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) , ui(new Ui::AboutDialog) + , m_model(new QStringListModel(this)) { ui->setupUi(this); this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); @@ -26,8 +27,6 @@ AboutDialog::AboutDialog(QWidget *parent) auto ack_text = Utils::barrayToString(ack); ui->ackText->setText(ack_text); - m_model = new QStringListModel(this); - QString contributors = Utils::barrayToString(Utils::fileOpenQRC(":assets/contributors.txt")); QStringList contributor_list = contributors.split("\n"); m_model->setStringList(contributor_list); diff --git a/src/dialog/outputsweepdialog.cpp b/src/dialog/outputsweepdialog.cpp index 0789b1c..f92c3a2 100644 --- a/src/dialog/outputsweepdialog.cpp +++ b/src/dialog/outputsweepdialog.cpp @@ -3,15 +3,19 @@ #include "ui_outputsweepdialog.h" #include "outputsweepdialog.h" +#include "libwalletqt/WalletManager.h" -OutputSweepDialog::OutputSweepDialog(QWidget *parent) +OutputSweepDialog::OutputSweepDialog(QWidget *parent, CoinsInfo* coin) : QDialog(parent) , ui(new Ui::OutputSweepDialog) { ui->setupUi(this); + m_amount = coin->amount(); + connect(ui->checkBox_churn, &QCheckBox::toggled, [&](bool toggled){ ui->lineEdit_address->setEnabled(!toggled); + ui->lineEdit_address->setText(toggled ? "Primary address" : ""); }); connect(ui->buttonBox, &QDialogButtonBox::accepted, [&](){ @@ -20,6 +24,19 @@ OutputSweepDialog::OutputSweepDialog(QWidget *parent) m_outputs = ui->spinBox_numOutputs->value(); }); + connect(ui->spinBox_numOutputs, QOverload::of(&QSpinBox::valueChanged), [this](int value){ + if (value == 1) { + ui->label_split->setText(""); + return; + } + + QString origAmount = WalletManager::displayAmount(m_amount); + QString splitAmount = WalletManager::displayAmount(m_amount / value); + + ui->label_split->setText(QString("%1 XMR ≈ %2x %3 XMR").arg(origAmount, QString::number(value), splitAmount)); + }); + ui->label_split->setText(""); + this->adjustSize(); } diff --git a/src/dialog/outputsweepdialog.h b/src/dialog/outputsweepdialog.h index ebbffce..f91e65f 100644 --- a/src/dialog/outputsweepdialog.h +++ b/src/dialog/outputsweepdialog.h @@ -5,6 +5,7 @@ #define FEATHER_OUTPUTSWEEPDIALOG_H #include +#include "libwalletqt/CoinsInfo.h" namespace Ui { class OutputSweepDialog; @@ -15,7 +16,7 @@ class OutputSweepDialog : public QDialog Q_OBJECT public: - explicit OutputSweepDialog(QWidget *parent = nullptr); + explicit OutputSweepDialog(QWidget *parent, CoinsInfo* coin); ~OutputSweepDialog() override; QString address(); @@ -25,6 +26,8 @@ public: private: Ui::OutputSweepDialog *ui; + uint64_t m_amount; + QString m_address; bool m_churn; int m_outputs; diff --git a/src/dialog/outputsweepdialog.ui b/src/dialog/outputsweepdialog.ui index e6abab4..fc417c4 100644 --- a/src/dialog/outputsweepdialog.ui +++ b/src/dialog/outputsweepdialog.ui @@ -6,16 +6,22 @@ 0 0 - 623 - 231 + 720 + 193 Sweep output + + 10 + + + 0 + @@ -36,48 +42,60 @@ + + + + Send to self (churn) + + + - - - Send to self (churn) - - + + + + + Number of outputs: + + + + + + + 1 + + + 16 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - Advanced options - - - true - - + + false - - - QFormLayout::ExpandingFieldsGrow - - - - - Number of outputs: - - - - - - - 1 - - - 16 - - - - + + 1.000000000000 XMR ≈ 5x 0.200000000000 XMR + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + diff --git a/src/dialog/transactioninfodialog.cpp b/src/dialog/transactioninfodialog.cpp index 7347c8b..2de9dad 100644 --- a/src/dialog/transactioninfodialog.cpp +++ b/src/dialog/transactioninfodialog.cpp @@ -7,10 +7,15 @@ #include "libwalletqt/CoinsInfo.h" #include "libwalletqt/WalletManager.h" #include "libwalletqt/Transfer.h" +#include "libwalletqt/TransactionHistory.h" #include "utils.h" #include "utils/ColorScheme.h" +#include "model/ModelUtils.h" +#include "config.h" +#include "appcontext.h" #include +#include TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent) : QDialog(parent) @@ -23,32 +28,26 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx m_txid = txInfo->hash(); ui->label_txid->setText(m_txid); - QString txKey = m_wallet->getTxKey(txInfo->hash()); - if (txKey.isEmpty()) { + m_txKey = m_wallet->getTxKey(txInfo->hash()); + if (m_txKey.isEmpty()) { ui->btn_CopyTxKey->setEnabled(false); ui->btn_CopyTxKey->setToolTip("Transaction key unknown"); } - m_txKey = txKey; connect(ui->btn_CopyTxKey, &QPushButton::pressed, this, &TransactionInfoDialog::copyTxKey); connect(ui->btn_createTxProof, &QPushButton::pressed, this, &TransactionInfoDialog::createTxProof); - QString blockHeight = QString::number(txInfo->blockHeight()); - if (blockHeight == "0") - blockHeight = "Unconfirmed"; + connect(m_wallet, &Wallet::newBlock, this, &TransactionInfoDialog::updateData); - ui->label_status->setText(QString("Status: %1 confirmations").arg(txInfo->confirmations())); - ui->label_date->setText(QString("Date: %1").arg(txInfo->timestamp().toString("yyyy-MM-dd HH:mm"))); - ui->label_blockHeight->setText(QString("Block height: %1").arg(blockHeight)); + this->setData(txInfo); - QString direction = txInfo->direction() == TransactionInfo::Direction_In ? "received" : "sent"; - ui->label_amount->setText(QString("Amount %1: %2").arg(direction, txInfo->displayAmount())); - - QString fee = txInfo->fee().isEmpty() ? "n/a" : txInfo->fee(); - ui->label_fee->setText(QString("Fee: %1").arg(txInfo->isCoinbase() ? WalletManager::displayAmount(0) : fee)); - ui->label_unlockTime->setText(QString("Unlock time: %1 (height)").arg(txInfo->unlockTime())); - - qDebug() << m_wallet->coins()->coins_from_txid(txInfo->hash()); + if (AppContext::txCache.contains(txInfo->hash()) && (txInfo->isFailed() || txInfo->isPending()) && txInfo->direction() != TransactionInfo::Direction_In) { + connect(ui->btn_rebroadcastTx, &QPushButton::pressed, [this]{ + emit resendTranscation(m_txid); + }); + } else { + ui->btn_rebroadcastTx->hide(); + } QTextCursor cursor = ui->destinations->textCursor(); for (const auto& transfer : txInfo->transfers()) { @@ -59,15 +58,66 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx cursor.insertText(QString(" %1").arg(amount), QTextCharFormat()); cursor.insertBlock(); } + if (txInfo->transfers().size() == 0) { ui->frameDestinations->hide(); } m_txProofDialog = new TxProofDialog(this, m_wallet, txInfo); + QCoreApplication::processEvents(); + + qreal lineHeight = QFontMetrics(ui->destinations->document()->defaultFont()).height(); + qreal docHeight = txInfo->transfers().size(); + int h = int(docHeight * (lineHeight + 2) + 11); + h = qMin(qMax(h, 100), 600); + ui->destinations->setMinimumHeight(h); + ui->destinations->setMaximumHeight(h); + ui->destinations->verticalScrollBar()->hide(); + this->adjustSize(); } +void TransactionInfoDialog::setData(TransactionInfo* tx) { + QString blockHeight = QString::number(tx->blockHeight()); + + if (tx->isFailed()) { + ui->label_status->setText("Status: Failed (node was unable to relay transaction)"); + } + if (blockHeight == "0") { + ui->label_status->setText("Status: Unconfirmed (in mempool)"); + } + else { + QString dateTimeFormat = QString("%1 %2").arg(config()->get(Config::dateFormat).toString(), config()->get(Config::timeFormat).toString()); + QString date = tx->timestamp().toString(dateTimeFormat); + QString statusText = QString("Status: Included in block %1 (%2 confirmations) on %3").arg(blockHeight, QString::number(tx->confirmations()), date); + ui->label_status->setText(statusText); + } + + + if (tx->confirmationsRequired() > tx->confirmations()) { + bool mandatoryLock = tx->confirmationsRequired() == 10; + QString confsRequired = QString::number(tx->confirmationsRequired() - tx->confirmations()); + ui->label_lock->setText(QString("Lock: Outputs become spendable in %1 blocks (%2)").arg(confsRequired, mandatoryLock ? "consensus rule" : "specified by sender")); + } else { + ui->label_lock->setText("Lock: Outputs are spendable"); + } + + QString direction = tx->direction() == TransactionInfo::Direction_In ? "received" : "sent"; + ui->label_amount->setText(QString("Amount %1: %2").arg(direction, tx->displayAmount())); + + QString fee = tx->fee().isEmpty() ? "n/a" : tx->fee(); + ui->label_fee->setText(QString("Fee: %1 XMR").arg(tx->isCoinbase() ? WalletManager::displayAmount(0) : fee)); + +} + +void TransactionInfoDialog::updateData() { + if (!m_wallet) return; + TransactionInfo* tx = m_wallet->history()->transaction(m_txid); + if (!tx) return; + this->setData(tx); +} + void TransactionInfoDialog::copyTxKey() { Utils::copyToClipboard(m_txKey); } diff --git a/src/dialog/transactioninfodialog.h b/src/dialog/transactioninfodialog.h index d74e231..02908dc 100644 --- a/src/dialog/transactioninfodialog.h +++ b/src/dialog/transactioninfodialog.h @@ -24,9 +24,14 @@ public: explicit TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr); ~TransactionInfoDialog() override; +signals: + void resendTranscation(const QString &txid); + private: void copyTxKey(); void createTxProof(); + void setData(TransactionInfo* tx); + void updateData(); Ui::TransactionInfoDialog *ui; @@ -35,6 +40,7 @@ private: Wallet *m_wallet; QString m_txKey; QString m_txid; + QTimer m_updateTimer; }; #endif //FEATHER_TRANSACTIONINFODIALOG_H diff --git a/src/dialog/transactioninfodialog.ui b/src/dialog/transactioninfodialog.ui index c761040..ceb0dfc 100644 --- a/src/dialog/transactioninfodialog.ui +++ b/src/dialog/transactioninfodialog.ui @@ -6,17 +6,14 @@ 0 0 - 829 - 493 + 929 + 631 Transaction - - - @@ -37,81 +34,46 @@ - + - - - - - Status: - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - Date: - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - Block height: - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - - Qt::Vertical + + + Status: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - Amount received: - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - Fee: - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - Unlock time: - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - + + + Lock: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Amount received: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Fee: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + @@ -154,6 +116,12 @@ + + + 0 + 0 + + Destinations: @@ -162,17 +130,11 @@ - + 0 0 - - - 0 - 100 - - true @@ -187,7 +149,7 @@ Qt::Vertical - QSizePolicy::Minimum + QSizePolicy::Expanding @@ -213,6 +175,13 @@ + + + + Rebroadcast Transaction + + + diff --git a/src/dialog/txconfadvdialog.ui b/src/dialog/txconfadvdialog.ui index 38f3cbc..98abf6b 100644 --- a/src/dialog/txconfadvdialog.ui +++ b/src/dialog/txconfadvdialog.ui @@ -53,6 +53,9 @@ TextLabel + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -67,6 +70,9 @@ TextLabel + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -88,6 +94,9 @@ TextLabel + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -106,6 +115,9 @@ Description: + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -113,6 +125,9 @@ Size: + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -120,6 +135,9 @@ Unlock time: + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -127,6 +145,9 @@ Ringsize: + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + diff --git a/src/dialog/viewonlydialog.cpp b/src/dialog/viewonlydialog.cpp index d62c5b3..3a551ff 100644 --- a/src/dialog/viewonlydialog.cpp +++ b/src/dialog/viewonlydialog.cpp @@ -26,7 +26,7 @@ ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent) } void ViewOnlyDialog::onWriteViewOnlyWallet(){ - QString fn = QFileDialog::getSaveFileName(this, "Save .keys wallet file", QDir::homePath(), "Monero wallet (*.keys)"); + QString fn = QFileDialog::getSaveFileName(this, "Save .keys wallet file", Utils::defaultWalletDir(), "Monero wallet (*.keys)"); if(fn.isEmpty()) return; if(!fn.endsWith(".keys")) fn += ".keys"; diff --git a/src/historywidget.cpp b/src/historywidget.cpp index 831e575..941601e 100644 --- a/src/historywidget.cpp +++ b/src/historywidget.cpp @@ -101,6 +101,9 @@ void HistoryWidget::showTxDetails() { if (!tx) return; auto *dialog = new TransactionInfoDialog(m_wallet, tx, this); + connect(dialog, &TransactionInfoDialog::resendTranscation, [this](const QString &txid){ + emit resendTransaction(txid); + }); dialog->show(); } diff --git a/src/libwalletqt/Coins.cpp b/src/libwalletqt/Coins.cpp index 677c700..c275cab 100644 --- a/src/libwalletqt/Coins.cpp +++ b/src/libwalletqt/Coins.cpp @@ -24,6 +24,11 @@ bool Coins::coin(int index, std::function callback) return true; } +CoinsInfo* Coins::coin(int index) +{ + return m_tinfo.value(index); +} + void Coins::refresh(quint32 accountIndex) { emit refreshStarted(); @@ -74,18 +79,17 @@ void Coins::thaw(int index) const emit coinThawed(); } -QStringList Coins::coins_from_txid(const QString &txid) +QVector Coins::coins_from_txid(const QString &txid) { - QStringList keyimages; + QVector coins; for (int i = 0; i < this->count(); i++) { - this->coin(i, [&keyimages, &txid](const CoinsInfo &x) { - if (x.hash() == txid) { - keyimages += x.keyImage(); - } - }); + CoinsInfo* coin = this->coin(i); + if (coin->hash() == txid) { + coins.append(coin); + } } - return keyimages; + return coins; } Coins::Coins(Monero::Coins *pimpl, QObject *parent) diff --git a/src/libwalletqt/Coins.h b/src/libwalletqt/Coins.h index e92f458..62060a9 100644 --- a/src/libwalletqt/Coins.h +++ b/src/libwalletqt/Coins.h @@ -25,11 +25,12 @@ Q_OBJECT public: Q_INVOKABLE bool coin(int index, std::function callback); + Q_INVOKABLE CoinsInfo * coin(int index); Q_INVOKABLE void refresh(quint32 accountIndex); Q_INVOKABLE void refreshUnlocked(); Q_INVOKABLE void freeze(int index) const; Q_INVOKABLE void thaw(int index) const; - Q_INVOKABLE QStringList coins_from_txid(const QString &txid); // Todo: return CoinsInfo vector + Q_INVOKABLE QVector coins_from_txid(const QString &txid); quint64 count() const; diff --git a/src/libwalletqt/Subaddress.cpp b/src/libwalletqt/Subaddress.cpp index 8518fda..28f3125 100644 --- a/src/libwalletqt/Subaddress.cpp +++ b/src/libwalletqt/Subaddress.cpp @@ -78,3 +78,8 @@ quint64 Subaddress::count() const return m_rows.size(); } + +Monero::SubaddressRow* Subaddress::row(int index) const +{ + return m_rows.value(index); +} \ No newline at end of file diff --git a/src/libwalletqt/Subaddress.h b/src/libwalletqt/Subaddress.h index 92f9c88..735d370 100644 --- a/src/libwalletqt/Subaddress.h +++ b/src/libwalletqt/Subaddress.h @@ -23,6 +23,7 @@ public: Q_INVOKABLE void refresh(quint32 accountIndex) const; Q_INVOKABLE quint64 unusedLookahead() const; quint64 count() const; + Monero::SubaddressRow* row(int index) const; signals: void refreshStarted() const; diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index b47b34b..0140207 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -293,6 +293,11 @@ bool Wallet::viewOnly() const return m_walletImpl->watchOnly(); } +bool Wallet::isDeterministic() const +{ + return m_walletImpl->isDeterministic(); +} + quint64 Wallet::balance() const { return balance(m_currentSubaddressAccount); @@ -400,9 +405,11 @@ void Wallet::refreshHeightAsync() daemonHeightFuture.second.waitForFinished(); targetHeightFuture.second.waitForFinished(); - setConnectionStatus(ConnectionStatus_Connected); - - emit heightRefreshed(walletHeight, daemonHeight, targetHeight); + if (daemonHeight > 0 && targetHeight > 0) { + emit heightRefreshed(walletHeight, daemonHeight, targetHeight); + qDebug() << "Setting connection status from refreshHeightAsync"; + setConnectionStatus(ConnectionStatus_Connected); + } }); } diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h index 56f2013..58fd655 100644 --- a/src/libwalletqt/Wallet.h +++ b/src/libwalletqt/Wallet.h @@ -224,6 +224,9 @@ public: //! returns if view only wallet Q_INVOKABLE bool viewOnly() const; + //! return true if deterministic keys + Q_INVOKABLE bool isDeterministic() const; + Q_INVOKABLE void refreshHeightAsync(); //! export/import key images diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3b2b31c..a9df680 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -597,7 +597,7 @@ void MainWindow::onWalletOpened() { // receive page m_ctx->currentWallet->subaddress()->refresh( m_ctx->currentWallet->currentSubaddressAccount()); - ui->receiveWidget->setModel( m_ctx->currentWallet->subaddressModel(), m_ctx->currentWallet->subaddress()); + ui->receiveWidget->setModel( m_ctx->currentWallet->subaddressModel(), m_ctx->currentWallet); if (m_ctx->currentWallet->subaddress()->count() == 1) { for (int i = 0; i < 10; i++) { m_ctx->currentWallet->subaddress()->addRow(m_ctx->currentWallet->currentSubaddressAccount(), ""); @@ -837,6 +837,16 @@ void MainWindow::showWalletInfoDialog() { } void MainWindow::showSeedDialog() { + if (m_ctx->currentWallet->viewOnly()) { + QMessageBox::information(this, "Information", "Wallet is view-only and has no seed.\n\nTo obtain wallet keys go to Wallet -> View-Only"); + return; + } + + if (!m_ctx->currentWallet->isDeterministic()) { + QMessageBox::information(this, "Information", "Wallet is non-deterministic and has no seed.\n\nTo obtain wallet keys go to Wallet -> Keys"); + return; + } + auto *dialog = new SeedDialog(m_ctx->currentWallet, this); dialog->exec(); dialog->deleteLater(); @@ -1303,6 +1313,11 @@ void MainWindow::updateNetStats() { return; } + if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) { + m_statusLabelNetStats->setText(""); + return; + } + if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Connected && m_ctx->currentWallet->synchronized()) { m_statusLabelNetStats->setText(""); return; diff --git a/src/model/CoinsModel.cpp b/src/model/CoinsModel.cpp index 9231695..85468b4 100644 --- a/src/model/CoinsModel.cpp +++ b/src/model/CoinsModel.cpp @@ -197,4 +197,9 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in return QVariant(); } } +} + +CoinsInfo* CoinsModel::entryFromIndex(const QModelIndex &index) const { + Q_ASSERT(index.isValid() && index.row() < m_coins->count()); + return m_coins->coin(index.row()); } \ No newline at end of file diff --git a/src/model/CoinsModel.h b/src/model/CoinsModel.h index 062ff9d..6db5e03 100644 --- a/src/model/CoinsModel.h +++ b/src/model/CoinsModel.h @@ -43,6 +43,8 @@ public: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + CoinsInfo* entryFromIndex(const QModelIndex &index) const; + public slots: void startReset(); void endReset(); diff --git a/src/model/HistoryView.cpp b/src/model/HistoryView.cpp index 2eec65c..c3a99bd 100644 --- a/src/model/HistoryView.cpp +++ b/src/model/HistoryView.cpp @@ -4,6 +4,7 @@ #include "HistoryView.h" #include "TransactionHistoryProxyModel.h" +#include "libwalletqt/TransactionInfo.h" #include #include @@ -186,3 +187,14 @@ void HistoryView::resetViewToDefaults() fitColumnsToWindow(); } } + +void HistoryView::keyPressEvent(QKeyEvent *event) { + TransactionInfo* tx = this->currentEntry(); + + if (event->matches(QKeySequence::Copy) && tx) { + Utils::copyToClipboard(tx->hash()); + } + else { + QTreeView::keyPressEvent(event); + } +} \ No newline at end of file diff --git a/src/model/HistoryView.h b/src/model/HistoryView.h index 75205e1..63ba555 100644 --- a/src/model/HistoryView.h +++ b/src/model/HistoryView.h @@ -4,6 +4,7 @@ #ifndef FEATHER_HISTORYVIEW_H #define FEATHER_HISTORYVIEW_H +#include #include #include @@ -29,6 +30,9 @@ private slots: void fitColumnsToContents(); void resetViewToDefaults(); +protected: + void keyPressEvent(QKeyEvent *event); + private: TransactionHistoryModel* sourceModel(); diff --git a/src/model/SubaddressModel.cpp b/src/model/SubaddressModel.cpp index 35ea020..a6ec715 100644 --- a/src/model/SubaddressModel.cpp +++ b/src/model/SubaddressModel.cpp @@ -180,3 +180,8 @@ bool SubaddressModel::isShowFullAddresses() const { int SubaddressModel::unusedLookahead() const { return m_subaddress->unusedLookahead(); } + +Monero::SubaddressRow* SubaddressModel::entryFromIndex(const QModelIndex &index) const { + Q_ASSERT(index.isValid() && index.row() < m_subaddress->count()); + return m_subaddress->row(index.row()); +} \ No newline at end of file diff --git a/src/model/SubaddressModel.h b/src/model/SubaddressModel.h index 773711b..0b8eb0c 100644 --- a/src/model/SubaddressModel.h +++ b/src/model/SubaddressModel.h @@ -38,6 +38,8 @@ public: bool isShowFullAddresses() const; void setShowFullAddresses(bool show); + Monero::SubaddressRow* entryFromIndex(const QModelIndex &index) const; + int unusedLookahead() const; public slots: diff --git a/src/model/SubaddressProxyModel.cpp b/src/model/SubaddressProxyModel.cpp index 66705cc..a984e39 100644 --- a/src/model/SubaddressProxyModel.cpp +++ b/src/model/SubaddressProxyModel.cpp @@ -29,6 +29,10 @@ bool SubaddressProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &so if (sourceRow == 0 && m_hidePrimary) return false; + if (!m_showHidden && m_hiddenAddresses.contains(address)) { + return false; + } + if (!m_searchRegExp.isEmpty()) { return address.contains(m_searchCaseSensitiveRegExp) || label.contains(m_searchRegExp); } diff --git a/src/model/SubaddressProxyModel.h b/src/model/SubaddressProxyModel.h index 7a51335..9fbc401 100644 --- a/src/model/SubaddressProxyModel.h +++ b/src/model/SubaddressProxyModel.h @@ -22,16 +22,30 @@ public slots: m_searchCaseSensitiveRegExp.setPattern(searchString); invalidateFilter(); } + void setShowUsed(const bool showUsed){ m_showUsed = showUsed; invalidateFilter(); } + + void setShowHidden(const bool showHidden){ + m_showHidden = showHidden; + invalidateFilter(); + } + + void setHiddenAddresses(const QStringList& hiddenAddresses) { + m_hiddenAddresses = hiddenAddresses; + invalidateFilter(); + } + private: Subaddress *m_subaddress; + QStringList m_hiddenAddresses; QRegExp m_searchRegExp; QRegExp m_searchCaseSensitiveRegExp; bool m_showUsed = false; + bool m_showHidden = false; bool m_hidePrimary; }; diff --git a/src/model/TransactionHistoryModel.cpp b/src/model/TransactionHistoryModel.cpp index 1d9aa6e..8f699c4 100644 --- a/src/model/TransactionHistoryModel.cpp +++ b/src/model/TransactionHistoryModel.cpp @@ -141,7 +141,10 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI switch (column) { case Column::Date: - return tInfo.timestamp().toString("yyyy-MM-dd HH:mm "); + { + return tInfo.timestamp().toString(QString("%1 %2 ").arg(config()->get(Config::dateFormat).toString(), + config()->get(Config::timeFormat).toString())); + } case Column::Description: return tInfo.description(); case Column::Amount: diff --git a/src/receivewidget.cpp b/src/receivewidget.cpp index 748fa58..23078a1 100644 --- a/src/receivewidget.cpp +++ b/src/receivewidget.cpp @@ -35,13 +35,19 @@ ReceiveWidget::ReceiveWidget(QWidget *parent) : connect(ui->qrCode, &ClickableLabel::clicked, this, &ReceiveWidget::showQrCodeDialog); connect(ui->label_addressSearch, &QLineEdit::textChanged, this, &ReceiveWidget::setSearchFilter); + + connect(ui->check_showUsed, &QCheckBox::clicked, this, &ReceiveWidget::setShowUsedAddresses); + connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses); } -void ReceiveWidget::setModel(SubaddressModel * model, Subaddress * subaddress) { - m_subaddress = subaddress; +void ReceiveWidget::setModel(SubaddressModel * model, Wallet * wallet) { + m_wallet = wallet; + m_subaddress = wallet->subaddress(); m_model = model; - m_proxyModel = new SubaddressProxyModel(this, subaddress); + m_proxyModel = new SubaddressProxyModel(this, m_subaddress); m_proxyModel->setSourceModel(m_model); + m_proxyModel->setHiddenAddresses(this->getHiddenAddresses()); + ui->addresses->setModel(m_proxyModel); ui->addresses->setColumnHidden(SubaddressModel::isUsed, true); @@ -74,13 +80,13 @@ void ReceiveWidget::editLabel() { } void ReceiveWidget::showContextMenu(const QPoint &point) { - QModelIndex index = ui->addresses->indexAt(point); - if (!index.isValid()) { - return; - } + Monero::SubaddressRow* row = this->currentEntry(); + if (!row) return; + + QString address = QString::fromStdString(row->getAddress()); + bool isUsed = row->isUsed(); auto *menu = new QMenu(ui->addresses); - bool isUsed = index.model()->data(index.siblingAtColumn(SubaddressModel::isUsed), Qt::UserRole).toBool(); menu->addAction(QIcon(":/assets/images/copy.png"), "Copy address", this, &ReceiveWidget::copyAddress); menu->addAction(QIcon(":/assets/images/copy.png"), "Copy label", this, &ReceiveWidget::copyLabel); @@ -90,6 +96,13 @@ void ReceiveWidget::showContextMenu(const QPoint &point) { menu->addAction(m_showTransactionsAction); } + QStringList hiddenAddresses = this->getHiddenAddresses(); + if (hiddenAddresses.contains(address)) { + menu->addAction("Show address", this, &ReceiveWidget::showAddress); + } else { + menu->addAction("Hide address", this, &ReceiveWidget::hideAddress); + } + menu->popup(ui->addresses->viewport()->mapToGlobal(point)); } @@ -117,6 +130,11 @@ void ReceiveWidget::setShowUsedAddresses(bool show) { m_proxyModel->setShowUsed(show); } +void ReceiveWidget::setShowHiddenAddresses(bool show) { + if (!m_proxyModel) return; + m_proxyModel->setShowHidden(show); +} + void ReceiveWidget::setSearchFilter(const QString &filter) { if (!m_proxyModel) return; m_proxyModel->setSearchFilter(filter); @@ -128,6 +146,24 @@ void ReceiveWidget::showHeaderMenu(const QPoint& position) m_headerMenu->exec(QCursor::pos()); } +void ReceiveWidget::hideAddress() +{ + Monero::SubaddressRow* row = this->currentEntry(); + if (!row) return; + QString address = QString::fromStdString(row->getAddress()); + this->addHiddenAddress(address); + m_proxyModel->setHiddenAddresses(this->getHiddenAddresses()); +} + +void ReceiveWidget::showAddress() +{ + Monero::SubaddressRow* row = this->currentEntry(); + if (!row) return; + QString address = QString::fromStdString(row->getAddress()); + this->removeHiddenAddress(address); + m_proxyModel->setHiddenAddresses(this->getHiddenAddresses()); +} + void ReceiveWidget::updateQrCode(){ QModelIndex index = ui->addresses->currentIndex(); if (!index.isValid()) { @@ -156,6 +192,36 @@ void ReceiveWidget::showQrCodeDialog() { dialog->deleteLater(); } +QStringList ReceiveWidget::getHiddenAddresses() { + QString data = m_wallet->getCacheAttribute("feather.hiddenaddresses"); + return data.split(","); +} + +void ReceiveWidget::addHiddenAddress(const QString& address) { + QStringList hiddenAddresses = this->getHiddenAddresses(); + if (!hiddenAddresses.contains(address)) { + hiddenAddresses.append(address); + } + QString data = hiddenAddresses.join(","); + m_wallet->setCacheAttribute("feather.hiddenaddresses", data); +} + +void ReceiveWidget::removeHiddenAddress(const QString &address) { + QStringList hiddenAddresses = this->getHiddenAddresses(); + hiddenAddresses.removeAll(address); + QString data = hiddenAddresses.join(","); + m_wallet->setCacheAttribute("feather.hiddenaddresses", data); +} + +Monero::SubaddressRow* ReceiveWidget::currentEntry() { + QModelIndexList list = ui->addresses->selectionModel()->selectedRows(); + if (list.size() == 1) { + return m_model->entryFromIndex(m_proxyModel->mapToSource(list.first())); + } else { + return nullptr; + } +} + ReceiveWidget::~ReceiveWidget() { delete ui; } diff --git a/src/receivewidget.h b/src/receivewidget.h index 035eb2c..a522caa 100644 --- a/src/receivewidget.h +++ b/src/receivewidget.h @@ -23,7 +23,7 @@ Q_OBJECT public: explicit ReceiveWidget(QWidget *parent = nullptr); - void setModel(SubaddressModel * model, Subaddress * subaddress); + void setModel(SubaddressModel * model, Wallet * wallet); ~ReceiveWidget() override; @@ -34,6 +34,7 @@ public slots: void showContextMenu(const QPoint& point); void setShowFullAddresses(bool show); void setShowUsedAddresses(bool show); + void setShowHiddenAddresses(bool show); void setSearchFilter(const QString &filter); void onShowTransactions(); void resetModel(); @@ -44,6 +45,8 @@ signals: private slots: void showHeaderMenu(const QPoint& position); + void hideAddress(); + void showAddress(); private: Ui::ReceiveWidget *ui; @@ -54,9 +57,14 @@ private: Subaddress * m_subaddress; SubaddressModel * m_model; SubaddressProxyModel * m_proxyModel; + Wallet * m_wallet; void updateQrCode(); void showQrCodeDialog(); + QStringList getHiddenAddresses(); + void addHiddenAddress(const QString& address); + void removeHiddenAddress(const QString& address); + Monero::SubaddressRow* currentEntry(); }; #endif //FEATHER_RECEIVEWIDGET_H diff --git a/src/receivewidget.ui b/src/receivewidget.ui index eaa3b37..52c8e74 100644 --- a/src/receivewidget.ui +++ b/src/receivewidget.ui @@ -82,6 +82,27 @@ + + + + 0 + + + + + Show used + + + + + + + Show hidden + + + + + diff --git a/src/sendwidget.ui b/src/sendwidget.ui index b5b3810..17de2ad 100644 --- a/src/sendwidget.ui +++ b/src/sendwidget.ui @@ -46,7 +46,14 @@ - + + + Qt::ScrollBarAlwaysOff + + + QPlainTextEdit::NoWrap + + diff --git a/src/settings.cpp b/src/settings.cpp index 4ab33a1..295f2f2 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -48,10 +48,29 @@ Settings::Settings(QWidget *parent) : } ui->comboBox_amountPrecision->setCurrentIndex(config()->get(Config::amountPrecision).toInt()); + // Date format combobox + QDateTime now = QDateTime::currentDateTime(); + for (const auto & format : m_dateFormats) { + ui->comboBox_dateFormat->addItem(now.toString(format)); + } + QString dateFormatSetting = config()->get(Config::dateFormat).toString(); + if (m_dateFormats.contains(dateFormatSetting)) + ui->comboBox_dateFormat->setCurrentIndex(m_dateFormats.indexOf(dateFormatSetting)); + + // Time format combobox + for (const auto & format : m_timeFormats) { + ui->comboBox_timeFormat->addItem(now.toString(format)); + } + QString timeFormatSetting = config()->get(Config::timeFormat).toString(); + if (m_timeFormats.contains(timeFormatSetting)) + ui->comboBox_timeFormat->setCurrentIndex(m_timeFormats.indexOf(timeFormatSetting)); + connect(ui->comboBox_skin, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_skinChanged); connect(ui->comboBox_blockExplorer, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_blockExplorerChanged); connect(ui->comboBox_redditFrontend, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_redditFrontendChanged); connect(ui->comboBox_amountPrecision, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_amountPrecisionChanged); + connect(ui->comboBox_dateFormat, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_dateFormatChanged); + connect(ui->comboBox_timeFormat, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_timeFormatChanged); // setup preferred fiat currency combobox QStringList fiatCurrencies; @@ -110,6 +129,14 @@ void Settings::comboBox_amountPrecisionChanged(int pos) { emit amountPrecisionChanged(pos); } +void Settings::comboBox_dateFormatChanged(int pos) { + config()->set(Config::dateFormat, m_dateFormats.at(pos)); +} + +void Settings::comboBox_timeFormatChanged(int pos) { + config()->set(Config::timeFormat, m_timeFormats.at(pos)); +} + void Settings::copyToClipboard() { ui->textLogs->copy(); } diff --git a/src/settings.h b/src/settings.h index cf4465c..437c680 100644 --- a/src/settings.h +++ b/src/settings.h @@ -40,15 +40,18 @@ public slots: void comboBox_blockExplorerChanged(int pos); void comboBox_redditFrontendChanged(int pos); void comboBox_amountPrecisionChanged(int pos); - -private: - QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"}; + void comboBox_dateFormatChanged(int pos); + void comboBox_timeFormatChanged(int pos); private: void setupSkinCombobox(); AppContext *m_ctx; Ui::Settings *ui; + + QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"}; + QStringList m_dateFormats{"yyyy-MM-dd", "MM-dd-yyyy", "dd-MM-yyyy"}; + QStringList m_timeFormats{"hh:mm", "hh:mm ap"}; }; #endif // SETTINGS_H diff --git a/src/settings.ui b/src/settings.ui index 8a24ffb..46b1311 100644 --- a/src/settings.ui +++ b/src/settings.ui @@ -161,14 +161,14 @@ - + Warn before opening external link - + Hide balance @@ -211,6 +211,26 @@ + + + + Date format: + + + + + + + + + + Time format: + + + + + + diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 10efcdd..6bd659e 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -48,7 +48,9 @@ static const QHash configStrings = { {Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}}, {Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}}, {Config::GUI_HistoryViewState, {QS("GUI_HistoryViewState"), {}}}, - {Config::amountPrecision, {QS("amountPrecision"), 4}} + {Config::amountPrecision, {QS("amountPrecision"), 4}}, + {Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}}, + {Config::timeFormat, {QS("timeFormat"), "HH:mm"}} }; diff --git a/src/utils/config.h b/src/utils/config.h index 7effce1..6398d8f 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -52,7 +52,9 @@ public: showHistorySyncNotice, GUI_HistoryViewState, amountPrecision, - portableMode + portableMode, + dateFormat, + timeFormat }; ~Config() override; diff --git a/src/wizard/PageMenu.ui b/src/wizard/PageMenu.ui index 92e8117..65f4f37 100644 --- a/src/wizard/PageMenu.ui +++ b/src/wizard/PageMenu.ui @@ -82,6 +82,9 @@ + + Qt::NoFocus + Dark mode diff --git a/src/wizard/PageNetwork.h b/src/wizard/PageNetwork.h index a180dd5..f0a9158 100644 --- a/src/wizard/PageNetwork.h +++ b/src/wizard/PageNetwork.h @@ -26,7 +26,6 @@ public: private: AppContext *m_ctx; - QLabel *topLabel; Ui::PageNetwork *ui; }; diff --git a/src/wizard/PageWalletRestoreKeys.h b/src/wizard/PageWalletRestoreKeys.h index 2122ca8..ff20301 100644 --- a/src/wizard/PageWalletRestoreKeys.h +++ b/src/wizard/PageWalletRestoreKeys.h @@ -27,8 +27,6 @@ public: int nextId() const override; private: - void resetWidgets(); - AppContext *m_ctx; WizardFields *m_fields; Ui::PageWalletRestoreKeys *ui; diff --git a/src/wizard/PageWalletRestoreSeed.cpp b/src/wizard/PageWalletRestoreSeed.cpp index 75938be..6f58478 100644 --- a/src/wizard/PageWalletRestoreSeed.cpp +++ b/src/wizard/PageWalletRestoreSeed.cpp @@ -5,7 +5,6 @@ #include "PageWalletRestoreSeed.h" #include "ui_PageWalletRestoreSeed.h" -#include #include #include