mirror of
https://github.com/feather-wallet/feather.git
synced 2024-12-23 03:59:29 +00:00
Merge pull request 'Multibroadcast transactions' (#345) from tobtoht/feather:wizard_redesign into master
Reviewed-on: https://git.featherwallet.org/feather/feather/pulls/345
This commit is contained in:
commit
a73d12a14f
34 changed files with 814 additions and 566 deletions
|
@ -29,7 +29,7 @@ if(DEBUG)
|
|||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
endif()
|
||||
|
||||
set(MONERO_HEAD "52acbb68c1a4cc67ee539325a8febc2c144596c4")
|
||||
set(MONERO_HEAD "41327974116dedccc2f9709d8ad3a8a1f591faed")
|
||||
set(BUILD_GUI_DEPS ON)
|
||||
set(ARCH "x86-64")
|
||||
set(BUILD_64 ON)
|
||||
|
|
|
@ -42,9 +42,9 @@ 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.6 --depth 1 https://git.torproject.org/tor.git && \
|
||||
RUN git clone -b tor-0.4.5.7 --depth 1 https://git.torproject.org/tor.git && \
|
||||
cd tor && \
|
||||
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
||||
git reset --hard 83f895c015de55201e5f226f84a866f30f5ee14b && \
|
||||
./autogen.sh && \
|
||||
./configure \
|
||||
--disable-asciidoc \
|
||||
|
|
|
@ -146,9 +146,9 @@ RUN wget https://github.com/libevent/libevent/releases/download/release-2.1.11-s
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
RUN git clone -b tor-0.4.5.6 --depth 1 https://git.torproject.org/tor.git && \
|
||||
RUN git clone -b tor-0.4.5.7 --depth 1 https://git.torproject.org/tor.git && \
|
||||
cd tor && \
|
||||
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
||||
git reset --hard 83f895c015de55201e5f226f84a866f30f5ee14b && \
|
||||
./autogen.sh && \
|
||||
./configure --host=x86_64-w64-mingw32 \
|
||||
--disable-asciidoc \
|
||||
|
|
2
monero
2
monero
|
@ -1 +1 @@
|
|||
Subproject commit 52acbb68c1a4cc67ee539325a8febc2c144596c4
|
||||
Subproject commit 41327974116dedccc2f9709d8ad3a8a1f591faed
|
|
@ -265,6 +265,35 @@ void AppContext::onAmountPrecisionChanged(int precision) {
|
|||
model->amountPrecision = precision;
|
||||
}
|
||||
|
||||
void AppContext::commitTransaction(PendingTransaction *tx) {
|
||||
// Nodes - even well-connected, properly configured ones - consistently fail to relay transactions
|
||||
// To mitigate transactions failing we just send the transaction to every node we know about over Tor
|
||||
if (config()->get(Config::multiBroadcast).toBool()) {
|
||||
this->onMultiBroadcast(tx);
|
||||
}
|
||||
|
||||
this->currentWallet->commitTransactionAsync(tx);
|
||||
}
|
||||
|
||||
void AppContext::onMultiBroadcast(PendingTransaction *tx) {
|
||||
UtilsNetworking *net = new UtilsNetworking(this->network, this);
|
||||
DaemonRpc *rpc = new DaemonRpc(this, net, "");
|
||||
|
||||
int count = tx->txCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
QString txData = tx->signedTxToHex(i);
|
||||
|
||||
for (const auto& node: this->nodes->websocketNodes()) {
|
||||
if (!node.online) continue;
|
||||
|
||||
QString address = node.as_url();
|
||||
qDebug() << QString("Relaying %1 to: %2").arg(tx->txid()[i], address);
|
||||
rpc->setDaemonAddress(address);
|
||||
rpc->sendRawTransaction(txData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppContext::onWalletOpened(Wallet *wallet) {
|
||||
auto state = wallet->status();
|
||||
if (state != Wallet::Status_Ok) {
|
||||
|
@ -334,35 +363,13 @@ void AppContext::setWindowTitle(bool mining) {
|
|||
void AppContext::onWSMessage(const QJsonObject &msg) {
|
||||
QString cmd = msg.value("cmd").toString();
|
||||
|
||||
if(cmd == "blockheights") {
|
||||
auto heights = msg.value("data").toObject();
|
||||
auto mainnet = heights.value("mainnet").toInt();
|
||||
auto stagenet = heights.value("stagenet").toInt();
|
||||
auto changed = false;
|
||||
if (cmd == "blockheights") {
|
||||
QJsonObject data = msg.value("data").toObject();
|
||||
int mainnet = data.value("mainnet").toInt();
|
||||
int stagenet = data.value("stagenet").toInt();
|
||||
|
||||
if(!this->heights.contains("mainnet")) {
|
||||
this->heights["mainnet"] = mainnet;
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
if (mainnet > this->heights["mainnet"]) {
|
||||
this->heights["mainnet"] = mainnet;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if(!this->heights.contains("stagenet")) {
|
||||
this->heights["stagenet"] = stagenet;
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
if (stagenet > this->heights["stagenet"]) {
|
||||
this->heights["stagenet"] = stagenet;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(changed)
|
||||
emit blockHeightWSUpdated(this->heights);
|
||||
this->heights[NetworkType::MAINNET] = mainnet;
|
||||
this->heights[NetworkType::STAGENET] = stagenet;
|
||||
}
|
||||
|
||||
else if(cmd == "nodes") {
|
||||
|
@ -478,15 +485,16 @@ void AppContext::onWSCCS(const QJsonArray &ccs_data) {
|
|||
}
|
||||
|
||||
void AppContext::createConfigDirectory(const QString &dir) {
|
||||
QString config_dir_tor = QString("%1%2").arg(dir).arg("tor");
|
||||
QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data");
|
||||
QString config_dir_tor = QString("%1/%2").arg(dir).arg("tor");
|
||||
QString config_dir_tordata = QString("%1/%2").arg(dir).arg("tor/data");
|
||||
|
||||
QStringList createDirs({dir, config_dir_tor, config_dir_tordata});
|
||||
for(const auto &d: createDirs) {
|
||||
if(!Utils::dirExists(d)) {
|
||||
qDebug() << QString("Creating directory: %1").arg(d);
|
||||
if (!QDir().mkpath(d))
|
||||
throw std::runtime_error("Could not create directory " + d.toStdString());
|
||||
if (!QDir().mkpath(d)) {
|
||||
qCritical() << "Could not create directory " << d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -690,14 +698,14 @@ void AppContext::onWalletRefreshed(bool success) {
|
|||
}
|
||||
|
||||
qDebug() << "Wallet refresh status: " << success;
|
||||
|
||||
this->currentWallet->refreshHeightAsync();
|
||||
}
|
||||
|
||||
void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) {
|
||||
// Called whenever a new block gets scanned by the wallet
|
||||
this->syncStatusUpdated(blockheight, targetHeight);
|
||||
|
||||
if (this->currentWallet->synchronized()) {
|
||||
if (!this->currentWallet) return;
|
||||
if (this->currentWallet->isSynchronized()) {
|
||||
this->currentWallet->coins()->refreshUnlocked();
|
||||
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
|
||||
// Todo: only refresh tx confirmations
|
||||
|
@ -759,7 +767,7 @@ void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, con
|
|||
|
||||
void AppContext::storeWallet() {
|
||||
// Do not store a synchronizing wallet: store() is NOT thread safe and may crash the wallet
|
||||
if (this->currentWallet == nullptr || !this->currentWallet->synchronized())
|
||||
if (this->currentWallet == nullptr || !this->currentWallet->isSynchronized())
|
||||
return;
|
||||
|
||||
qDebug() << "Storing wallet";
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "utils/wsclient.h"
|
||||
#include "utils/txfiathistory.h"
|
||||
#include "utils/FeatherSeed.h"
|
||||
#include "utils/daemonrpc.h"
|
||||
#include "widgets/RedditPost.h"
|
||||
#include "widgets/CCSEntry.h"
|
||||
#include "utils/RestoreHeightLookup.h"
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
QString walletPassword = "";
|
||||
NetworkType::Type networkType;
|
||||
|
||||
QMap<QString, int> heights;
|
||||
QMap<NetworkType::Type, int> heights;
|
||||
QMap<NetworkType::Type, RestoreHeightLookup*> restoreHeights;
|
||||
PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
|
||||
QString seedLanguage = "English"; // 14 word `monero-seed` only has English
|
||||
|
@ -66,6 +67,7 @@ public:
|
|||
WSClient *ws;
|
||||
XmRig *XMRig;
|
||||
Nodes *nodes;
|
||||
DaemonRpc *daemonRpc;
|
||||
static Prices *prices;
|
||||
static WalletKeysFilesModel *wallets;
|
||||
static double balance;
|
||||
|
@ -81,6 +83,7 @@ public:
|
|||
void createWallet(FeatherSeed seed, const QString &path, const QString &password, const QString &seedOffset = "");
|
||||
void createWalletFromKeys(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight, bool deterministic = false);
|
||||
void createWalletFinish(const QString &password);
|
||||
void commitTransaction(PendingTransaction *tx);
|
||||
void syncStatusUpdated(quint64 height, quint64 target);
|
||||
void updateBalance();
|
||||
void initTor();
|
||||
|
@ -105,6 +108,7 @@ public slots:
|
|||
void onSetRestoreHeight(quint64 height);
|
||||
void onPreferredFiatCurrencyChanged(const QString &symbol);
|
||||
void onAmountPrecisionChanged(int precision);
|
||||
void onMultiBroadcast(PendingTransaction *tx);
|
||||
|
||||
private slots:
|
||||
void onWSNodes(const QJsonArray &nodes);
|
||||
|
@ -134,7 +138,6 @@ signals:
|
|||
void blockchainSync(int height, int target);
|
||||
void refreshSync(int height, int target);
|
||||
void synchronized();
|
||||
void blockHeightWSUpdated(QMap<QString, int> heights);
|
||||
void walletRefreshed();
|
||||
void walletOpened();
|
||||
void walletCreatedError(const QString &msg);
|
||||
|
|
|
@ -1455,3 +1455,58 @@
|
|||
1599426969:2181000
|
||||
1599604157:2182500
|
||||
1599786817:2184000
|
||||
1599969318:2185500
|
||||
1600147688:2187000
|
||||
1600327569:2188500
|
||||
1600510218:2190000
|
||||
1600688674:2191500
|
||||
1600867919:2193000
|
||||
1601047108:2194500
|
||||
1601226981:2196000
|
||||
1601404059:2197500
|
||||
1601584064:2199000
|
||||
1601762823:2200500
|
||||
1601946046:2202000
|
||||
1602123016:2203500
|
||||
1602302020:2205000
|
||||
1602480047:2206500
|
||||
1602640101:2208000
|
||||
1602834791:2209500
|
||||
1603025260:2211000
|
||||
1603202279:2212500
|
||||
1603383969:2214000
|
||||
1603566322:2215500
|
||||
1603746737:2217000
|
||||
1603927129:2218500
|
||||
1604112554:2220000
|
||||
1604289877:2221500
|
||||
1604474365:2223000
|
||||
1604653260:2224500
|
||||
1604830135:2226000
|
||||
1605007197:2227500
|
||||
1605185169:2229000
|
||||
1605372544:2230500
|
||||
1605551973:2232000
|
||||
1605734501:2233500
|
||||
1605910469:2235000
|
||||
1606091151:2236500
|
||||
1606276021:2238000
|
||||
1606452893:2239500
|
||||
1606627629:2241000
|
||||
1606811187:2242500
|
||||
1606991795:2244000
|
||||
1607172363:2245500
|
||||
1607353315:2247000
|
||||
1607530844:2248500
|
||||
1607716100:2250000
|
||||
1607890493:2251500
|
||||
1608067069:2253000
|
||||
1608249924:2254500
|
||||
1608429171:2256000
|
||||
1608613290:2257500
|
||||
1608791286:2259000
|
||||
1608972563:2260500
|
||||
1609151786:2262000
|
||||
1609331787:2263500
|
||||
1609513572:2265000
|
||||
1609692129:2266500
|
|
@ -442,3 +442,90 @@
|
|||
1599636188:661500
|
||||
1599809533:663000
|
||||
1600001474:664500
|
||||
1600168506:666000
|
||||
1600360911:667500
|
||||
1600585502:669000
|
||||
1600723074:670500
|
||||
1600989712:672000
|
||||
1601126870:673500
|
||||
1601342006:675000
|
||||
1601531952:676500
|
||||
1601712860:678000
|
||||
1601888075:679500
|
||||
1602072633:681000
|
||||
1602210804:682500
|
||||
1602390469:684000
|
||||
1602588519:685500
|
||||
1602759479:687000
|
||||
1602934491:688500
|
||||
1603134321:690000
|
||||
1603296351:691500
|
||||
1603486625:693000
|
||||
1603689061:694500
|
||||
1603841411:696000
|
||||
1604017061:697500
|
||||
1604195275:699000
|
||||
1604379244:700500
|
||||
1604562487:702000
|
||||
1604737907:703500
|
||||
1604923764:705000
|
||||
1605103115:706500
|
||||
1605286071:708000
|
||||
1605470071:709500
|
||||
1605639278:711000
|
||||
1605823578:712500
|
||||
1606010900:714000
|
||||
1606188630:715500
|
||||
1606366871:717000
|
||||
1606530937:718500
|
||||
1606743518:720000
|
||||
1606899734:721500
|
||||
1607074620:723000
|
||||
1607295957:724500
|
||||
1607480999:726000
|
||||
1607660787:727500
|
||||
1607840859:729000
|
||||
1608022934:730500
|
||||
1608202441:732000
|
||||
1608382317:733500
|
||||
1608563014:735000
|
||||
1608760731:736500
|
||||
1608941535:738000
|
||||
1609125279:739500
|
||||
1609300581:741000
|
||||
1609479221:742500
|
||||
1609663165:744000
|
||||
1609842526:745500
|
||||
1610017591:747000
|
||||
1610178062:748500
|
||||
1610393422:750000
|
||||
1610574236:751500
|
||||
1610755343:753000
|
||||
1610932059:754500
|
||||
1611119735:756000
|
||||
1611303782:757500
|
||||
1611475083:759000
|
||||
1611663782:760500
|
||||
1611847193:762000
|
||||
1611996841:763500
|
||||
1612304524:765000
|
||||
1612476234:766500
|
||||
1612666606:768000
|
||||
1612877927:769500
|
||||
1613072065:771000
|
||||
1613256943:772500
|
||||
1613446398:774000
|
||||
1613622490:775500
|
||||
1613798350:777000
|
||||
1614039651:778500
|
||||
1614217602:780000
|
||||
1614432073:781500
|
||||
1614557574:783000
|
||||
1614817212:784500
|
||||
1615014204:786000
|
||||
1615200863:787500
|
||||
1615390786:789000
|
||||
1615573554:790500
|
||||
1615731420:792000
|
||||
1615933315:793500
|
||||
1616104918:795000
|
|
@ -47,7 +47,7 @@ void DebugInfoDialog::updateInfo() {
|
|||
ui->label_daemonHeight->setText(QString::number(m_ctx->currentWallet->daemonBlockChainHeight()));
|
||||
ui->label_targetHeight->setText(QString::number(m_ctx->currentWallet->daemonBlockChainTargetHeight()));
|
||||
ui->label_restoreHeight->setText(QString::number(m_ctx->currentWallet->getWalletCreationHeight()));
|
||||
ui->label_synchronized->setText(m_ctx->currentWallet->synchronized() ? "True" : "False");
|
||||
ui->label_synchronized->setText(m_ctx->currentWallet->isSynchronized() ? "True" : "False");
|
||||
|
||||
auto node = m_ctx->nodes->connection();
|
||||
ui->label_remoteNode->setText(node.full);
|
||||
|
@ -75,12 +75,14 @@ QString DebugInfoDialog::statusToString(Wallet::ConnectionStatus status) {
|
|||
switch (status) {
|
||||
case Wallet::ConnectionStatus_Disconnected:
|
||||
return "Disconnected";
|
||||
case Wallet::ConnectionStatus_Connected:
|
||||
return "Connected";
|
||||
case Wallet::ConnectionStatus_WrongVersion:
|
||||
return "Daemon wrong version";
|
||||
case Wallet::ConnectionStatus_Connecting:
|
||||
return "Connecting";
|
||||
case Wallet::ConnectionStatus_Synchronizing:
|
||||
return "Synchronizing";
|
||||
case Wallet::ConnectionStatus_Synchronized:
|
||||
return "Synchronized";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ void TxConfAdvDialog::signedQrCode() {
|
|||
|
||||
void TxConfAdvDialog::broadcastTransaction() {
|
||||
if (m_tx == nullptr) return;
|
||||
m_ctx->currentWallet->commitTransactionAsync(m_tx);
|
||||
m_ctx->commitTransaction(m_tx);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,11 @@ void HistoryWidget::setModel(TransactionHistoryProxyModel *model, Wallet *wallet
|
|||
m_wallet->transactionHistoryModel()->amountPrecision = config()->get(Config::amountPrecision).toInt();
|
||||
|
||||
// Load view state
|
||||
ui->history->setViewState(QByteArray::fromBase64(config()->get(Config::GUI_HistoryViewState).toByteArray()));
|
||||
QByteArray historyViewState = QByteArray::fromBase64(config()->get(Config::GUI_HistoryViewState).toByteArray());
|
||||
|
||||
if (!historyViewState.isEmpty()) {
|
||||
ui->history->setViewState(historyViewState);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::resetModel()
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
#include "utils/ScopeGuard.h"
|
||||
|
||||
namespace {
|
||||
static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5;
|
||||
static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 30;
|
||||
static const int WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS = 5;
|
||||
|
||||
static constexpr char ATTRIBUTE_SUBADDRESS_ACCOUNT[] = "feather.subaddress_account";
|
||||
}
|
||||
|
||||
|
@ -78,10 +74,6 @@ void Wallet::refreshingSet(bool value)
|
|||
}
|
||||
}
|
||||
|
||||
void Wallet::setConnectionTimeout(int timeout) {
|
||||
m_connectionTimeout = timeout;
|
||||
}
|
||||
|
||||
void Wallet::setConnectionStatus(ConnectionStatus value)
|
||||
{
|
||||
if (m_connectionStatus == value)
|
||||
|
@ -102,6 +94,17 @@ void Wallet::setConnectionStatus(ConnectionStatus value)
|
|||
}
|
||||
}
|
||||
|
||||
void Wallet::onNewBlock(uint64_t walletHeight) {
|
||||
// Called whenever a new block gets scanned by the wallet
|
||||
quint64 daemonHeight = m_daemonBlockChainTargetHeight;
|
||||
|
||||
if (walletHeight < (daemonHeight - 1)) {
|
||||
setConnectionStatus(ConnectionStatus_Synchronizing);
|
||||
} else {
|
||||
setConnectionStatus(ConnectionStatus_Synchronized);
|
||||
}
|
||||
}
|
||||
|
||||
QString Wallet::getProxyAddress() const
|
||||
{
|
||||
QMutexLocker locker(&m_proxyMutex);
|
||||
|
@ -127,9 +130,21 @@ void Wallet::setProxyAddress(QString address)
|
|||
|
||||
bool Wallet::synchronized() const
|
||||
{
|
||||
// Misleading: this will return true if wallet has synchronized at least once even if it isn't currently synchronized
|
||||
return m_walletImpl->synchronized();
|
||||
}
|
||||
|
||||
bool Wallet::isSynchronized() const
|
||||
{
|
||||
return connectionStatus() == ConnectionStatus_Synchronized;
|
||||
}
|
||||
|
||||
bool Wallet::isConnected() const
|
||||
{
|
||||
auto status = connectionStatus();
|
||||
return status == ConnectionStatus_Synchronizing || status == ConnectionStatus_Synchronized;
|
||||
}
|
||||
|
||||
QString Wallet::errorString() const
|
||||
{
|
||||
return QString::fromStdString(m_walletImpl->errorString());
|
||||
|
@ -211,7 +226,6 @@ bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 uppe
|
|||
}
|
||||
emit proxyAddressChanged();
|
||||
|
||||
setTrustedDaemon(trustedDaemon);
|
||||
setTrustedDaemon(trustedDaemon);
|
||||
return true;
|
||||
}
|
||||
|
@ -239,7 +253,6 @@ void Wallet::initAsync(
|
|||
{
|
||||
emit walletCreationHeightChanged();
|
||||
qDebug() << "init async finished - starting refresh";
|
||||
refreshHeightAsync();
|
||||
startRefresh();
|
||||
}
|
||||
});
|
||||
|
@ -249,6 +262,12 @@ void Wallet::initAsync(
|
|||
}
|
||||
}
|
||||
|
||||
bool Wallet::setDaemon(const QString &daemonAddress)
|
||||
{
|
||||
qDebug() << "setDaemon: " + daemonAddress;
|
||||
return m_walletImpl->setDaemon(daemonAddress.toStdString(), m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), m_useSSL);
|
||||
}
|
||||
|
||||
bool Wallet::isHwBacked() const
|
||||
{
|
||||
return m_walletImpl->getDeviceType() != Monero::Wallet::Device_Software;
|
||||
|
@ -380,37 +399,53 @@ void Wallet::deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex,
|
|||
});
|
||||
}
|
||||
|
||||
void Wallet::refreshHeightAsync()
|
||||
bool Wallet::refreshHeights()
|
||||
{
|
||||
m_scheduler.run([this] {
|
||||
quint64 daemonHeight;
|
||||
QPair<bool, QFuture<void>> daemonHeightFuture = m_scheduler.run([this, &daemonHeight] {
|
||||
daemonHeight = daemonBlockChainHeight();
|
||||
});
|
||||
if (!daemonHeightFuture.first)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// daemonHeight and targetHeight will be 0 if call to get_info fails
|
||||
|
||||
quint64 targetHeight;
|
||||
quint64 daemonHeight;
|
||||
QPair<bool, QFuture<void>> daemonHeightFuture = m_scheduler.run([this, &daemonHeight] {
|
||||
daemonHeight = m_walletImpl->daemonBlockChainHeight();;
|
||||
});
|
||||
if (!daemonHeightFuture.first)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// We must wait here for get_info to return, otherwise targetHeight will get cache value of 0
|
||||
daemonHeightFuture.second.waitForFinished();
|
||||
bool success = daemonHeight > 0;
|
||||
|
||||
quint64 targetHeight = 0;
|
||||
if (success) {
|
||||
QPair<bool, QFuture<void>> targetHeightFuture = m_scheduler.run([this, &targetHeight] {
|
||||
targetHeight = daemonBlockChainTargetHeight();
|
||||
targetHeight = m_walletImpl->daemonBlockChainTargetHeight();
|
||||
});
|
||||
if (!targetHeightFuture.first)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
quint64 walletHeight = blockChainHeight();
|
||||
daemonHeightFuture.second.waitForFinished();
|
||||
targetHeightFuture.second.waitForFinished();
|
||||
}
|
||||
|
||||
if (daemonHeight > 0 && targetHeight > 0) {
|
||||
emit heightRefreshed(walletHeight, daemonHeight, targetHeight);
|
||||
qDebug() << "Setting connection status from refreshHeightAsync";
|
||||
setConnectionStatus(ConnectionStatus_Connected);
|
||||
m_daemonBlockChainHeight = daemonHeight;
|
||||
m_daemonBlockChainTargetHeight = targetHeight;
|
||||
|
||||
success = (daemonHeight > 0 && targetHeight > 0);
|
||||
|
||||
if (success) {
|
||||
quint64 walletHeight = blockChainHeight();
|
||||
emit heightRefreshed(walletHeight, daemonHeight, targetHeight);
|
||||
|
||||
if (walletHeight < (daemonHeight - 1)) {
|
||||
setConnectionStatus(ConnectionStatus_Synchronizing);
|
||||
} else {
|
||||
setConnectionStatus(ConnectionStatus_Synchronized);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setConnectionStatus(ConnectionStatus_Disconnected);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
quint64 Wallet::blockChainHeight() const
|
||||
|
@ -420,32 +455,13 @@ quint64 Wallet::blockChainHeight() const
|
|||
|
||||
quint64 Wallet::daemonBlockChainHeight() const
|
||||
{
|
||||
// cache daemon blockchain height for some time (60 seconds by default)
|
||||
|
||||
if (m_daemonBlockChainHeight == 0
|
||||
|| m_daemonBlockChainHeightTime.elapsed() / 1000 > m_daemonBlockChainHeightTtl)
|
||||
{
|
||||
m_daemonBlockChainHeight = m_walletImpl->daemonBlockChainHeight();
|
||||
m_daemonBlockChainHeightTime.restart();
|
||||
}
|
||||
// Can not block UI
|
||||
return m_daemonBlockChainHeight;
|
||||
}
|
||||
|
||||
quint64 Wallet::daemonBlockChainTargetHeight() const
|
||||
{
|
||||
if (m_daemonBlockChainTargetHeight <= 1
|
||||
|| m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl)
|
||||
{
|
||||
m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight();
|
||||
|
||||
// Target height is set to 0 if daemon is synced.
|
||||
// Use current height from daemon when target height < current height
|
||||
if (m_daemonBlockChainTargetHeight < m_daemonBlockChainHeight){
|
||||
m_daemonBlockChainTargetHeight = m_daemonBlockChainHeight;
|
||||
}
|
||||
m_daemonBlockChainTargetHeightTime.restart();
|
||||
}
|
||||
|
||||
// Can not block UI
|
||||
return m_daemonBlockChainTargetHeight;
|
||||
}
|
||||
|
||||
|
@ -584,11 +600,15 @@ PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QSt
|
|||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority)
|
||||
{
|
||||
pauseRefresh();
|
||||
|
||||
std::set<uint32_t> subaddr_indices;
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
|
||||
dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count,
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl,0);
|
||||
|
||||
startRefresh();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -606,6 +626,8 @@ void Wallet::createTransactionAsync(const QString &dst_addr, const QString &paym
|
|||
PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
PendingTransaction::Priority priority)
|
||||
{
|
||||
pauseRefresh();
|
||||
|
||||
std::vector<std::string> dests;
|
||||
for (auto &addr : dst_addr) {
|
||||
dests.push_back(addr.toStdString());
|
||||
|
@ -619,6 +641,8 @@ PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &d
|
|||
// TODO: remove mixin count
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionMultDest(dests, "", amounts, 11, static_cast<Monero::PendingTransaction::Priority>(priority));
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl);
|
||||
|
||||
startRefresh();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -638,11 +662,15 @@ void Wallet::createTransactionMultiDestAsync(const QVector<QString> &dst_addr, c
|
|||
PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const QString &payment_id,
|
||||
quint32 mixin_count, PendingTransaction::Priority priority)
|
||||
{
|
||||
pauseRefresh();
|
||||
|
||||
std::set<uint32_t> subaddr_indices;
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
|
||||
dst_addr.toStdString(), payment_id.toStdString(), Monero::optional<uint64_t>(), mixin_count,
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl, this);
|
||||
|
||||
startRefresh();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -660,9 +688,13 @@ void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &p
|
|||
PendingTransaction *Wallet::createTransactionSingle(const QString &key_image, const QString &dst_addr, const size_t outputs,
|
||||
PendingTransaction::Priority priority)
|
||||
{
|
||||
pauseRefresh();
|
||||
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionSingle(key_image.toStdString(), dst_addr.toStdString(),
|
||||
outputs, static_cast<Monero::PendingTransaction::Priority>(priority));
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl, this);
|
||||
|
||||
startRefresh();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -678,8 +710,12 @@ void Wallet::createTransactionSingleAsync(const QString &key_image, const QStrin
|
|||
|
||||
PendingTransaction *Wallet::createSweepUnmixableTransaction()
|
||||
{
|
||||
pauseRefresh();
|
||||
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createSweepUnmixableTransaction();
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl, this);
|
||||
|
||||
startRefresh();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -870,16 +906,6 @@ QString Wallet::integratedAddress(const QString &paymentId) const
|
|||
return QString::fromStdString(m_walletImpl->integratedAddress(paymentId.toStdString()));
|
||||
}
|
||||
|
||||
QString Wallet::paymentId() const
|
||||
{
|
||||
return m_paymentId;
|
||||
}
|
||||
|
||||
void Wallet::setPaymentId(const QString &paymentId)
|
||||
{
|
||||
m_paymentId = paymentId;
|
||||
}
|
||||
|
||||
QString Wallet::getCacheAttribute(const QString &key) const {
|
||||
return QString::fromStdString(m_walletImpl->getCacheAttribute(key.toStdString()));
|
||||
}
|
||||
|
@ -1221,11 +1247,8 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
|||
, m_addressBook(nullptr)
|
||||
, m_addressBookModel(nullptr)
|
||||
, m_daemonBlockChainHeight(0)
|
||||
, m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS)
|
||||
, m_daemonBlockChainTargetHeight(0)
|
||||
, m_daemonBlockChainTargetHeightTtl(DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS)
|
||||
, m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
|
||||
, m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS)
|
||||
, m_disconnected(true)
|
||||
, m_currentSubaddressAccount(0)
|
||||
, m_subaddress(nullptr)
|
||||
|
@ -1248,11 +1271,7 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
|||
m_walletImpl->setListener(m_walletListener);
|
||||
m_currentSubaddressAccount = getCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT).toUInt();
|
||||
// start cache timers
|
||||
m_connectionStatusTime.start();
|
||||
m_daemonBlockChainHeightTime.start();
|
||||
m_daemonBlockChainTargetHeightTime.start();
|
||||
m_initialized = false;
|
||||
m_connectionStatusRunning = false;
|
||||
m_daemonUsername = "";
|
||||
m_daemonPassword = "";
|
||||
|
||||
|
@ -1286,11 +1305,10 @@ Wallet::~Wallet()
|
|||
//Monero::WalletManagerFactory::getWalletManager()->closeWallet(m_walletImpl);
|
||||
if(status() == Status_Critical)
|
||||
qDebug("Not storing wallet cache");
|
||||
// Don't store on wallet close for now
|
||||
// else if( m_walletImpl->store(""))
|
||||
// qDebug("Wallet cache stored successfully");
|
||||
// else
|
||||
// qDebug("Error storing wallet cache");
|
||||
else if( m_walletImpl->store(""))
|
||||
qDebug("Wallet cache stored successfully");
|
||||
else
|
||||
qDebug("Error storing wallet cache");
|
||||
delete m_walletImpl;
|
||||
m_walletImpl = NULL;
|
||||
delete m_walletListener;
|
||||
|
@ -1314,7 +1332,12 @@ void Wallet::startRefreshThread()
|
|||
if (elapsed >= refreshInterval || m_refreshNow)
|
||||
{
|
||||
m_refreshNow = false;
|
||||
refresh(false);
|
||||
// Don't call refresh function if we don't have the daemon and target height
|
||||
// We do this to prevent to UI from getting confused about the amount of blocks that are still remaining
|
||||
bool haveHeights = refreshHeights();
|
||||
if (haveHeights) {
|
||||
refresh(false);
|
||||
}
|
||||
last = std::chrono::steady_clock::now();
|
||||
}
|
||||
}
|
||||
|
@ -1329,9 +1352,7 @@ void Wallet::startRefreshThread()
|
|||
}
|
||||
|
||||
void Wallet::onRefreshed(bool success) {
|
||||
if (success) {
|
||||
setConnectionStatus(ConnectionStatus_Connected);
|
||||
} else {
|
||||
if (!success) {
|
||||
setConnectionStatus(ConnectionStatus_Disconnected);
|
||||
}
|
||||
}
|
|
@ -74,37 +74,9 @@ struct TxProofResult {
|
|||
class Wallet : public QObject, public PassprasePrompter
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool disconnected READ disconnected NOTIFY disconnectedChanged)
|
||||
Q_PROPERTY(bool refreshing READ refreshing NOTIFY refreshingChanged)
|
||||
Q_PROPERTY(QString seedLanguage READ getSeedLanguage)
|
||||
Q_PROPERTY(Status status READ status)
|
||||
Q_PROPERTY(NetworkType::Type nettype READ nettype)
|
||||
Q_PROPERTY(ConnectionStatus connectionStatus READ connectionStatus)
|
||||
Q_PROPERTY(quint32 currentSubaddressAccount READ currentSubaddressAccount NOTIFY currentSubaddressAccountChanged)
|
||||
Q_PROPERTY(bool synchronized READ synchronized)
|
||||
Q_PROPERTY(QString errorString READ errorString)
|
||||
Q_PROPERTY(TransactionHistory * history READ history)
|
||||
Q_PROPERTY(QString paymentId READ paymentId WRITE setPaymentId)
|
||||
Q_PROPERTY(TransactionHistoryProxyModel * historyModel READ historyModel NOTIFY historyModelChanged)
|
||||
Q_PROPERTY(QString path READ path)
|
||||
Q_PROPERTY(AddressBookModel * addressBookModel READ addressBookModel)
|
||||
Q_PROPERTY(AddressBook * addressBook READ addressBook NOTIFY addressBookChanged)
|
||||
Q_PROPERTY(SubaddressModel * subaddressModel READ subaddressModel)
|
||||
Q_PROPERTY(Subaddress * subaddress READ subaddress)
|
||||
Q_PROPERTY(SubaddressAccountModel * subaddressAccountModel READ subaddressAccountModel)
|
||||
Q_PROPERTY(SubaddressAccount * subaddressAccount READ subaddressAccount)
|
||||
Q_PROPERTY(bool viewOnly READ viewOnly)
|
||||
Q_PROPERTY(QString secretViewKey READ getSecretViewKey)
|
||||
Q_PROPERTY(QString publicViewKey READ getPublicViewKey)
|
||||
Q_PROPERTY(QString secretSpendKey READ getSecretSpendKey)
|
||||
Q_PROPERTY(QString publicSpendKey READ getPublicSpendKey)
|
||||
Q_PROPERTY(QString daemonLogPath READ getDaemonLogPath CONSTANT)
|
||||
Q_PROPERTY(QString proxyAddress READ getProxyAddress WRITE setProxyAddress NOTIFY proxyAddressChanged)
|
||||
Q_PROPERTY(quint64 walletCreationHeight READ getWalletCreationHeight WRITE setWalletCreationHeight NOTIFY walletCreationHeightChanged)
|
||||
|
||||
public:
|
||||
|
||||
|
||||
enum Status {
|
||||
Status_Ok = Monero::Wallet::Status_Ok,
|
||||
Status_Error = Monero::Wallet::Status_Error,
|
||||
|
@ -115,9 +87,10 @@ public:
|
|||
|
||||
enum ConnectionStatus {
|
||||
ConnectionStatus_Disconnected = Monero::Wallet::ConnectionStatus_Disconnected,
|
||||
ConnectionStatus_Connected = Monero::Wallet::ConnectionStatus_Connected,
|
||||
ConnectionStatus_WrongVersion = Monero::Wallet::ConnectionStatus_WrongVersion,
|
||||
ConnectionStatus_Connecting
|
||||
ConnectionStatus_Connecting = 9,
|
||||
ConnectionStatus_Synchronizing = 10,
|
||||
ConnectionStatus_Synchronized = 11
|
||||
};
|
||||
|
||||
Q_ENUM(ConnectionStatus)
|
||||
|
@ -132,7 +105,7 @@ public:
|
|||
QString getSeedLanguage() const;
|
||||
|
||||
//! set seed language
|
||||
Q_INVOKABLE void setSeedLanguage(const QString &lang);
|
||||
void setSeedLanguage(const QString &lang);
|
||||
|
||||
//! returns last operation's status
|
||||
Status status() const;
|
||||
|
@ -143,32 +116,37 @@ public:
|
|||
//! returns true if wallet was ever synchronized
|
||||
bool synchronized() const;
|
||||
|
||||
//! returns true if wallet is currently synchronized
|
||||
bool isSynchronized() const;
|
||||
|
||||
//! return true if wallet is connected to a node
|
||||
bool isConnected() const;
|
||||
|
||||
//! returns last operation's error message
|
||||
QString errorString() const;
|
||||
|
||||
//! changes the password using existing parameters (path, seed, seed lang)
|
||||
Q_INVOKABLE bool setPassword(const QString &password);
|
||||
bool setPassword(const QString &password);
|
||||
|
||||
//! get current wallet password
|
||||
Q_INVOKABLE QString getPassword();
|
||||
QString getPassword();
|
||||
|
||||
//! returns wallet's public address
|
||||
Q_INVOKABLE QString address(quint32 accountIndex, quint32 addressIndex) const;
|
||||
QString address(quint32 accountIndex, quint32 addressIndex) const;
|
||||
|
||||
//! returns the subaddress index of the address
|
||||
Q_INVOKABLE SubaddressIndex subaddressIndex(const QString &address) const;
|
||||
SubaddressIndex subaddressIndex(const QString &address) const;
|
||||
|
||||
//! returns wallet file's path
|
||||
QString path() const;
|
||||
|
||||
//! saves wallet to the file by given path
|
||||
//! empty path stores in current location
|
||||
Q_INVOKABLE void store(const QString &path = "");
|
||||
// Q_INVOKABLE void storeAsync(const QJSValue &callback, const QString &path = "");
|
||||
void store(const QString &path = "");
|
||||
// void storeAsync(const QJSValue &callback, const QString &path = "");
|
||||
|
||||
//! initializes wallet asynchronously
|
||||
Q_INVOKABLE void initAsync(
|
||||
void initAsync(
|
||||
const QString &daemonAddress,
|
||||
bool trustedDaemon = false,
|
||||
quint64 upperTransactionLimit = 0,
|
||||
|
@ -177,167 +155,167 @@ public:
|
|||
quint64 restoreHeight = 0,
|
||||
const QString &proxyAddress = "");
|
||||
|
||||
bool setDaemon(const QString &daemonAddress);
|
||||
|
||||
// Set daemon rpc user/pass
|
||||
Q_INVOKABLE void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = "");
|
||||
void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = "");
|
||||
|
||||
//! create a view only wallet
|
||||
Q_INVOKABLE bool createViewOnly(const QString &path, const QString &password) const;
|
||||
bool createViewOnly(const QString &path, const QString &password) const;
|
||||
|
||||
//! connects to daemon
|
||||
Q_INVOKABLE bool connectToDaemon();
|
||||
|
||||
//! set connect to daemon timeout
|
||||
Q_INVOKABLE void setConnectionTimeout(int timeout);
|
||||
bool connectToDaemon();
|
||||
|
||||
//! indicates if daemon is trusted
|
||||
Q_INVOKABLE void setTrustedDaemon(bool arg);
|
||||
void setTrustedDaemon(bool arg);
|
||||
|
||||
//! indicates if ssl should be used to connect to daemon
|
||||
Q_INVOKABLE void setUseSSL(bool ssl);
|
||||
void setUseSSL(bool ssl);
|
||||
|
||||
//! returns balance
|
||||
Q_INVOKABLE quint64 balance() const;
|
||||
Q_INVOKABLE quint64 balance(quint32 accountIndex) const;
|
||||
Q_INVOKABLE quint64 balanceAll() const;
|
||||
quint64 balance() const;
|
||||
quint64 balance(quint32 accountIndex) const;
|
||||
quint64 balanceAll() const;
|
||||
|
||||
//! returns unlocked balance
|
||||
Q_INVOKABLE quint64 unlockedBalance() const;
|
||||
Q_INVOKABLE quint64 unlockedBalance(quint32 accountIndex) const;
|
||||
Q_INVOKABLE quint64 unlockedBalanceAll() const;
|
||||
quint64 unlockedBalance() const;
|
||||
quint64 unlockedBalance(quint32 accountIndex) const;
|
||||
quint64 unlockedBalanceAll() const;
|
||||
|
||||
//! account/address management
|
||||
quint32 currentSubaddressAccount() const;
|
||||
Q_INVOKABLE void switchSubaddressAccount(quint32 accountIndex);
|
||||
Q_INVOKABLE void addSubaddressAccount(const QString& label);
|
||||
Q_INVOKABLE quint32 numSubaddressAccounts() const;
|
||||
Q_INVOKABLE quint32 numSubaddresses(quint32 accountIndex) const;
|
||||
Q_INVOKABLE void addSubaddress(const QString& label);
|
||||
Q_INVOKABLE QString getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const;
|
||||
Q_INVOKABLE void setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, const QString &label);
|
||||
Q_INVOKABLE void deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId);
|
||||
void switchSubaddressAccount(quint32 accountIndex);
|
||||
void addSubaddressAccount(const QString& label);
|
||||
quint32 numSubaddressAccounts() const;
|
||||
quint32 numSubaddresses(quint32 accountIndex) const;
|
||||
void addSubaddress(const QString& label);
|
||||
QString getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const;
|
||||
void setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, const QString &label);
|
||||
void deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId);
|
||||
|
||||
//! hw-device backed wallets
|
||||
Q_INVOKABLE bool isHwBacked() const;
|
||||
Q_INVOKABLE bool isLedger() const;
|
||||
Q_INVOKABLE bool isTrezor() const;
|
||||
bool isHwBacked() const;
|
||||
bool isLedger() const;
|
||||
bool isTrezor() const;
|
||||
|
||||
//! returns if view only wallet
|
||||
Q_INVOKABLE bool viewOnly() const;
|
||||
bool viewOnly() const;
|
||||
|
||||
//! return true if deterministic keys
|
||||
Q_INVOKABLE bool isDeterministic() const;
|
||||
bool isDeterministic() const;
|
||||
|
||||
Q_INVOKABLE void refreshHeightAsync();
|
||||
//! refresh daemon blockchain and target height
|
||||
bool refreshHeights();
|
||||
|
||||
//! export/import key images
|
||||
Q_INVOKABLE bool exportKeyImages(const QString& path, bool all = false);
|
||||
Q_INVOKABLE bool importKeyImages(const QString& path);
|
||||
bool exportKeyImages(const QString& path, bool all = false);
|
||||
bool importKeyImages(const QString& path);
|
||||
|
||||
//! export/import outputs
|
||||
Q_INVOKABLE bool exportOutputs(const QString& path, bool all = false);
|
||||
Q_INVOKABLE bool importOutputs(const QString& path);
|
||||
bool exportOutputs(const QString& path, bool all = false);
|
||||
bool importOutputs(const QString& path);
|
||||
|
||||
//! import a transaction
|
||||
Q_INVOKABLE bool importTransaction(const QString& txid, const QVector<quint64>& output_indeces, quint64 height, quint64 timestamp, bool miner_tx, bool pool, bool double_spend_seen);
|
||||
bool importTransaction(const QString& txid, const QVector<quint64>& output_indeces, quint64 height, quint64 timestamp, bool miner_tx, bool pool, bool double_spend_seen);
|
||||
|
||||
Q_INVOKABLE QString printBlockchain();
|
||||
Q_INVOKABLE QString printTransfers();
|
||||
Q_INVOKABLE QString printPayments();
|
||||
Q_INVOKABLE QString printUnconfirmedPayments();
|
||||
Q_INVOKABLE QString printConfirmedTransferDetails();
|
||||
Q_INVOKABLE QString printUnconfirmedTransferDetails();
|
||||
Q_INVOKABLE QString printPubKeys();
|
||||
Q_INVOKABLE QString printTxNotes();
|
||||
Q_INVOKABLE QString printSubaddresses();
|
||||
Q_INVOKABLE QString printSubaddressLabels();
|
||||
Q_INVOKABLE QString printAdditionalTxKeys();
|
||||
Q_INVOKABLE QString printAttributes();
|
||||
Q_INVOKABLE QString printKeyImages();
|
||||
Q_INVOKABLE QString printAccountTags();
|
||||
Q_INVOKABLE QString printTxKeys();
|
||||
Q_INVOKABLE QString printAddressBook();
|
||||
Q_INVOKABLE QString printScannedPoolTxs();
|
||||
QString printBlockchain();
|
||||
QString printTransfers();
|
||||
QString printPayments();
|
||||
QString printUnconfirmedPayments();
|
||||
QString printConfirmedTransferDetails();
|
||||
QString printUnconfirmedTransferDetails();
|
||||
QString printPubKeys();
|
||||
QString printTxNotes();
|
||||
QString printSubaddresses();
|
||||
QString printSubaddressLabels();
|
||||
QString printAdditionalTxKeys();
|
||||
QString printAttributes();
|
||||
QString printKeyImages();
|
||||
QString printAccountTags();
|
||||
QString printTxKeys();
|
||||
QString printAddressBook();
|
||||
QString printScannedPoolTxs();
|
||||
|
||||
//! refreshes the wallet
|
||||
Q_INVOKABLE bool refresh(bool historyAndSubaddresses = false);
|
||||
bool refresh(bool historyAndSubaddresses = false);
|
||||
|
||||
// pause/resume refresh
|
||||
Q_INVOKABLE void startRefresh();
|
||||
Q_INVOKABLE void pauseRefresh();
|
||||
void startRefresh();
|
||||
void pauseRefresh();
|
||||
|
||||
//! returns current wallet's block height
|
||||
//! (can be less than daemon's blockchain height when wallet sync in progress)
|
||||
Q_INVOKABLE quint64 blockChainHeight() const;
|
||||
quint64 blockChainHeight() const;
|
||||
|
||||
//! returns daemon's blockchain height
|
||||
Q_INVOKABLE quint64 daemonBlockChainHeight() const;
|
||||
quint64 daemonBlockChainHeight() const;
|
||||
|
||||
//! returns daemon's blockchain target height
|
||||
Q_INVOKABLE quint64 daemonBlockChainTargetHeight() const;
|
||||
quint64 daemonBlockChainTargetHeight() const;
|
||||
|
||||
//! creates transaction
|
||||
Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id,
|
||||
PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority);
|
||||
|
||||
//! creates async transaction
|
||||
Q_INVOKABLE void createTransactionAsync(const QString &dst_addr, const QString &payment_id,
|
||||
void createTransactionAsync(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority);
|
||||
|
||||
//! creates multi-destination transaction
|
||||
Q_INVOKABLE PendingTransaction * createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
PendingTransaction * createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
PendingTransaction::Priority priority);
|
||||
|
||||
//! creates async multi-destination transaction
|
||||
Q_INVOKABLE void createTransactionMultiDestAsync(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
void createTransactionMultiDestAsync(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
PendingTransaction::Priority priority);
|
||||
|
||||
|
||||
//! creates transaction with all outputs
|
||||
Q_INVOKABLE PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
|
||||
PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
|
||||
quint32 mixin_count, PendingTransaction::Priority priority);
|
||||
|
||||
//! creates async transaction with all outputs
|
||||
Q_INVOKABLE void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
|
||||
void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
|
||||
quint32 mixin_count, PendingTransaction::Priority priority);
|
||||
|
||||
//! creates transaction with single input
|
||||
Q_INVOKABLE PendingTransaction * createTransactionSingle(const QString &key_image, const QString &dst_addr,
|
||||
PendingTransaction * createTransactionSingle(const QString &key_image, const QString &dst_addr,
|
||||
size_t outputs, PendingTransaction::Priority priority);
|
||||
|
||||
//! creates async transaction with single input
|
||||
Q_INVOKABLE void createTransactionSingleAsync(const QString &key_image, const QString &dst_addr,
|
||||
void createTransactionSingleAsync(const QString &key_image, const QString &dst_addr,
|
||||
size_t outputs, PendingTransaction::Priority priority);
|
||||
|
||||
//! creates sweep unmixable transaction
|
||||
Q_INVOKABLE PendingTransaction * createSweepUnmixableTransaction();
|
||||
PendingTransaction * createSweepUnmixableTransaction();
|
||||
|
||||
//! creates async sweep unmixable transaction
|
||||
Q_INVOKABLE void createSweepUnmixableTransactionAsync();
|
||||
void createSweepUnmixableTransactionAsync();
|
||||
|
||||
//! Sign a transfer from file
|
||||
Q_INVOKABLE UnsignedTransaction * loadTxFile(const QString &fileName);
|
||||
UnsignedTransaction * loadTxFile(const QString &fileName);
|
||||
|
||||
//! Load an unsigned transaction from a base64 encoded string
|
||||
Q_INVOKABLE UnsignedTransaction * loadTxFromBase64Str(const QString &unsigned_tx);
|
||||
UnsignedTransaction * loadTxFromBase64Str(const QString &unsigned_tx);
|
||||
|
||||
//! Load a signed transaction from file
|
||||
Q_INVOKABLE PendingTransaction * loadSignedTxFile(const QString &fileName);
|
||||
PendingTransaction * loadSignedTxFile(const QString &fileName);
|
||||
|
||||
//! Submit a transfer from file
|
||||
Q_INVOKABLE bool submitTxFile(const QString &fileName) const;
|
||||
bool submitTxFile(const QString &fileName) const;
|
||||
|
||||
//! asynchronous transaction commit
|
||||
Q_INVOKABLE void commitTransactionAsync(PendingTransaction * t);
|
||||
void commitTransactionAsync(PendingTransaction * t);
|
||||
|
||||
//! deletes transaction and frees memory
|
||||
Q_INVOKABLE void disposeTransaction(PendingTransaction * t);
|
||||
void disposeTransaction(PendingTransaction * t);
|
||||
|
||||
//! deletes unsigned transaction and frees memory
|
||||
Q_INVOKABLE void disposeTransaction(UnsignedTransaction * t);
|
||||
void disposeTransaction(UnsignedTransaction * t);
|
||||
|
||||
// Q_INVOKABLE void estimateTransactionFeeAsync(const QString &destination,
|
||||
// void estimateTransactionFeeAsync(const QString &destination,
|
||||
// quint64 amount,
|
||||
// PendingTransaction::Priority priority,
|
||||
// const QJSValue &callback);
|
||||
|
@ -376,46 +354,41 @@ public:
|
|||
CoinsModel *coinsModel() const;
|
||||
|
||||
//! generate payment id
|
||||
Q_INVOKABLE QString generatePaymentId() const;
|
||||
QString generatePaymentId() const;
|
||||
|
||||
//! integrated address
|
||||
Q_INVOKABLE QString integratedAddress(const QString &paymentId) const;
|
||||
QString integratedAddress(const QString &paymentId) const;
|
||||
|
||||
//! signing a message
|
||||
Q_INVOKABLE QString signMessage(const QString &message, bool filename = false, const QString &address = "") const;
|
||||
QString signMessage(const QString &message, bool filename = false, const QString &address = "") const;
|
||||
|
||||
//! verify a signed message
|
||||
Q_INVOKABLE bool verifySignedMessage(const QString &message, const QString &address, const QString &signature, bool filename = false) const;
|
||||
bool verifySignedMessage(const QString &message, const QString &address, const QString &signature, bool filename = false) const;
|
||||
|
||||
//! Parse URI
|
||||
Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error);
|
||||
|
||||
//! saved payment id
|
||||
QString paymentId() const;
|
||||
|
||||
void setPaymentId(const QString &paymentId);
|
||||
bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error);
|
||||
|
||||
//! Namespace your cacheAttribute keys to avoid collisions
|
||||
Q_INVOKABLE bool setCacheAttribute(const QString &key, const QString &val);
|
||||
Q_INVOKABLE QString getCacheAttribute(const QString &key) const;
|
||||
bool setCacheAttribute(const QString &key, const QString &val);
|
||||
QString getCacheAttribute(const QString &key) const;
|
||||
|
||||
Q_INVOKABLE bool setUserNote(const QString &txid, const QString ¬e);
|
||||
Q_INVOKABLE QString getUserNote(const QString &txid) const;
|
||||
Q_INVOKABLE QString getTxKey(const QString &txid) const;
|
||||
//Q_INVOKABLE void getTxKeyAsync(const QString &txid, const QJSValue &callback);
|
||||
Q_INVOKABLE QString checkTxKey(const QString &txid, const QString &tx_key, const QString &address);
|
||||
Q_INVOKABLE TxProof getTxProof(const QString &txid, const QString &address, const QString &message) const;
|
||||
// Q_INVOKABLE void getTxProofAsync(const QString &txid, const QString &address, const QString &message, const QJSValue &callback);
|
||||
//Q_INVOKABLE QString checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
|
||||
Q_INVOKABLE TxProofResult checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
|
||||
Q_INVOKABLE TxProof getSpendProof(const QString &txid, const QString &message) const;
|
||||
// Q_INVOKABLE void getSpendProofAsync(const QString &txid, const QString &message, const QJSValue &callback);
|
||||
Q_INVOKABLE QPair<bool, bool> checkSpendProof(const QString &txid, const QString &message, const QString &signature) const;
|
||||
bool setUserNote(const QString &txid, const QString ¬e);
|
||||
QString getUserNote(const QString &txid) const;
|
||||
QString getTxKey(const QString &txid) const;
|
||||
//void getTxKeyAsync(const QString &txid, const QJSValue &callback);
|
||||
QString checkTxKey(const QString &txid, const QString &tx_key, const QString &address);
|
||||
TxProof getTxProof(const QString &txid, const QString &address, const QString &message) const;
|
||||
// void getTxProofAsync(const QString &txid, const QString &address, const QString &message, const QJSValue &callback);
|
||||
//QString checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
|
||||
TxProofResult checkTxProof(const QString &txid, const QString &address, const QString &message, const QString &signature);
|
||||
TxProof getSpendProof(const QString &txid, const QString &message) const;
|
||||
// void getSpendProofAsync(const QString &txid, const QString &message, const QJSValue &callback);
|
||||
QPair<bool, bool> checkSpendProof(const QString &txid, const QString &message, const QString &signature) const;
|
||||
// Rescan spent outputs
|
||||
Q_INVOKABLE bool rescanSpent();
|
||||
bool rescanSpent();
|
||||
|
||||
// check if fork rules should be used
|
||||
Q_INVOKABLE bool useForkRules(quint8 version, quint64 earlyBlocks = 0) const;
|
||||
bool useForkRules(quint8 version, quint64 earlyBlocks = 0) const;
|
||||
|
||||
//! Get wallet keys
|
||||
QString getSecretViewKey() const {return QString::fromStdString(m_walletImpl->secretViewKey());}
|
||||
|
@ -427,30 +400,29 @@ public:
|
|||
void setWalletCreationHeight(quint64 height);
|
||||
|
||||
QString getDaemonLogPath() const;
|
||||
QString getWalletLogPath() const;
|
||||
|
||||
// Blackalled outputs
|
||||
Q_INVOKABLE bool blackballOutput(const QString &amount, const QString &offset);
|
||||
Q_INVOKABLE bool blackballOutputs(const QList<QString> &outputs, bool add);
|
||||
Q_INVOKABLE bool blackballOutputs(const QString &filename, bool add);
|
||||
Q_INVOKABLE bool unblackballOutput(const QString &amount, const QString &offset);
|
||||
bool blackballOutput(const QString &amount, const QString &offset);
|
||||
bool blackballOutputs(const QList<QString> &outputs, bool add);
|
||||
bool blackballOutputs(const QString &filename, bool add);
|
||||
bool unblackballOutput(const QString &amount, const QString &offset);
|
||||
|
||||
// Rings
|
||||
Q_INVOKABLE QString getRing(const QString &key_image);
|
||||
Q_INVOKABLE QString getRings(const QString &txid);
|
||||
Q_INVOKABLE bool setRing(const QString &key_image, const QString &ring, bool relative);
|
||||
QString getRing(const QString &key_image);
|
||||
QString getRings(const QString &txid);
|
||||
bool setRing(const QString &key_image, const QString &ring, bool relative);
|
||||
|
||||
// key reuse mitigation options
|
||||
Q_INVOKABLE void segregatePreForkOutputs(bool segregate);
|
||||
Q_INVOKABLE void segregationHeight(quint64 height);
|
||||
Q_INVOKABLE void keyReuseMitigation2(bool mitigation);
|
||||
void segregatePreForkOutputs(bool segregate);
|
||||
void segregationHeight(quint64 height);
|
||||
void keyReuseMitigation2(bool mitigation);
|
||||
|
||||
// Passphrase entry for hardware wallets
|
||||
Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
|
||||
void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
|
||||
virtual void onWalletPassphraseNeeded(bool on_device) override;
|
||||
|
||||
Q_INVOKABLE quint64 getBytesReceived() const;
|
||||
Q_INVOKABLE quint64 getBytesSent() const;
|
||||
quint64 getBytesReceived() const;
|
||||
quint64 getBytesSent() const;
|
||||
|
||||
// TODO: setListenter() when it implemented in API
|
||||
signals:
|
||||
|
@ -510,6 +482,8 @@ private:
|
|||
void setProxyAddress(QString address);
|
||||
void startRefreshThread();
|
||||
|
||||
void onNewBlock(uint64_t height);
|
||||
|
||||
private:
|
||||
friend class WalletManager;
|
||||
friend class WalletListenerImpl;
|
||||
|
@ -523,17 +497,13 @@ private:
|
|||
QString m_paymentId;
|
||||
AddressBook * m_addressBook;
|
||||
mutable AddressBookModel * m_addressBookModel;
|
||||
mutable QElapsedTimer m_daemonBlockChainHeightTime;
|
||||
mutable quint64 m_daemonBlockChainHeight;
|
||||
int m_daemonBlockChainHeightTtl;
|
||||
mutable QElapsedTimer m_daemonBlockChainTargetHeightTime;
|
||||
mutable quint64 m_daemonBlockChainTargetHeight;
|
||||
int m_daemonBlockChainTargetHeightTtl;
|
||||
|
||||
mutable ConnectionStatus m_connectionStatus;
|
||||
int m_connectionStatusTtl;
|
||||
mutable QElapsedTimer m_connectionStatusTime;
|
||||
|
||||
bool m_disconnected;
|
||||
mutable bool m_initialized;
|
||||
mutable bool m_initialized;
|
||||
uint32_t m_currentSubaddressAccount;
|
||||
Subaddress * m_subaddress;
|
||||
mutable SubaddressModel * m_subaddressModel;
|
||||
|
@ -542,8 +512,6 @@ private:
|
|||
Coins * m_coins;
|
||||
mutable CoinsModel * m_coinsModel;
|
||||
QMutex m_asyncMutex;
|
||||
QMutex m_connectionStatusMutex;
|
||||
bool m_connectionStatusRunning;
|
||||
QString m_daemonUsername;
|
||||
QString m_daemonPassword;
|
||||
QString m_proxyAddress;
|
||||
|
|
|
@ -32,6 +32,7 @@ void WalletListenerImpl::unconfirmedMoneyReceived(const std::string &txId, uint6
|
|||
void WalletListenerImpl::newBlock(uint64_t height)
|
||||
{
|
||||
// qDebug() << __FUNCTION__;
|
||||
m_wallet->onNewBlock(height);
|
||||
emit m_wallet->newBlock(height, m_wallet->daemonBlockChainTargetHeight());
|
||||
}
|
||||
|
||||
|
|
|
@ -481,3 +481,26 @@ void WalletManager::onPassphraseEntered(const QString &passphrase, bool enter_on
|
|||
m_passphraseReceiver->onPassphraseEntered(passphrase, enter_on_device, entry_abort);
|
||||
}
|
||||
}
|
||||
|
||||
QString WalletManager::proxyAddress() const
|
||||
{
|
||||
QMutexLocker locker(&m_proxyMutex);
|
||||
return m_proxyAddress;
|
||||
}
|
||||
|
||||
void WalletManager::setProxyAddress(QString address)
|
||||
{
|
||||
m_scheduler.run([this, address] {
|
||||
{
|
||||
QMutexLocker locker(&m_proxyMutex);
|
||||
|
||||
if (!m_pimpl->setProxy(address.toStdString()))
|
||||
{
|
||||
qCritical() << "Failed to set proxy address" << address;
|
||||
}
|
||||
|
||||
m_proxyAddress = std::move(address);
|
||||
}
|
||||
emit proxyAddressChanged();
|
||||
});
|
||||
}
|
|
@ -172,6 +172,9 @@ public:
|
|||
Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
|
||||
virtual void onWalletPassphraseNeeded(bool on_device) override;
|
||||
|
||||
QString proxyAddress() const;
|
||||
void setProxyAddress(QString address);
|
||||
|
||||
signals:
|
||||
|
||||
void walletOpened(Wallet * wallet);
|
||||
|
@ -186,6 +189,7 @@ signals:
|
|||
const QString &firstSigner,
|
||||
const QString &secondSigner) const;
|
||||
void miningStatus(bool isMining) const;
|
||||
void proxyAddressChanged() const;
|
||||
|
||||
public slots:
|
||||
private:
|
||||
|
@ -202,6 +206,8 @@ private:
|
|||
QPointer<Wallet> m_currentWallet;
|
||||
PassphraseReceiver * m_passphraseReceiver;
|
||||
QMutex m_mutex_passphraseReceiver;
|
||||
QString m_proxyAddress;
|
||||
mutable QMutex m_proxyMutex;
|
||||
FutureScheduler m_scheduler;
|
||||
};
|
||||
|
||||
|
|
|
@ -102,9 +102,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
|||
|
||||
if(cliMode) {
|
||||
QCoreApplication cli_app(argc, argv);
|
||||
QCoreApplication::setApplicationName("feather");
|
||||
QCoreApplication::setOrganizationDomain("featherwallet.org");
|
||||
QCoreApplication::setOrganizationName("featherwallet.org");
|
||||
QCoreApplication::setApplicationName("FeatherWallet");
|
||||
|
||||
auto *ctx = new AppContext(&parser);
|
||||
|
||||
|
@ -136,9 +134,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
|||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QApplication::setApplicationName("feather");
|
||||
QApplication::setOrganizationDomain("featherwallet.org");
|
||||
QApplication::setOrganizationName("featherwallet.org");
|
||||
QApplication::setApplicationName("FeatherWallet");
|
||||
|
||||
parser.process(app); // Parse again for --help and --version
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QFileDialog>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "dialog/txconfdialog.h"
|
||||
|
@ -37,6 +38,12 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
|
|||
pMainWindow = this;
|
||||
ui->setupUi(this);
|
||||
|
||||
// Preload icons for better performance
|
||||
m_statusDisconnected = QIcon(":/assets/images/status_disconnected.svg");
|
||||
m_statusConnecting = QIcon(":/assets/images/status_lagging.svg");
|
||||
m_statusSynchronizing = QIcon(":/assets/images/status_waiting.svg");
|
||||
m_statusSynchronized = QIcon(":/assets/images/status_connected.svg");
|
||||
|
||||
m_windowSettings = new Settings(this);
|
||||
m_aboutDialog = new AboutDialog(this);
|
||||
m_windowCalc = new CalcWindow(this);
|
||||
|
@ -244,7 +251,11 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) :
|
|||
if(config()->get(Config::warnOnAlpha).toBool()) {
|
||||
QString warning = "Feather Wallet is currently in beta.\n\nPlease report any bugs "
|
||||
"you encounter on our Git repository, IRC or on /r/FeatherWallet.";
|
||||
QMessageBox::warning(this, "Beta Warning", warning);
|
||||
QMessageBox warningMb(this);
|
||||
warningMb.setWindowTitle("Beta Warning");
|
||||
warningMb.setText(warning);
|
||||
this->centerWidget(warningMb);
|
||||
warningMb.exec();
|
||||
config()->set(Config::warnOnAlpha, false);
|
||||
}
|
||||
|
||||
|
@ -360,10 +371,14 @@ void MainWindow::initMain() {
|
|||
return;
|
||||
}
|
||||
|
||||
this->setEnabled(false);
|
||||
this->setEnabled(true);
|
||||
this->show();
|
||||
m_wizard = this->createWizard(WalletWizard::Page_Menu);
|
||||
m_wizard->show();
|
||||
|
||||
// wizard won't spawn on top of MainWindow without this dumb pattern
|
||||
this->setEnabled(false);
|
||||
m_wizard->setEnabled(true);
|
||||
this->touchbarShowWizard();
|
||||
}
|
||||
|
||||
|
@ -658,7 +673,6 @@ void MainWindow::setStatusText(const QString &text, bool override, int timeout)
|
|||
void MainWindow::onSynchronized() {
|
||||
this->updateNetStats();
|
||||
this->setStatusText("Synchronized");
|
||||
this->onConnectionStatusChanged(Wallet::ConnectionStatus_Connected);
|
||||
}
|
||||
|
||||
void MainWindow::onBlockchainSync(int height, int target) {
|
||||
|
@ -679,34 +693,32 @@ void MainWindow::onConnectionStatusChanged(int status)
|
|||
|
||||
// Update connection info in status bar.
|
||||
|
||||
QString statusIcon;
|
||||
QString statusMsg;
|
||||
QIcon *icon;
|
||||
switch(status){
|
||||
case Wallet::ConnectionStatus_Disconnected:
|
||||
statusIcon = ":/assets/images/status_disconnected.svg";
|
||||
icon = &m_statusDisconnected;
|
||||
this->setStatusText("Disconnected");
|
||||
break;
|
||||
case Wallet::ConnectionStatus_Connected:
|
||||
if (m_ctx->currentWallet->synchronized()) {
|
||||
statusIcon = ":/assets/images/status_connected.svg";
|
||||
} else {
|
||||
statusIcon = ":/assets/images/status_waiting.svg";
|
||||
}
|
||||
break;
|
||||
case Wallet::ConnectionStatus_Connecting:
|
||||
statusIcon = ":/assets/images/status_lagging.svg";
|
||||
this->setStatusText("Connecting to daemon");
|
||||
icon = &m_statusConnecting;
|
||||
this->setStatusText("Connecting to node");
|
||||
break;
|
||||
case Wallet::ConnectionStatus_WrongVersion:
|
||||
statusIcon = ":/assets/images/status_disconnected.svg";
|
||||
this->setStatusText("Incompatible daemon");
|
||||
icon = &m_statusDisconnected;
|
||||
this->setStatusText("Incompatible node");
|
||||
break;
|
||||
case Wallet::ConnectionStatus_Synchronizing:
|
||||
icon = &m_statusSynchronizing;
|
||||
break;
|
||||
case Wallet::ConnectionStatus_Synchronized:
|
||||
icon = &m_statusSynchronized;
|
||||
break;
|
||||
default:
|
||||
statusIcon = ":/assets/images/status_disconnected.svg";
|
||||
icon = &m_statusDisconnected;
|
||||
break;
|
||||
}
|
||||
|
||||
m_statusBtnConnectionStatusIndicator->setIcon(QIcon(statusIcon));
|
||||
m_statusBtnConnectionStatusIndicator->setIcon(*icon);
|
||||
}
|
||||
|
||||
void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QVector<QString> &address) {
|
||||
|
@ -751,7 +763,7 @@ void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QVecto
|
|||
break;
|
||||
}
|
||||
case QDialog::Accepted:
|
||||
m_ctx->currentWallet->commitTransactionAsync(tx);
|
||||
m_ctx->commitTransaction(tx);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -854,20 +866,13 @@ void MainWindow::showSeedDialog() {
|
|||
|
||||
void MainWindow::showConnectionStatusDialog() {
|
||||
auto status = m_ctx->currentWallet->connectionStatus();
|
||||
bool synchronized = m_ctx->currentWallet->synchronized();
|
||||
bool synchronized = m_ctx->currentWallet->isSynchronized();
|
||||
|
||||
QString statusMsg;
|
||||
switch(status){
|
||||
case Wallet::ConnectionStatus_Disconnected:
|
||||
statusMsg = "Wallet is disconnected from daemon.";
|
||||
break;
|
||||
case Wallet::ConnectionStatus_Connected: {
|
||||
auto node = m_ctx->nodes->connection();
|
||||
statusMsg = QString("Wallet is connected to %1").arg(node.full);
|
||||
if (synchronized)
|
||||
statusMsg += " and synchronized";
|
||||
break;
|
||||
}
|
||||
case Wallet::ConnectionStatus_Connecting: {
|
||||
auto node = m_ctx->nodes->connection();
|
||||
statusMsg = QString("Wallet is connecting to %1").arg(node.full);
|
||||
|
@ -876,6 +881,15 @@ void MainWindow::showConnectionStatusDialog() {
|
|||
case Wallet::ConnectionStatus_WrongVersion:
|
||||
statusMsg = "Wallet is connected to incompatible daemon.";
|
||||
break;
|
||||
case Wallet::ConnectionStatus_Synchronizing: {
|
||||
auto node = m_ctx->nodes->connection();
|
||||
statusMsg = QString("Wallet is connected to %1").arg(node.full);
|
||||
}
|
||||
case Wallet::ConnectionStatus_Synchronized: {
|
||||
if (synchronized)
|
||||
statusMsg += " and synchronized";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
statusMsg = "Unknown connection status (this should never happen).";
|
||||
}
|
||||
|
@ -961,28 +975,6 @@ void MainWindow::menuWalletCloseClicked() {
|
|||
m_ctx->closeWallet(true, true);
|
||||
}
|
||||
|
||||
void MainWindow::menuWalletOpenClicked() {
|
||||
auto walletPath = config()->get(Config::walletPath).toString();
|
||||
if(walletPath.isEmpty())
|
||||
walletPath = m_ctx->defaultWalletDir;
|
||||
QString path = QFileDialog::getOpenFileName(this, "Select your wallet file", walletPath, "Wallet file (*.keys)");
|
||||
if(path.isEmpty()) return;
|
||||
|
||||
QFileInfo infoPath(path);
|
||||
if(!infoPath.isReadable()) {
|
||||
QMessageBox::warning(this, "Cannot read wallet file", "Permission error.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(path == m_ctx->walletPath) {
|
||||
QMessageBox::warning(this, "Wallet already opened", "Please open another wallet.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_ctx->closeWallet(false);
|
||||
m_ctx->onOpenWallet(path, "");
|
||||
}
|
||||
|
||||
void MainWindow::menuAboutClicked() {
|
||||
m_aboutDialog->show();
|
||||
}
|
||||
|
@ -1318,7 +1310,7 @@ void MainWindow::updateNetStats() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Connected && m_ctx->currentWallet->synchronized()) {
|
||||
if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Synchronized) {
|
||||
m_statusLabelNetStats->setText("");
|
||||
return;
|
||||
}
|
||||
|
@ -1357,6 +1349,16 @@ void MainWindow::bringToFront() {
|
|||
activateWindow();
|
||||
}
|
||||
|
||||
void MainWindow::centerWidget(QWidget &w) {
|
||||
QScreen *s = QGuiApplication::primaryScreen();
|
||||
|
||||
const QRect sr = s->geometry();
|
||||
const QRect wr({}, w.frameSize().boundedTo(sr.size()));
|
||||
|
||||
w.resize(wr.size());
|
||||
w.move(sr.center() - wr.center());
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
delete ui;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "dialog/keysdialog.h"
|
||||
#include "dialog/aboutdialog.h"
|
||||
#include "dialog/restoredialog.h"
|
||||
#include "libwalletqt/Wallet.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
|
@ -117,7 +118,6 @@ public slots:
|
|||
void onWalletCreatedError(const QString &err);
|
||||
void onWalletCreated(Wallet *wallet);
|
||||
void menuWalletCloseClicked();
|
||||
void menuWalletOpenClicked();
|
||||
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);
|
||||
void onViewOnBlockExplorer(const QString &txid);
|
||||
void onResendTransaction(const QString &txid);
|
||||
|
@ -173,6 +173,7 @@ private:
|
|||
void showBalanceDialog();
|
||||
QString statusDots();
|
||||
void bringToFront();
|
||||
void centerWidget(QWidget &w);
|
||||
|
||||
WalletWizard *createWizard(WalletWizard::Page startPage);
|
||||
|
||||
|
@ -223,6 +224,11 @@ private:
|
|||
bool m_statusOverrideActive = false;
|
||||
QTimer m_txTimer;
|
||||
|
||||
QIcon m_statusDisconnected;
|
||||
QIcon m_statusConnecting;
|
||||
QIcon m_statusSynchronizing;
|
||||
QIcon m_statusSynchronized;
|
||||
|
||||
private slots:
|
||||
void menuToggleTabVisible(const QString &key);
|
||||
};
|
||||
|
|
|
@ -85,6 +85,8 @@ void HistoryView::setSearchMode(bool mode) {
|
|||
|
||||
if (mode) {
|
||||
header()->showSection(TransactionHistoryModel::TxID);
|
||||
} else {
|
||||
header()->hideSection(TransactionHistoryModel::TxID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +101,8 @@ bool HistoryView::setViewState(const QByteArray& state)
|
|||
header()->setSortIndicator(-1, Qt::AscendingOrder);
|
||||
bool status = header()->restoreState(state);
|
||||
m_columnsNeedRelayout = state.isEmpty();
|
||||
|
||||
m_showTxidColumn = !header()->isSectionHidden(TransactionHistoryModel::TxID);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
TransactionHistoryProxyModel* m_model;
|
||||
bool m_inSearchMode = false;
|
||||
bool m_columnsNeedRelayout = true;
|
||||
bool m_showTxidColumn = false;
|
||||
|
||||
QMenu* m_headerMenu;
|
||||
QActionGroup* m_columnActions;
|
||||
|
|
|
@ -100,7 +100,7 @@ void SendWidget::fillAddress(const QString &address) {
|
|||
}
|
||||
|
||||
void SendWidget::sendClicked() {
|
||||
if (m_ctx->currentWallet->connectionStatus() != Wallet::ConnectionStatus_Connected) {
|
||||
if (!m_ctx->currentWallet->isConnected()) {
|
||||
QMessageBox::warning(this, "Error", "Unable to create transaction:\n\n"
|
||||
"Wallet is not connected to a node.\n"
|
||||
"Go to File -> Settings -> Node to manually connect to a node.");
|
||||
|
|
|
@ -50,6 +50,9 @@
|
|||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="tabChangesFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
|
|
|
@ -20,6 +20,9 @@ Settings::Settings(QWidget *parent) :
|
|||
ui->tabWidget->setTabVisible(4, false);
|
||||
|
||||
connect(ui->btnCopyToClipboard, &QPushButton::clicked, this, &Settings::copyToClipboard);
|
||||
connect(ui->checkBox_multiBroadcast, &QCheckBox::toggled, [](bool toggled){
|
||||
config()->set(Config::multiBroadcast, toggled);
|
||||
});
|
||||
connect(ui->checkBox_externalLink, &QCheckBox::clicked, this, &Settings::checkboxExternalLinkWarn);
|
||||
connect(ui->checkBox_hideBalance, &QCheckBox::toggled, [this](bool toggled){
|
||||
config()->set(Config::hideBalance, toggled);
|
||||
|
@ -34,6 +37,7 @@ Settings::Settings(QWidget *parent) :
|
|||
connect(ui->nodeWidget, &NodeWidget::connectToNode, m_ctx->nodes, QOverload<const FeatherNode&>::of(&Nodes::connectToNode));
|
||||
|
||||
// setup checkboxes
|
||||
ui->checkBox_multiBroadcast->setChecked(config()->get(Config::multiBroadcast).toBool());
|
||||
ui->checkBox_externalLink->setChecked(config()->get(Config::warnOnExternalLink).toBool());
|
||||
ui->checkBox_hideBalance->setChecked(config()->get(Config::hideBalance).toBool());
|
||||
|
||||
|
|
395
src/settings.ui
395
src/settings.ui
|
@ -23,214 +23,225 @@
|
|||
<attribute name="title">
|
||||
<string>General</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Preferred fiat currency:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboBox_fiatCurrency">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>USD</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>EUR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>RUB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>GBP</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AUD</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CAD</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CHF</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CNY</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CZK</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>JPY</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>KRW</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>MXN</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>NZD</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>SEK</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>THB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>TRY</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ZAR</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Appearance:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboBox_skin"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Block explorer:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboBox_blockExplorer">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>exploremonero.com</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>xmrchain.net</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>moneroblocks.info</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>blockchair.com</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Reddit frontend:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="comboBox_redditFrontend">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>old.reddit.com</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>reddit.com</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>teddit.net</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Amount precision:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="comboBox_amountPrecision"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Date format:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="comboBox_dateFormat"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Time format:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="comboBox_timeFormat"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_multiBroadcast">
|
||||
<property name="text">
|
||||
<string>Preferred fiat currency:</string>
|
||||
<string>Multibroadcast outgoing transactions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboBox_fiatCurrency">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>USD</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>EUR</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>RUB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>GBP</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AUD</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CAD</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CHF</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CNY</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CZK</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>JPY</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>KRW</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>MXN</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>NZD</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>SEK</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>THB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>TRY</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ZAR</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Appearance:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboBox_skin"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Block explorer:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboBox_blockExplorer">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>exploremonero.com</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>xmrchain.net</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>moneroblocks.info</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>blockchair.com</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_externalLink">
|
||||
<property name="text">
|
||||
<string>Warn before opening external link</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_hideBalance">
|
||||
<property name="text">
|
||||
<string>Hide balance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Reddit frontend:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="comboBox_redditFrontend">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>old.reddit.com</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>reddit.com</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>teddit.net</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Amount precision:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="comboBox_amountPrecision"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Date format:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="comboBox_dateFormat"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Time format:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="comboBox_timeFormat"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_node">
|
||||
|
|
|
@ -50,7 +50,8 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
|||
{Config::GUI_HistoryViewState, {QS("GUI_HistoryViewState"), {}}},
|
||||
{Config::amountPrecision, {QS("amountPrecision"), 4}},
|
||||
{Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}},
|
||||
{Config::timeFormat, {QS("timeFormat"), "HH:mm"}}
|
||||
{Config::timeFormat, {QS("timeFormat"), "HH:mm"}},
|
||||
{Config::multiBroadcast, {QS("multiBroadcast"), true}}
|
||||
};
|
||||
|
||||
|
||||
|
@ -110,23 +111,8 @@ Config::Config(QObject* parent)
|
|||
{
|
||||
QDir configDir = Config::defaultConfigDir();
|
||||
|
||||
QString portablePath = QCoreApplication::applicationDirPath().append("/%1");
|
||||
if (QFile::exists(portablePath.arg(".portable"))) {
|
||||
init(portablePath.arg("feather_data/settings.json"));
|
||||
return;
|
||||
}
|
||||
|
||||
bool isTails = TailsOS::detect();
|
||||
if (isTails) { // #if defined(PORTABLE)
|
||||
QString appImagePath = qgetenv("APPIMAGE");
|
||||
QFileInfo appImageDir(appImagePath);
|
||||
|
||||
QDir portablePath(appImageDir.absoluteDir().path() + "/feather_data");
|
||||
if (portablePath.mkpath(".")) {
|
||||
configDir = portablePath;
|
||||
} else {
|
||||
qCritical() << "Unable to create portable directory: " << portablePath.path();
|
||||
}
|
||||
if (!QDir().mkpath(configDir.path())) {
|
||||
qWarning() << "Unable to create config path: " << configDir.path();
|
||||
}
|
||||
|
||||
QString configPath = configDir.filePath("settings.json");
|
||||
|
@ -135,6 +121,26 @@ Config::Config(QObject* parent)
|
|||
}
|
||||
|
||||
QDir Config::defaultConfigDir() {
|
||||
QString portablePath = QCoreApplication::applicationDirPath().append("/%1");
|
||||
if (QFile::exists(portablePath.arg(".portable"))) {
|
||||
return portablePath.arg("feather_data");
|
||||
}
|
||||
|
||||
if (TailsOS::detect()) {
|
||||
QString path = []{
|
||||
QString appImagePath = qgetenv("APPIMAGE");
|
||||
if (appImagePath.isEmpty()) {
|
||||
qDebug() << "Not an appimage, using currentPath()";
|
||||
return QDir::currentPath() + "/.feather/.config/feather";
|
||||
}
|
||||
|
||||
QFileInfo appImageDir(appImagePath);
|
||||
return appImageDir.absoluteDir().path() + "/.feather/.config/feather";
|
||||
}();
|
||||
|
||||
return QDir(path);
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
return QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||
#elif defined(Q_OS_MACOS)
|
||||
|
|
|
@ -54,7 +54,8 @@ public:
|
|||
amountPrecision,
|
||||
portableMode,
|
||||
dateFormat,
|
||||
timeFormat
|
||||
timeFormat,
|
||||
multiBroadcast
|
||||
};
|
||||
|
||||
~Config() override;
|
||||
|
|
|
@ -69,7 +69,12 @@ void WalletKeysFilesModel::refresh() {
|
|||
|
||||
void WalletKeysFilesModel::updateDirectories() {
|
||||
this->walletDirectories.clear();
|
||||
this->walletDirectories << m_ctx->defaultWalletDir; // TODO
|
||||
QDir defaultWalletDir = QDir(Utils::defaultWalletDir());
|
||||
QString walletDir = defaultWalletDir.path();
|
||||
defaultWalletDir.cdUp();
|
||||
QString walletDirRoot = defaultWalletDir.path();
|
||||
this->walletDirectories << walletDir;
|
||||
this->walletDirectories << walletDirRoot;
|
||||
auto walletPath = config()->get(Config::walletPath).toString();
|
||||
if(!walletPath.isEmpty() && Utils::fileExists(walletPath)) {
|
||||
QDir d = QFileInfo(walletPath).absoluteDir();
|
||||
|
|
|
@ -183,7 +183,7 @@ void Nodes::autoConnect(bool forceReconnect) {
|
|||
this->connectToNode(node);
|
||||
return;
|
||||
}
|
||||
else if (status == Wallet::ConnectionStatus_Connected && m_connection.isConnecting) {
|
||||
else if ((status == Wallet::ConnectionStatus_Synchronizing || status == Wallet::ConnectionStatus_Synchronized) && m_connection.isConnecting) {
|
||||
qInfo() << QString("Node connected to %1").arg(m_connection.address);
|
||||
|
||||
// set current connection object
|
||||
|
@ -376,6 +376,10 @@ QList<FeatherNode> Nodes::customNodes() {
|
|||
return m_customNodes;
|
||||
}
|
||||
|
||||
QList<FeatherNode> Nodes::websocketNodes() {
|
||||
return m_websocketNodes;
|
||||
}
|
||||
|
||||
FeatherNode Nodes::connection() {
|
||||
return m_connection;
|
||||
}
|
||||
|
|
|
@ -69,8 +69,8 @@ struct FeatherNode {
|
|||
return QString("%1%2").arg(auth).arg(this->address);
|
||||
}
|
||||
|
||||
QString as_url() {
|
||||
return QString("%1://%2/get_info").arg(this->isHttps ? "https": "http",this->full);
|
||||
QString as_url() const {
|
||||
return QString("%1://%2").arg(this->isHttps ? "https": "http",this->full);
|
||||
}
|
||||
|
||||
bool operator == (const FeatherNode &other) const {
|
||||
|
@ -88,7 +88,9 @@ public:
|
|||
|
||||
NodeSource source();
|
||||
FeatherNode connection();
|
||||
|
||||
QList<FeatherNode> customNodes();
|
||||
QList<FeatherNode> websocketNodes();
|
||||
|
||||
NodeModel *modelWebsocket;
|
||||
NodeModel *modelCustom;
|
||||
|
|
|
@ -11,7 +11,7 @@ TxFiatHistory::TxFiatHistory(int genesis_timestamp, const QString &configDirecto
|
|||
QObject(parent),
|
||||
m_genesis_timestamp(genesis_timestamp),
|
||||
m_configDirectory(configDirectory) {
|
||||
m_databasePath = QString("%1fiatHistory.db").arg(configDirectory);
|
||||
m_databasePath = QString("%1/fiatHistory.db").arg(configDirectory);
|
||||
this->loadDatabase();
|
||||
}
|
||||
|
||||
|
|
|
@ -481,6 +481,26 @@ bool Utils::isTorsocks() {
|
|||
}
|
||||
|
||||
QString Utils::defaultWalletDir() {
|
||||
QString portablePath = QCoreApplication::applicationDirPath().append("/%1");
|
||||
if (QFile::exists(portablePath.arg(".portable"))) {
|
||||
return portablePath.arg("feather_data/wallets");
|
||||
}
|
||||
|
||||
if (TailsOS::detect()) {
|
||||
QString path = []{
|
||||
QString appImagePath = qgetenv("APPIMAGE");
|
||||
if (appImagePath.isEmpty()) {
|
||||
qDebug() << "Not an appimage, using currentPath()";
|
||||
return QDir::currentPath() + "/.feather/Monero/wallets";
|
||||
}
|
||||
|
||||
QFileInfo appImageDir(appImagePath);
|
||||
return appImageDir.absoluteDir().path() + "/.feather/Monero/wallets";
|
||||
}();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_LINUX) or defined(Q_OS_MAC)
|
||||
return QString("%1/Monero/wallets").arg(QDir::homePath());
|
||||
#elif defined(Q_OS_WIN)
|
||||
|
|
|
@ -94,7 +94,7 @@ void NodeWidget::onContextConnect() {
|
|||
void NodeWidget::onContextStatusURL() {
|
||||
FeatherNode node = this->selectedNode();
|
||||
if (!node.full.isEmpty())
|
||||
Utils::externalLinkWarning(this, node.as_url());
|
||||
Utils::externalLinkWarning(this, QString("%1/get_info").arg(node.as_url()));
|
||||
}
|
||||
|
||||
void NodeWidget::onContextNodeCopy() {
|
||||
|
|
|
@ -69,8 +69,7 @@ WalletWizard::WalletWizard(AppContext *ctx, WalletWizard::Page startPage, QWidge
|
|||
});
|
||||
|
||||
connect(openWalletPage, &PageOpenWallet::openWallet, [=](const QString &path){
|
||||
const auto walletPassword = this->field("walletPassword").toString();
|
||||
emit openWallet(path, walletPassword);
|
||||
emit openWallet(path, "");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -89,6 +88,12 @@ void WalletWizard::createWallet() {
|
|||
|
||||
auto seed = FeatherSeed(m_ctx->restoreHeights[m_ctx->networkType], QString::fromStdString(globals::coinName), m_ctx->seedLanguage, m_wizardFields.seed.split(" "));
|
||||
|
||||
if (m_wizardFields.mode == WizardMode::CreateWallet && m_ctx->heights.contains(m_ctx->networkType)) {
|
||||
int restoreHeight = m_ctx->heights[m_ctx->networkType];
|
||||
qInfo() << "New wallet, setting restore height to latest blockheight: " << restoreHeight;
|
||||
seed.setRestoreHeight(restoreHeight);
|
||||
}
|
||||
|
||||
if (m_wizardFields.mode == WizardMode::RestoreFromSeed && m_wizardFields.seedType == SeedType::MONERO)
|
||||
seed.setRestoreHeight(m_wizardFields.restoreHeight);
|
||||
|
||||
|
|
Loading…
Reference in a new issue