feat(bootstrap,validate): Retry keeps the mirror; Validate works offline

- Bootstrap: Retry now reuses the source the user actually started (was always
  the default), and a "Try mirror" button offers the alternate server on
  failure (s_lastUrl remembered on start, cleared on a fresh Confirm).
- Validate Address: classification + checksum are local, so the dialog no
  longer requires a node connection — offline/lite now validate and show the
  type, with ownership reported as "Unknown — node offline / not checkable in
  the lite wallet" instead of a dead "not connected" screen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-18 13:05:40 -05:00
co-authored by Claude Opus 4.8
parent f3f0b32a48
commit 7cea9b7339
3 changed files with 29 additions and 15 deletions
+16 -14
View File
@@ -91,7 +91,8 @@ void ValidateAddressDialog::render(App* app)
ImGui::Spacing();
// Validate button
bool can_validate = strlen(s_address_input) > 0 && !s_validating && app->isConnected();
// Classification + checksum are LOCAL, so allow validating offline (the is-mine check needs the node).
bool can_validate = strlen(s_address_input) > 0 && !s_validating;
if (!can_validate) {
ImGui::BeginDisabled();
@@ -123,8 +124,9 @@ void ValidateAddressDialog::render(App* app)
s_address_type.clear();
s_validated = true;
s_validating = false;
} else if (app->isLiteBuild()) {
// Lite has no node to ask: the checksum verdict is the answer, ownership is unknown (hidden).
} else if (app->isLiteBuild() || !app->isConnected()) {
// No node to ask (lite, or full-node offline): the checksum verdict is the answer; ownership
// is unknown. The result block shows why.
s_is_valid = true;
s_is_mine = false;
s_ownership_known = false;
@@ -209,15 +211,17 @@ void ValidateAddressDialog::render(App* app)
ImGui::SameLine(lbl.position);
ImGui::Text("%s", s_address_type.c_str());
// Is mine? (not shown when no node was asked - lite)
if (s_ownership_known) {
ImGui::Text("%s", TR("validate_ownership"));
ImGui::SameLine(lbl.position);
if (s_is_mine) {
ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f), "%s", TR("validate_is_mine"));
} else {
ImGui::TextDisabled("%s", TR("validate_not_mine"));
}
// Is mine? When no node was asked (lite / offline) say why ownership is unknown rather
// than silently omitting it.
ImGui::Text("%s", TR("validate_ownership"));
ImGui::SameLine(lbl.position);
if (!s_ownership_known) {
ImGui::TextDisabled("%s", TR(app->isLiteBuild() ? "validate_ownership_unknown_lite"
: "validate_ownership_unknown_offline"));
} else if (s_is_mine) {
ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f), "%s", TR("validate_is_mine"));
} else {
ImGui::TextDisabled("%s", TR("validate_not_mine"));
}
if (s_is_mining) { // valid, but not for payments
ImGui::Spacing();
@@ -227,8 +231,6 @@ void ValidateAddressDialog::render(App* app)
}
}
}
} else if (!app->isConnected()) {
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), "%s", TR("not_connected"));
} else {
// Pre-interaction placeholder: keeps the results area from reading as a large
// dead gap between the Validate/Paste row and the Close button until a result exists.