fix(ui): finish a stranded bootstrap even when its dialog is closed
A Settings bootstrap was only wrapped up inside the dialog's own draw path. If the dialog finished downloading, verifying or extracting while the user had clicked away or minimized the window, completion was never processed: the connect and reconcile gate stayed held and the post-bootstrap rescan was never armed. - Completion is now a pure decision driven from a pump() that both the per-frame update and the dialog's render call, so a finished bootstrap is handled every tick whether or not the dialog is drawn. - With the dialog open the behaviour is unchanged: it advances to the Done or Failed screen and those screens still own the gate. With the dialog closed, pump() releases the gate itself and shows a success or failure toast; a user-cancelled run is released silently. User-visible: a bootstrap started from Settings now completes, arms its rescan and reports its result even if the dialog is closed or the window is minimized when it finishes. Tests: the completion decision for an unfinished worker, a completed run with the dialog open and closed, a failed run, and a user-cancelled run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -89,6 +89,7 @@
|
||||
#include "util/daemon_updater.h"
|
||||
#include "util/http_download.h"
|
||||
#include "util/bootstrap.h"
|
||||
#include "ui/windows/bootstrap_completion.h"
|
||||
#include "util/background_sampler.h"
|
||||
#include "util/lite_server_probe.h"
|
||||
#include "util/wallet_file_probe.h"
|
||||
@@ -17667,6 +17668,46 @@ void testWriteFileIfDifferent()
|
||||
|
||||
removeTree(dir);
|
||||
}
|
||||
void testBootstrapCompletion()
|
||||
{
|
||||
using dragonx::ui::resolveBootstrapCompletion;
|
||||
using B = dragonx::util::Bootstrap;
|
||||
using N = dragonx::ui::BootstrapCompletion::Next;
|
||||
|
||||
// Worker not finished: nothing happens regardless of state/dialog.
|
||||
{
|
||||
auto c = resolveBootstrapCompletion(false, B::State::Extracting, false, false);
|
||||
EXPECT_TRUE(c.next == N::Pending);
|
||||
EXPECT_TRUE(!c.markRescan && !c.releaseGate && !c.toast);
|
||||
}
|
||||
// Completed, dialog open: rescan, but the dialog owns the gate/toast.
|
||||
{
|
||||
auto c = resolveBootstrapCompletion(true, B::State::Completed, true, false);
|
||||
EXPECT_TRUE(c.next == N::Done);
|
||||
EXPECT_TRUE(c.markRescan);
|
||||
EXPECT_TRUE(!c.releaseGate && !c.toast);
|
||||
}
|
||||
// Completed, dialog closed: we release the gate and toast the success.
|
||||
{
|
||||
auto c = resolveBootstrapCompletion(true, B::State::Completed, false, false);
|
||||
EXPECT_TRUE(c.next == N::Done);
|
||||
EXPECT_TRUE(c.markRescan && c.releaseGate && c.toast);
|
||||
}
|
||||
// Failed, dialog closed: release the gate and toast, but no rescan.
|
||||
{
|
||||
auto c = resolveBootstrapCompletion(true, B::State::Failed, false, false);
|
||||
EXPECT_TRUE(c.next == N::Failed);
|
||||
EXPECT_TRUE(!c.markRescan);
|
||||
EXPECT_TRUE(c.releaseGate && c.toast);
|
||||
}
|
||||
// User-cancelled, dialog closed: release the gate silently (no toast, no rescan).
|
||||
{
|
||||
auto c = resolveBootstrapCompletion(true, B::State::Failed, false, true);
|
||||
EXPECT_TRUE(c.next == N::Failed);
|
||||
EXPECT_TRUE(!c.markRescan && c.releaseGate && !c.toast);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
@@ -17800,6 +17841,7 @@ int main()
|
||||
testBootstrapPreflightKeepsOldChain();
|
||||
testBootstrapUserCancelWindow();
|
||||
testBootstrapQuitWait();
|
||||
testBootstrapCompletion();
|
||||
testWriteFileAtomic();
|
||||
testCopyFileAtomic();
|
||||
testBundleCopy();
|
||||
|
||||
Reference in New Issue
Block a user