Compare commits
3
Commits
5cfa713be1
...
7d2972f315
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d2972f315 | ||
|
|
8eee351faa | ||
|
|
09f39f9183 |
+28
-27
@@ -1584,28 +1584,28 @@ void App::updateWalletIndexForActiveWallet(bool markOpened)
|
||||
void App::switchToWallet(const std::string& walletFile, bool stopDaemonConfirmed, bool salvage)
|
||||
{
|
||||
if (!supportsFullNodeLifecycleActions()) {
|
||||
ui::Notifications::instance().warning("Full-node lifecycle actions are unavailable in lite build");
|
||||
ui::Notifications::instance().warning(TR("toast_lite_lifecycle_unavailable"));
|
||||
return;
|
||||
}
|
||||
if (walletFile.empty() || !settings_) return;
|
||||
if (settings_->getActiveWalletFile() == walletFile) {
|
||||
ui::Notifications::instance().info("That wallet is already open.");
|
||||
ui::Notifications::instance().info(TR("toast_wallet_already_open"));
|
||||
return;
|
||||
}
|
||||
if (daemon_restarting_) {
|
||||
ui::Notifications::instance().warning("The node is busy restarting — try again in a moment.");
|
||||
ui::Notifications::instance().warning(TR("toast_node_busy_restarting"));
|
||||
return;
|
||||
}
|
||||
// Don't race the other daemon-lifecycle operations. rescan/repair set state_.sync.rescanning; the
|
||||
// seed-migration flow drives its own daemon stop/start; an encryption restart sets daemon_restarting_.
|
||||
if (state_.sync.rescanning) {
|
||||
ui::Notifications::instance().warning("A rescan or repair is in progress — try again once it finishes.");
|
||||
ui::Notifications::instance().warning(TR("toast_rescan_in_progress"));
|
||||
return;
|
||||
}
|
||||
// W3-4: block switching while a migration is PENDING, not only while its dialog is open — closing
|
||||
// the dialog via "Later" mid-migration leaves the pending state but previously dropped this guard.
|
||||
if (show_seed_migration_ || (settings_ && settings_->getSeedMigrationPending())) {
|
||||
ui::Notifications::instance().warning("Finish or cancel the seed migration before switching wallets.");
|
||||
ui::Notifications::instance().warning(TR("toast_finish_migration_first"));
|
||||
return;
|
||||
}
|
||||
if (consolidation_.active()) {
|
||||
@@ -1613,11 +1613,11 @@ void App::switchToWallet(const std::string& walletFile, bool stopDaemonConfirmed
|
||||
return;
|
||||
}
|
||||
if (!isUsingEmbeddedDaemon()) {
|
||||
ui::Notifications::instance().warning("Switching wallets needs the embedded daemon — stop any external dragonxd first.");
|
||||
ui::Notifications::instance().warning(TR("toast_switch_needs_embedded"));
|
||||
return;
|
||||
}
|
||||
if (hasTransactionSendProgress()) {
|
||||
ui::Notifications::instance().warning("Finish or cancel the pending send before switching wallets.");
|
||||
ui::Notifications::instance().warning(TR("toast_finish_send_first"));
|
||||
return;
|
||||
}
|
||||
if (refuseIfNodeBusy()) return;
|
||||
@@ -2234,7 +2234,7 @@ void App::refreshCoreData(bool allowBalance)
|
||||
last_tx_block_height_ = -1;
|
||||
invalidateShieldedHistoryScanProgress(true);
|
||||
if (user_initiated_rescan_) {
|
||||
ui::Notifications::instance().success("Blockchain rescan complete");
|
||||
ui::Notifications::instance().success(TR("toast_rescan_complete"));
|
||||
user_initiated_rescan_ = false; // surfaced once; not for background rebuilds
|
||||
}
|
||||
}
|
||||
@@ -3517,7 +3517,7 @@ void App::startMining(int threads)
|
||||
{
|
||||
if (!supportsSoloMining()) {
|
||||
(void)threads;
|
||||
ui::Notifications::instance().warning("Solo mining is unavailable in lite build");
|
||||
ui::Notifications::instance().warning(TR("toast_solo_unavailable_lite"));
|
||||
return;
|
||||
}
|
||||
if (!state_.connected || !rpc_ || !worker_) return;
|
||||
@@ -3545,7 +3545,7 @@ void App::startMining(int threads)
|
||||
DEBUG_LOGF("Mining started with %d threads\n", threads);
|
||||
} else {
|
||||
DEBUG_LOGF("Failed to start mining: %s\n", errMsg.c_str());
|
||||
ui::Notifications::instance().error("Mining failed: " + errMsg);
|
||||
ui::Notifications::instance().error(std::string(TR("toast_mining_failed")) + util::friendlyRpcError(errMsg));
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -3577,7 +3577,7 @@ void App::stopMining()
|
||||
} else {
|
||||
// Don't silently leave generate=true as if it worked: tell the user and let the next
|
||||
// getmininginfo refresh reconcile the true daemon state. (M-07)
|
||||
ui::Notifications::instance().error("Failed to stop mining: " + errMsg);
|
||||
ui::Notifications::instance().error(std::string(TR("toast_stop_mining_failed")) + util::friendlyRpcError(errMsg));
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -3587,7 +3587,7 @@ void App::startPoolMining(int threads)
|
||||
{
|
||||
if (!supportsPoolMining()) {
|
||||
(void)threads;
|
||||
ui::Notifications::instance().warning("Pool mining is unavailable in this build");
|
||||
ui::Notifications::instance().warning(TR("toast_pool_unavailable"));
|
||||
return;
|
||||
}
|
||||
// Clamp to [1, logical cores] before the count reaches xmrig (M-06/M-08 pool path).
|
||||
@@ -3664,7 +3664,7 @@ void App::postPoolMinerJob(int threads, bool retargetOnly)
|
||||
|
||||
if (cfg.wallet_address.empty()) {
|
||||
DEBUG_LOGF("[ERROR] Pool mining: No wallet address available\n");
|
||||
ui::Notifications::instance().error("No wallet address available — generate a Z address in the Receive tab");
|
||||
ui::Notifications::instance().error(TR("toast_no_address_generate_z"));
|
||||
if (retargetOnly) stopPoolMining();
|
||||
return;
|
||||
}
|
||||
@@ -3707,7 +3707,7 @@ void App::postPoolMinerJob(int threads, bool retargetOnly)
|
||||
if (ok) {
|
||||
// Miner spawned — it still needs a few seconds to connect to the pool and start hashing.
|
||||
pool_starting_.store(true, std::memory_order_relaxed);
|
||||
ui::Notifications::instance().info("Starting pool miner — connecting to the pool…");
|
||||
ui::Notifications::instance().info(TR("toast_pool_connecting"));
|
||||
} else {
|
||||
DEBUG_LOGF("[ERROR] Pool mining: %s\n", err.c_str());
|
||||
// Windows Defender blocking (error 225 = ERROR_VIRUS_INFECTED)
|
||||
@@ -3718,7 +3718,7 @@ void App::postPoolMinerJob(int threads, bool retargetOnly)
|
||||
pending_antivirus_dialog_ = true;
|
||||
#endif
|
||||
} else {
|
||||
ui::Notifications::instance().error("Failed to start pool miner: " + err);
|
||||
ui::Notifications::instance().error(std::string(TR("toast_pool_start_failed")) + util::friendlyRpcError(err));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -3754,7 +3754,7 @@ void App::banPeer(const std::string& ip, int duration_seconds)
|
||||
err = e.what();
|
||||
}
|
||||
return [this, err]() {
|
||||
if (!err.empty()) ui::Notifications::instance().error("Ban failed: " + err);
|
||||
if (!err.empty()) ui::Notifications::instance().error(std::string(TR("toast_ban_failed")) + util::friendlyRpcError(err));
|
||||
else refreshPeerInfo();
|
||||
};
|
||||
});
|
||||
@@ -3772,7 +3772,7 @@ void App::unbanPeer(const std::string& ip)
|
||||
err = e.what();
|
||||
}
|
||||
return [this, err]() {
|
||||
if (!err.empty()) ui::Notifications::instance().error("Unban failed: " + err);
|
||||
if (!err.empty()) ui::Notifications::instance().error(std::string(TR("toast_unban_failed")) + util::friendlyRpcError(err));
|
||||
else refreshPeerInfo();
|
||||
};
|
||||
});
|
||||
@@ -3790,7 +3790,7 @@ void App::clearBans()
|
||||
err = e.what();
|
||||
}
|
||||
return [this, err]() {
|
||||
if (!err.empty()) { ui::Notifications::instance().error("Clear bans failed: " + err); return; }
|
||||
if (!err.empty()) { ui::Notifications::instance().error(std::string(TR("toast_clear_bans_failed")) + util::friendlyRpcError(err)); return; }
|
||||
state_.banned_peers.clear();
|
||||
refreshPeerInfo();
|
||||
};
|
||||
@@ -4101,7 +4101,7 @@ void App::exportPrivateKey(const std::string& address, std::function<void(const
|
||||
return [callback, key, err]() {
|
||||
if (!err.empty()) {
|
||||
DEBUG_LOGF("Export key error: %s\n", err.c_str());
|
||||
ui::Notifications::instance().error("Key export failed: " + err);
|
||||
ui::Notifications::instance().error(std::string(TR("toast_key_export_failed")) + util::friendlyRpcError(err));
|
||||
if (callback) callback("");
|
||||
} else if (callback) {
|
||||
callback(key);
|
||||
@@ -6657,7 +6657,7 @@ void App::beginAdoptSeedWallet()
|
||||
void App::restoreOriginalWallet()
|
||||
{
|
||||
if (!supportsFullNodeLifecycleActions()) {
|
||||
ui::Notifications::instance().warning("Full-node lifecycle actions are unavailable in lite build");
|
||||
ui::Notifications::instance().warning(TR("toast_lite_lifecycle_unavailable"));
|
||||
return;
|
||||
}
|
||||
if (daemon_restarting_) {
|
||||
@@ -6832,7 +6832,7 @@ bool App::walletRebuildAvailable() const { return !findWalletRebuildHelper().emp
|
||||
void App::rebuildWalletDatabase()
|
||||
{
|
||||
if (!supportsFullNodeLifecycleActions()) {
|
||||
ui::Notifications::instance().warning("Full-node lifecycle actions are unavailable in lite build");
|
||||
ui::Notifications::instance().warning(TR("toast_lite_lifecycle_unavailable"));
|
||||
return;
|
||||
}
|
||||
if (daemon_restarting_) { ui::Notifications::instance().warning(TR("wallet_restore_busy")); return; }
|
||||
@@ -7354,11 +7354,11 @@ void App::detectLowestAvailableBlockHeight(std::function<void(bool, int, bool)>
|
||||
bool App::runtimeRescan(int startHeight)
|
||||
{
|
||||
if (!supportsFullNodeLifecycleActions()) {
|
||||
ui::Notifications::instance().warning("Full-node lifecycle actions are unavailable in lite build");
|
||||
ui::Notifications::instance().warning(TR("toast_lite_lifecycle_unavailable"));
|
||||
return false;
|
||||
}
|
||||
if (!state_.connected || !rpc_ || !rpc_->isConnected() || !worker_) {
|
||||
ui::Notifications::instance().warning("Not connected to daemon");
|
||||
ui::Notifications::instance().warning(TR("toast_not_connected_daemon"));
|
||||
return false;
|
||||
}
|
||||
if (runtime_rescan_active_) return false;
|
||||
@@ -7395,8 +7395,9 @@ bool App::runtimeRescan(int startHeight)
|
||||
last_tx_block_height_ = -1;
|
||||
invalidateShieldedHistoryScanProgress(true);
|
||||
|
||||
ui::Notifications::instance().info("Rescanning blockchain from block " + std::to_string(startHeight) +
|
||||
" — this can take a while.");
|
||||
char rescanMsg[192];
|
||||
snprintf(rescanMsg, sizeof(rescanMsg), TR("toast_rescan_from_fmt"), static_cast<int>(startHeight));
|
||||
ui::Notifications::instance().info(rescanMsg);
|
||||
|
||||
const bool started = runLongWalletTask([this, startHeight](rpc::RPCClient& c) -> rpc::RPCWorker::MainCb {
|
||||
bool ok = false;
|
||||
@@ -7417,11 +7418,11 @@ bool App::runtimeRescan(int startHeight)
|
||||
noteWalletMutation();
|
||||
last_tx_block_height_ = -1;
|
||||
invalidateShieldedHistoryScanProgress(true);
|
||||
ui::Notifications::instance().success("Blockchain rescan complete");
|
||||
ui::Notifications::instance().success(TR("toast_rescan_complete"));
|
||||
refreshData();
|
||||
} else {
|
||||
state_.sync.rescan_progress = 0.0f;
|
||||
ui::Notifications::instance().error("Rescan failed: " + err);
|
||||
ui::Notifications::instance().error(std::string(TR("toast_rescan_failed")) + util::friendlyRpcError(err));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ WizardUiState s_wizardUi;
|
||||
void App::restartWizard()
|
||||
{
|
||||
if (!supportsFullNodeLifecycleActions()) {
|
||||
ui::Notifications::instance().warning("Lite wallet lifecycle requests are available from Settings as dry-run readiness checks");
|
||||
ui::Notifications::instance().warning(TR("toast_wizard_lite_unavailable"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -579,6 +579,9 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo&
|
||||
std::string curVer = s_live_miner_ver;
|
||||
if (curVer.empty()) curVer = app->poolMiningInstalledVersion();
|
||||
if (curVer.empty()) curVer = app->settings()->getXmrigVersion();
|
||||
// No miner installed at all → pool mining can't run. Make this a prominent
|
||||
// "Download miner" call-to-action instead of a subtle grey "Update" pill.
|
||||
const bool minerMissing = curVer.empty();
|
||||
// Version state: subtle GREEN + "xmrig releases" when up to date, subtle ORANGE +
|
||||
// "Update <latest>" when an update is available, neutral when either version is unknown.
|
||||
auto verNum = [](std::string s) -> std::vector<int> {
|
||||
@@ -609,7 +612,9 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo&
|
||||
const ImU32 subtleOrange = IM_COL32(214, 158, 74, 255);
|
||||
|
||||
char xbtn[64];
|
||||
if (upToDate)
|
||||
if (minerMissing)
|
||||
snprintf(xbtn, sizeof(xbtn), "%s", TR("xmrig_download_miner"));
|
||||
else if (upToDate)
|
||||
snprintf(xbtn, sizeof(xbtn), "%s", TR("xmrig_releases"));
|
||||
else if (!s_xmrig_latest_tag.empty())
|
||||
snprintf(xbtn, sizeof(xbtn), "%s %s", TR("xmrig_update_short"), s_xmrig_latest_tag.c_str());
|
||||
@@ -629,18 +634,21 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo&
|
||||
bool xhov = ImGui::IsItemHovered();
|
||||
bool xclk = ImGui::IsItemClicked();
|
||||
ImU32 xpill = minerBusy ? WithAlpha(OnSurface(), 12)
|
||||
: (xhov ? StateHover() : WithAlpha(OnSurface(), 28));
|
||||
: (minerMissing ? WithAlpha(Primary(), xhov ? 70 : 45)
|
||||
: (xhov ? StateHover() : WithAlpha(OnSurface(), 28)));
|
||||
dl->AddRectFilled(ImVec2(xbtnX, xbtnY), ImVec2(xbtnX + xbtnW, xbtnY + xbtnH),
|
||||
xpill, xbtnH * 0.3f);
|
||||
dl->AddText(capFont, capFont->LegacySize,
|
||||
ImVec2(xbtnX + xpadX, xbtnY + (xbtnH - xlblSz.y) * 0.5f),
|
||||
minerBusy ? OnSurfaceDisabled()
|
||||
: (upToDate ? subtleGreen : outdated ? subtleOrange : OnSurfaceMedium()),
|
||||
: (minerMissing ? Primary()
|
||||
: (upToDate ? subtleGreen : outdated ? subtleOrange : OnSurfaceMedium())),
|
||||
xbtn);
|
||||
if (xhov) {
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
material::Tooltip("%s", minerBusy ? TR("xmrig_stop_mining_first")
|
||||
: TR("xmrig_update_title"));
|
||||
: (minerMissing ? TR("xmrig_download_miner_tip")
|
||||
: TR("xmrig_update_title")));
|
||||
}
|
||||
if (xclk && !minerBusy) XmrigDownloadDialog::show(app);
|
||||
|
||||
|
||||
@@ -120,7 +120,10 @@ void RenderMiningModeToggle(App* app, const WalletState& state, const MiningInfo
|
||||
CancelMiningBenchmark(app, false); // don't leave a pool benchmark running after switching to solo (L-11)
|
||||
app->stopPoolMining();
|
||||
}
|
||||
if (soloHov) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (soloHov) {
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
material::Tooltip("%s", TR("mining_solo_tip"));
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SetCursorScreenPos(poolMin);
|
||||
@@ -136,6 +139,8 @@ void RenderMiningModeToggle(App* app, const WalletState& state, const MiningInfo
|
||||
if (soloMiningAvailable && poolHov && !soloMiningActive) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (poolHov && soloMiningActive && !s_pool_mode) {
|
||||
material::Tooltip("%s", TR("mining_stop_solo_for_pool"));
|
||||
} else if (poolHov && !soloMiningActive) {
|
||||
material::Tooltip("%s", TR("mining_pool_tip"));
|
||||
}
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(tMin.x, tMax.y));
|
||||
@@ -436,21 +441,51 @@ void RenderMiningModeToggle(App* app, const WalletState& state, const MiningInfo
|
||||
}
|
||||
}
|
||||
|
||||
// --- Worker: Bookmark button ---
|
||||
// --- Worker: Generate (when empty) / Bookmark button ---
|
||||
// A new wallet has no z-address, and a pool payout MUST be shielded. When the field is empty
|
||||
// show a one-click "generate a shielded address" button in place of the (useless-when-empty)
|
||||
// bookmark, instead of only a hover hint pointing at the Receive tab.
|
||||
ImGui::SameLine(0, 0);
|
||||
{
|
||||
std::string currentWorker(s_pool_worker);
|
||||
bool alreadySaved = miningValueAlreadySaved(app->settings()->getSavedPoolWorkers(), currentWorker);
|
||||
material::IconButtonStyle st;
|
||||
st.color = alreadySaved ? Primary() : OnSurfaceMedium();
|
||||
st.hoverBg = StateHover();
|
||||
st.bgRounding = 4.0f * dp;
|
||||
st.tooltip = alreadySaved ? TR("mining_already_saved") : TR("mining_save_payout_address");
|
||||
if (material::IconButton("##SaveWorkerAddr", alreadySaved ? ICON_MD_BOOKMARK : ICON_MD_BOOKMARK_BORDER,
|
||||
Type().iconSmall(), ImVec2(iconBtnW, inputFrameH2), st)
|
||||
&& !currentWorker.empty() && currentWorker != "x" && !alreadySaved) {
|
||||
app->settings()->addSavedPoolWorker(currentWorker);
|
||||
app->settings()->save();
|
||||
const bool noAddr = currentWorker.empty() || currentWorker == "x";
|
||||
if (noAddr) {
|
||||
material::IconButtonStyle st;
|
||||
st.color = Primary();
|
||||
st.hoverBg = StateHover();
|
||||
st.bgRounding = 4.0f * dp;
|
||||
st.tooltip = TR("mining_generate_z_address");
|
||||
if (material::IconButton("##GenZAddr", ICON_MD_ADD, Type().iconSmall(),
|
||||
ImVec2(iconBtnW, inputFrameH2), st)) {
|
||||
if (!app->isLiteBuild() && !app->isConnected()) {
|
||||
ui::Notifications::instance().warning(TR("toast_not_connected_daemon"));
|
||||
} else {
|
||||
char* wp = &s_pool_worker[0]; const size_t wn = sizeof(s_pool_worker);
|
||||
app->createNewZAddress([app, wp, wn](const std::string& addr) {
|
||||
if (addr.empty()) {
|
||||
ui::Notifications::instance().error(TR("mining_generate_z_failed"));
|
||||
return;
|
||||
}
|
||||
snprintf(wp, wn, "%s", addr.c_str()); // wp → the static s_pool_worker storage
|
||||
app->settings()->setPoolWorker(addr);
|
||||
app->settings()->save();
|
||||
ui::Notifications::instance().success(TR("mining_generate_z_ok"));
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool alreadySaved = miningValueAlreadySaved(app->settings()->getSavedPoolWorkers(), currentWorker);
|
||||
material::IconButtonStyle st;
|
||||
st.color = alreadySaved ? Primary() : OnSurfaceMedium();
|
||||
st.hoverBg = StateHover();
|
||||
st.bgRounding = 4.0f * dp;
|
||||
st.tooltip = alreadySaved ? TR("mining_already_saved") : TR("mining_save_payout_address");
|
||||
if (material::IconButton("##SaveWorkerAddr", alreadySaved ? ICON_MD_BOOKMARK : ICON_MD_BOOKMARK_BORDER,
|
||||
Type().iconSmall(), ImVec2(iconBtnW, inputFrameH2), st)
|
||||
&& !alreadySaved) {
|
||||
app->settings()->addSavedPoolWorker(currentWorker);
|
||||
app->settings()->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ static void DrawTxIcon(ImDrawList* dl, const std::string& type,
|
||||
} else if (type == "receive") {
|
||||
icon = ICON_MD_CALL_RECEIVED;
|
||||
} else if (type == "shield") {
|
||||
icon = ICON_MD_CALL_MADE;
|
||||
icon = ICON_MD_SHIELD; // a shield, not an outgoing arrow — it's an internal privacy move
|
||||
} else {
|
||||
icon = ICON_MD_CONSTRUCTION;
|
||||
}
|
||||
@@ -185,6 +185,9 @@ void RenderTransactionsTab(App* app)
|
||||
ImU32 greenCol = Success();
|
||||
ImU32 redCol = Error();
|
||||
ImU32 goldCol = Warning();
|
||||
// Neutral colour for a shielding move (your own funds going transparent→private): neither the
|
||||
// red of a spend nor the green of income, so a shield never reads as "money leaving".
|
||||
ImU32 shieldCol = schema::UI().resolveColor("var(--accent-shielded)", OnSurfaceMedium());
|
||||
std::string txLoadingText = app->transactionRefreshProgressText();
|
||||
bool txLoading = !txLoadingText.empty();
|
||||
|
||||
@@ -248,11 +251,9 @@ void RenderTransactionsTab(App* app)
|
||||
if (send_i >= 0 && recv_i >= 0) {
|
||||
isShieldLeg[send_i] = true;
|
||||
isShieldLeg[recv_i] = true;
|
||||
// The list shows the merged shield under the "Sent" filter, so count it there too —
|
||||
// otherwise the Sent card reads 0 while the Sent list is non-empty. Use the shielded
|
||||
// (receive-leg) amount, which is what the merged row displays.
|
||||
sendCount++;
|
||||
sendTotal += std::abs(state.transactions[recv_i].amount);
|
||||
// A shield moves your OWN funds transparent→private — it isn't a spend, so it is NOT
|
||||
// counted toward the Sent card/total (and no longer appears under the Sent filter).
|
||||
// It merges into one neutral "Shielded" row, visible under "All".
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,7 +544,7 @@ void RenderTransactionsTab(App* app)
|
||||
for (size_t i = 0; i < display_txns.size(); i++) {
|
||||
const auto& dtx = display_txns[i];
|
||||
if (type_filter != 0) {
|
||||
if (type_filter == 1 && dtx.display_type != "send" && dtx.display_type != "shield") continue;
|
||||
if (type_filter == 1 && dtx.display_type != "send") continue; // Sent = real spends; shields aren't sends
|
||||
if (type_filter == 2 && dtx.display_type != "receive") continue;
|
||||
if (type_filter == 3 && dtx.display_type != "generate" && dtx.display_type != "immature" && dtx.display_type != "mined") continue;
|
||||
if (type_filter == 4 && !chatStore.hasChatTxid(dtx.txid)) continue; // chat-only
|
||||
@@ -722,7 +723,7 @@ void RenderTransactionsTab(App* app)
|
||||
ImU32 iconCol;
|
||||
const char* typeStr;
|
||||
if (shieldedDisplay) {
|
||||
iconCol = redCol; typeStr = TR("sent_type");
|
||||
iconCol = shieldCol; typeStr = TR("shielded_self_type");
|
||||
} else if (tx.display_type == "receive") {
|
||||
iconCol = greenCol; typeStr = TR("recv_type");
|
||||
} else if (tx.display_type == "send") {
|
||||
@@ -750,7 +751,7 @@ void RenderTransactionsTab(App* app)
|
||||
float cy = rowPos.y + Layout::spacingMd();
|
||||
|
||||
// Icon
|
||||
DrawTxIcon(dl, shieldedDisplay ? "send" : tx.display_type,
|
||||
DrawTxIcon(dl, shieldedDisplay ? "shield" : tx.display_type,
|
||||
cx + rowIconSz, cy + body2->LegacySize * 0.5f, rowIconSz, iconCol);
|
||||
|
||||
// Type label
|
||||
@@ -769,7 +770,7 @@ void RenderTransactionsTab(App* app)
|
||||
OnSurfaceMedium(), addr_display.c_str());
|
||||
|
||||
// Amount (right-aligned, first line)
|
||||
ImU32 amtCol = (tx.amount >= 0) ? greenCol : redCol;
|
||||
ImU32 amtCol = shieldedDisplay ? shieldCol : ((tx.amount >= 0) ? greenCol : redCol);
|
||||
if (tx.amount >= 0)
|
||||
snprintf(buf, sizeof(buf), "+%.8f", tx.amount);
|
||||
else
|
||||
|
||||
@@ -1207,6 +1207,7 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["tx_chat_badge"] = "Message";
|
||||
strings_["recv_type"] = "Recv";
|
||||
strings_["sent_type"] = "Sent";
|
||||
strings_["shielded_self_type"] = "Shielded";
|
||||
strings_["immature_type"] = "Immature";
|
||||
strings_["mined_type"] = "Mined";
|
||||
strings_["mature"] = "Mature";
|
||||
@@ -1919,6 +1920,31 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["err_insufficient"] = "Not enough spendable balance to cover the amount and fee.";
|
||||
strings_["err_cant_reach"] = "Can't reach the node. Check that it's running and try again.";
|
||||
strings_["err_generic"] = "Something went wrong. Please try again.";
|
||||
// Node/wallet action toasts (were hardcoded English in app_network.cpp). The *_failed keys are
|
||||
// prefixes: the code appends a friendlyRpcError() detail after them.
|
||||
strings_["toast_lite_lifecycle_unavailable"] = "Full-node actions aren't available in the lite wallet.";
|
||||
strings_["toast_wallet_already_open"] = "That wallet is already open.";
|
||||
strings_["toast_node_busy_restarting"] = "The node is busy restarting — try again in a moment.";
|
||||
strings_["toast_rescan_in_progress"] = "A rescan or repair is in progress — try again once it finishes.";
|
||||
strings_["toast_finish_migration_first"] = "Finish or cancel the seed migration before switching wallets.";
|
||||
strings_["toast_switch_needs_embedded"] = "Switching wallets needs the embedded node — stop any external dragonxd first.";
|
||||
strings_["toast_finish_send_first"] = "Finish or cancel the pending send before switching wallets.";
|
||||
strings_["toast_rescan_complete"] = "Blockchain rescan complete.";
|
||||
strings_["toast_rescan_from_fmt"] = "Rescanning the blockchain from block %d — this can take a while.";
|
||||
strings_["toast_solo_unavailable_lite"] = "Solo mining isn't available in the lite wallet.";
|
||||
strings_["toast_pool_unavailable"] = "Pool mining isn't available in this build.";
|
||||
strings_["toast_no_address_generate_z"] = "No wallet address yet — generate a shielded (Z) address in the Receive tab.";
|
||||
strings_["toast_pool_connecting"] = "Starting pool miner — connecting to the pool…";
|
||||
strings_["toast_not_connected_daemon"] = "Not connected to the node.";
|
||||
strings_["toast_mining_failed"] = "Couldn't start mining: ";
|
||||
strings_["toast_stop_mining_failed"] = "Couldn't stop mining: ";
|
||||
strings_["toast_pool_start_failed"] = "Couldn't start the pool miner: ";
|
||||
strings_["toast_ban_failed"] = "Couldn't ban the peer: ";
|
||||
strings_["toast_unban_failed"] = "Couldn't unban the peer: ";
|
||||
strings_["toast_clear_bans_failed"] = "Couldn't clear bans: ";
|
||||
strings_["toast_key_export_failed"] = "Key export failed: ";
|
||||
strings_["toast_rescan_failed"] = "Rescan failed: ";
|
||||
strings_["toast_wizard_lite_unavailable"] = "Wallet setup actions aren't available in the lite wallet (see Settings for readiness checks).";
|
||||
strings_["console_capturing_output"] = "Capturing daemon output...";
|
||||
strings_["console_clear"] = "Clear";
|
||||
strings_["console_clear_console"] = "Clear Console";
|
||||
@@ -2263,6 +2289,9 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["validate_mining_type"] = "Mining address (transparent)";
|
||||
strings_["mining_est_daily_pool_sub"] = "rough solo-equivalent, before pool fee";
|
||||
strings_["mining_generate_z_address_hint"] = "Generate a Z address in the Receive tab to use as your payout address";
|
||||
strings_["mining_generate_z_address"] = "Generate a shielded payout address";
|
||||
strings_["mining_generate_z_ok"] = "Created a shielded payout address.";
|
||||
strings_["mining_generate_z_failed"] = "Couldn't create a shielded address — try the Receive tab.";
|
||||
strings_["mining_pool_needs_payout_tooltip"] = "Enter a payout address first (generate a Z address)";
|
||||
strings_["mining_pool"] = "Pool";
|
||||
strings_["mining_payout_foreign"] = "⚠ This payout address isn't in your current wallet — mined rewards would go to a different wallet. Update it if you switched wallets.";
|
||||
@@ -2302,6 +2331,8 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["mining_starting_tooltip"] = "Miner is starting...";
|
||||
strings_["mining_stop"] = "Stop";
|
||||
strings_["mining_stop_solo_for_pool"] = "Stop solo mining before starting pool mining";
|
||||
strings_["mining_solo_tip"] = "Solo: your node mines on its own. No pool fees, but a small CPU may wait a long time between rewards.";
|
||||
strings_["mining_pool_tip"] = "Pool: team up with other miners for smaller, more frequent payouts. Needs the DRG-XMRig miner and a shielded payout address.";
|
||||
strings_["mining_stop_solo_for_pool_settings"] = "Stop solo mining to change pool settings";
|
||||
strings_["mining_stopping"] = "Stopping...";
|
||||
strings_["mining_stopping_tooltip"] = "Miner is stopping...";
|
||||
@@ -2313,6 +2344,8 @@ void I18n::loadBuiltinEnglish()
|
||||
|
||||
// --- Miner (xmrig) updater ---
|
||||
strings_["xmrig_update_button"] = "Update miner…";
|
||||
strings_["xmrig_download_miner"] = "Download miner";
|
||||
strings_["xmrig_download_miner_tip"] = "Pool mining needs the DRG-XMRig miner. Click to download and install it.";
|
||||
strings_["xmrig_update_short"] = "Update";
|
||||
strings_["xmrig_releases"] = "xmrig releases";
|
||||
strings_["xmrig_current"] = "Current:";
|
||||
|
||||
Reference in New Issue
Block a user