diff --git a/src/ui/windows/network_tab.cpp b/src/ui/windows/network_tab.cpp index cebbdb8..985b11b 100644 --- a/src/ui/windows/network_tab.cpp +++ b/src/ui/windows/network_tab.cpp @@ -6,6 +6,7 @@ #include "../../app.h" #include "../../config/settings.h" +#include "../../data/wallet_state.h" #include "../../util/i18n.h" #include "../../util/lite_server_probe.h" #include "../../wallet/lite_connection_service.h" @@ -18,6 +19,7 @@ #include "../../embedded/IconsMaterialDesign.h" #include "imgui.h" +#include #include #include #include @@ -84,6 +86,70 @@ void RenderLiteNetworkTab(App* app) Type().textColored(TypeStyle::Caption, OnSurfaceMedium(), TR("lite_net_intro")); ImGui::Spacing(); + // ── Connection + sync status panel ───────────────────────────────────────── + { + const WalletState& ws = app->state(); + const SyncInfo& sync = ws.sync; + const bool connected = ws.connected; + ImDrawList* sdl = ImGui::GetWindowDrawList(); + const float panelH = 56.0f * dp; + const float panelW = ImGui::GetContentRegionAvail().x; + const float pad2 = 12.0f * dp; + ImVec2 pMin = ImGui::GetCursorScreenPos(); + ImVec2 pMax(pMin.x + panelW, pMin.y + panelH); + GlassPanelSpec sspec; sspec.rounding = 8.0f * dp; + DrawGlassPanel(sdl, pMin, pMax, sspec); + + // Top row: status dot + connection label (left); in-use server + latency (right). + ImU32 dotCol; const char* connLabel; + if (!connected) { dotCol = OnSurfaceDisabled(); connLabel = TR("lite_net_disconnected"); } + else if (sync.syncing) { dotCol = Warning(); connLabel = TR("lite_net_syncing"); } + else { dotCol = Success(); connLabel = TR("lite_net_synced"); } + const float dotR = 5.0f * dp; + sdl->AddCircleFilled(ImVec2(pMin.x + pad2 + dotR, pMin.y + 17.0f * dp), dotR, dotCol); + sdl->AddText(sub2, sub2->LegacySize, ImVec2(pMin.x + pad2 + dotR * 2 + 8.0f * dp, pMin.y + 9.0f * dp), + OnSurface(), connLabel); + + std::string inUse = randomMode ? std::string(TR("lite_net_random_server")) + : (sticky.empty() ? std::string("—") : util::liteServerHost(sticky)); + if (!randomMode && !sticky.empty()) { + const auto it = probe.find(sticky); + if (it != probe.end() && it->second.online) + inUse += " · " + std::to_string(it->second.latencyMs) + "ms"; + } + const ImVec2 inUseSz = cap->CalcTextSizeA(cap->LegacySize, FLT_MAX, 0, inUse.c_str()); + sdl->AddText(cap, cap->LegacySize, ImVec2(pMax.x - pad2 - inUseSz.x, pMin.y + 12.0f * dp), + OnSurfaceMedium(), inUse.c_str()); + + // Bottom row: sync detail + (while syncing) a thin progress bar. + char syncBuf[96]; + if (!connected) + snprintf(syncBuf, sizeof(syncBuf), "%s: %s", TR("lite_net_sync_label"), TR("lite_net_no_wallet")); + else if (sync.syncing) + snprintf(syncBuf, sizeof(syncBuf), "%s: %.1f%% · %d / %d", TR("lite_net_sync_label"), + sync.verification_progress * 100.0, sync.blocks, sync.headers); + else + snprintf(syncBuf, sizeof(syncBuf), "%s: %s · block %d", TR("lite_net_sync_label"), + TR("lite_net_synced"), sync.blocks); + sdl->AddText(cap, cap->LegacySize, ImVec2(pMin.x + pad2, pMin.y + 32.0f * dp), + OnSurfaceMedium(), syncBuf); + if (connected && sync.syncing) { + const float barY = pMin.y + panelH - 6.0f * dp; + const float barX = pMin.x + pad2; + const float barW = panelW - pad2 * 2; + const float barH = 2.5f * dp; + const float pct = static_cast(std::max(0.0, std::min(1.0, sync.verification_progress))); + sdl->AddRectFilled(ImVec2(barX, barY), ImVec2(barX + barW, barY + barH), + WithAlpha(OnSurface(), 25), barH * 0.5f); + if (pct > 0) + sdl->AddRectFilled(ImVec2(barX, barY), ImVec2(barX + barW * pct, barY + barH), + Primary(), barH * 0.5f); + } + + ImGui::Dummy(ImVec2(panelW, panelH)); // reserve the panel (proper boundary growth) + ImGui::Spacing(); + } + bool useRandom = randomMode; if (ImGui::Checkbox(TR("lite_net_use_random"), &useRandom)) { st->setLiteServerSelectionMode(useRandom ? LiteMode::Random : LiteMode::Sticky); diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index e80f115..58c3627 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -1080,6 +1080,13 @@ void I18n::loadBuiltinEnglish() strings_["lite_net_unhide"] = "Unhide"; strings_["lite_net_show_hidden"] = "Show hidden servers"; strings_["lite_net_hidden_section"] = "Hidden servers"; + strings_["lite_net_connected"] = "Connected"; + strings_["lite_net_disconnected"] = "Not connected"; + strings_["lite_net_syncing"] = "Syncing"; + strings_["lite_net_synced"] = "Synced"; + strings_["lite_net_random_server"] = "Random server"; + strings_["lite_net_sync_label"] = "Sync"; + strings_["lite_net_no_wallet"] = "No wallet open"; // --- Peers Tab --- strings_["peers_avg_ping"] = "Avg Ping";