[Client] Show latency in status bar and server tab indicator (#7154)

* [Client] Show live connection latency in the status bar

Add a permanent status-bar label fed by ConnectionController's
pingStatsUpdated: shows the latest round-trip time, hides while
disconnected or without samples, and carries a tooltip with
Last/Median/95th percentile/Maximum over the rolling sample window
(mirrored into the accessible description). The server tab gets the
same stats as its tooltip.

Took 2 minutes

Took 2 minutes

Took 1 minute

Took 48 seconds

Took 25 seconds

Took 4 minutes

* [Client] Graph connection latency history in the status bar

Add LatencyGraphWidget, a size-agnostic bar sparkline over the rolling
sample window: heights scale to the window's own range while colors map
onto an absolute quality ramp, so a steady good ping stays green. Embed
it in the new LatencyStatusWidget together with the textual ping
readout and feed both through ConnectionController's forwarded signals;
the whole area hides while disconnected or without samples.

Took 9 minutes

Took 14 seconds

* [Client] Show latency details when clicking the ping display

Clicking the status bar ping area opens a popup with a larger instance
of the latency graph plus the numeric statistics, selectable and
mirrored into the accessible name. Qt::Popup closes it on any outside
click; contents refresh live while open.


Took 33 seconds

* Fixup from core commit

Took 6 minutes

Took 5 seconds

Took 5 minutes

* Lint.

Took 12 minutes

* Consolidate.

Took 6 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-08-23 02:25:04 +02:00 committed by GitHub
parent fc0199d3db
commit 8a5723c0b5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 289 additions and 1 deletions

View file

@ -0,0 +1,51 @@
/**
* @file latency_graph_widget.cpp
* @ingroup Client
*/
#include "latency_graph_widget.h"
#include <QPainter>
LatencyGraphWidget::LatencyGraphWidget(QWidget *parent) : QWidget(parent)
{
}
void LatencyGraphWidget::setSamples(const QList<int> &samplesMs)
{
samples = samplesMs;
update();
}
void LatencyGraphWidget::paintEvent(QPaintEvent * /* event */)
{
if (samples.isEmpty()) {
return;
}
QPainter painter(this);
// Heights are relative to the window's own worst sample (floored at
// MinScaleMs) so the shape of the variance stays readable even when every
// value is small.
qint64 heightScaleMs = MinScaleMs;
for (int sample : samples) {
heightScaleMs = qMax(heightScaleMs, static_cast<qint64>(sample));
}
const qreal widthPerBar = static_cast<qreal>(width()) / samples.size();
for (int i = 0; i < samples.size(); ++i) {
const qreal heightRatio = qBound(0.0, static_cast<double>(samples.at(i)) / heightScaleMs, 1.0);
const qreal barHeight = heightRatio * height();
// Colors follow an absolute quality ramp: a steady good ping stays
// green no matter how uniform the window is.
const qreal colorRatio = qBound(0.0, static_cast<double>(samples.at(i)) / ColorScaleMs, 1.0);
QColor color;
color.setHsv(qRound(120.0 * (1.0 - colorRatio)), 255, 255);
const QRectF bar(static_cast<qreal>(i) * widthPerBar + 1.0, static_cast<qreal>(height()) - barHeight,
qMax(1.0, widthPerBar - 2.0), barHeight);
painter.fillRect(bar, color);
}
}