F3: the daemon connect loop retried forever with only an animated spinner when the daemon was reachable-but-never-ready (stuck in RPC warmup / -28, or an external daemon that never finishes init) -- no error, no guidance, no escape. It now stamps connect_stall_since_ the moment the daemon first goes "reachable but not ready" (the warmup branch + applyDaemonInitStatus) and clears it on connect / disconnect / warmup-complete. A pure, unit-testable util::connectHasStalled() helper (new util/connect_stall.h, 45s default from ui.toml [screens.loading].stall-timeout-sec) drives a "Taking longer than expected" notice in renderLoadingOverlay(): a title, a reassuring body with elapsed seconds, and a full-node hint to Settings > Restart Daemon or the Console. The background retry keeps running underneath, so the notice self-clears the instant it connects. Guarded off while the daemon is in State::Error (that case is owned by the existing crash-count hint). The overlay is a pure draw-list layer with no interactive widgets, so this follows the existing crash-hint idiom (guidance text, not injected buttons); the stalled state is computed locally in the overlay, so the only new App member is connect_stall_since_. Adds testConnectHasStalled to test_phase4.cpp and three i18n keys to i18n.cpp (English source of truth; the res/lang/*.json back-fill is deferred to a single add_missing_translations.py run at the end of the batch). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
28 lines
1.2 KiB
C++
28 lines
1.2 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
|
|
#pragma once
|
|
|
|
namespace dragonx {
|
|
namespace util {
|
|
|
|
// Default "taking longer than expected" threshold (seconds) for the daemon connect loop,
|
|
// overridable via ui.toml [screens.loading].stall-timeout-sec. Kept as a free function with
|
|
// no ImGui/App dependency so it is directly unit-testable from tests/test_phase4.cpp.
|
|
constexpr float kConnectStallDefaultSeconds = 45.0f;
|
|
|
|
// True once a daemon that is reachable-but-not-ready has stayed that way past the threshold.
|
|
// stallSince : timestamp (same clock as `now`) when the stall began; <= 0 means "not stalling".
|
|
// now : current time in the same units as stallSince.
|
|
// thresholdSec: how long to wait before considering it stalled; <= 0 disables the feature.
|
|
inline bool connectHasStalled(double stallSince, double now, float thresholdSec)
|
|
{
|
|
if (stallSince <= 0.0) return false; // not currently in a stall-tracked state
|
|
if (thresholdSec <= 0.0f) return false; // 0/negative disables the notice defensively
|
|
return (now - stallSince) >= static_cast<double>(thresholdSec);
|
|
}
|
|
|
|
} // namespace util
|
|
} // namespace dragonx
|