diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index bc227e00..9fabd060 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -176,7 +176,7 @@ void Settings::setupNetworkTab() { if (enabled) daemonManager()->start(); else - daemonManager()->stop(); + daemonManager()->stop(false); // non-blocking: don't freeze Settings while wownerod flushes m_nodes->autoConnect(true); }); } else { diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index 5888a066..1d187a75 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -3,9 +3,15 @@ #include "WindowManager.h" +#include +#include #include +#include #include +#include #include +#include +#include #include #include "Application.h" @@ -48,16 +54,22 @@ WindowManager::WindowManager(QObject *parent) this->buildTrayMenu(); m_tray->setVisible(conf()->get(Config::showTrayIcon).toBool()); - // wowlet: boot the embedded wownerod node early so it syncs while the user opens their wallet. - // No-op if the user disabled the local node (Config::runLocalNode) or no daemon is bundled. - daemonManager()->init(); - daemonManager()->start(); - this->initSkins(); this->patchMacStylesheet(); this->showCrashLogs(); + // wowlet: on the very first launch, let the user choose their own node vs a remote one BEFORE anything + // connects. No node — local or remote — starts until they hit Continue. Later launches use the saved choice. + if (conf()->get(Config::firstRun).toBool()) { + this->showNodeWelcome(); + } + + // wowlet: boot the embedded wownerod (shouldStartDaemon() makes this a no-op if the user chose a remote + // node), so it syncs while the user opens their wallet. + daemonManager()->init(); + daemonManager()->start(); + // wowlet: the embedded local node is configured automatically — skip the first-run network wizard. this->onInitialNetworkConfigured(); @@ -68,6 +80,45 @@ WindowManager::WindowManager(QObject *parent) } } +// wowlet: first-run "be your own node" welcome. Shown before any node starts; records the user's choice +// in Config::runLocalNode, which start()/autoConnect then honour. +void WindowManager::showNodeWelcome() { + QDialog dlg; + dlg.setWindowTitle("Welcome to wowlet"); + dlg.setMinimumWidth(440); + + auto *title = new QLabel("🐕 Welcome to wowlet", &dlg); + QFont tf = title->font(); + tf.setPointSize(tf.pointSize() + 4); + tf.setBold(true); + title->setFont(tf); + + auto *intro = new QLabel("wowlet runs your own Wownero node by default: be your own boss and help run the network.", &dlg); + intro->setWordWrap(true); + + auto *check = new QCheckBox("Run your own Wownero node (many recommended)", &dlg); + check->setChecked(conf()->get(Config::runLocalNode).toBool()); + + auto *hint = new QLabel("(untick to use a remote node instead)", &dlg); + hint->setStyleSheet("color: gray;"); + + auto *btn = new QPushButton("Continue", &dlg); + btn->setDefault(true); + connect(btn, &QPushButton::clicked, &dlg, &QDialog::accept); + + auto *layout = new QVBoxLayout(&dlg); + layout->addWidget(title); + layout->addWidget(intro); + layout->addSpacing(8); + layout->addWidget(check); + layout->addWidget(hint); + layout->addSpacing(8); + layout->addWidget(btn, 0, Qt::AlignRight); + + dlg.exec(); // modal — blocks until Continue + conf()->set(Config::runLocalNode, check->isChecked()); +} + QPointer WindowManager::m_instance(nullptr); void WindowManager::setEventFilter(EventFilter *ef) { diff --git a/src/WindowManager.h b/src/WindowManager.h index d0f3e460..98eb2b26 100644 --- a/src/WindowManager.h +++ b/src/WindowManager.h @@ -80,6 +80,7 @@ private: bool autoOpenWallet(); void initWizard(); + void showNodeWelcome(); // wowlet: first-run "be your own node" choice, before any node starts WalletWizard* createWizard(WalletWizard::Page startPage); void handleWalletError(const Utils::Message &message); diff --git a/src/utils/DaemonManager.cpp b/src/utils/DaemonManager.cpp index 2a95ef5f..6659a16c 100644 --- a/src/utils/DaemonManager.cpp +++ b/src/utils/DaemonManager.cpp @@ -97,7 +97,7 @@ void DaemonManager::start() { m_started = true; } -void DaemonManager::stop() { +void DaemonManager::stop(bool wait) { m_stopping = true; if (m_process->state() == QProcess::ProcessState::NotRunning) { m_started = false; @@ -107,12 +107,14 @@ void DaemonManager::stop() { // wownerod owns an LMDB database. Send SIGTERM so it flushes and exits cleanly; only hard-kill // if it refuses to shut down, to avoid blockchain database corruption. m_process->terminate(); + m_started = false; + if (!wait) + return; // toggle/live use: let it flush + exit in the background instead of freezing the UI thread. if (!m_process->waitForFinished(30000)) { qWarning() << "wownerod did not exit gracefully within 30s; killing"; m_process->kill(); m_process->waitForFinished(5000); } - m_started = false; } void DaemonManager::onStateChanged(QProcess::ProcessState state) { diff --git a/src/utils/DaemonManager.h b/src/utils/DaemonManager.h index 71389a70..a7c3f6f0 100644 --- a/src/utils/DaemonManager.h +++ b/src/utils/DaemonManager.h @@ -26,7 +26,7 @@ public: void init(); void start(); - void stop(); + void stop(bool wait = true); // wait=false: non-blocking (don't freeze the UI on a settings toggle) bool unpackBins(); bool isStarted() const { return m_started; } diff --git a/src/widgets/NodeWidget.cpp b/src/widgets/NodeWidget.cpp index de9a4ce7..61053d6a 100644 --- a/src/widgets/NodeWidget.cpp +++ b/src/widgets/NodeWidget.cpp @@ -59,11 +59,11 @@ NodeWidget::NodeWidget(QWidget *parent) // wowlet: built-in node toggle + the "why run your own node" messaging. Running your own node is // a privacy win (no remote operator sees your wallet) AND it strengthens the Wownero network by // adding a peer — a deliberate differentiator we surface clearly here. - m_localNodeCheck = new QCheckBox(tr("Run your own Wownero node (much recommended)"), this); + m_localNodeCheck = new QCheckBox(tr("Run your own Wownero node (many recommended)"), this); m_localNodeCheck->setChecked(conf()->get(Config::runLocalNode).toBool()); auto *localNodeInfo = new QLabel( - tr("wowlet bundles its own node so you can be your own boss — and every node keeps the Wownero " - "network strong + decentralized. 🐕 Uncheck to use a remote node instead."), this); + tr("wowlet runs your own Wownero node by default: be your own boss and help run the network. " + "🐕 Uncheck to use a remote node instead."), this); localNodeInfo->setWordWrap(true); localNodeInfo->setStyleSheet("color: gray;");