QtPass 2.0.0
Developer documentation
Loading...
Searching...
No Matches
otpcodewidget.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
3
11
12#include "otpcodewidget.h"
14
15#include <QHBoxLayout>
16#include <QLabel>
17#include <QProgressBar>
18#include <QTimer>
19#include <utility>
20
21namespace {
22
24constexpr int kRefreshIntervalMs = 1000;
26constexpr int kProgressHeight = 18;
28constexpr int kProgressWidth = 52;
29
30} // namespace
31
32OtpCodeWidget::OtpCodeWidget(Totp::Settings settings, bool withCopyButton,
33 bool monospace, QWidget *parent)
34 : QWidget(parent), m_settings(std::move(settings)) {
35 // Same borderless look as the action buttons PasswordDisplayPanel builds.
36 const QString buttonStyle =
37 "QPushButton { border-style: none; background: transparent; padding: 0; "
38 "margin: 0; icon-size: 16px; color: inherit; }";
39
40 auto *layout = new QHBoxLayout(this);
41 layout->setContentsMargins(0, 0, 0, 0);
42 layout->setSpacing(4);
43
44 if (withCopyButton) {
45 m_copyButton = new QPushButtonWithClipboard(QString(), this);
46 m_copyButton->setStyleSheet(buttonStyle);
49 layout->addWidget(m_copyButton);
50 }
51
52 m_codeLabel = new QLabel(this);
53 m_codeLabel->setObjectName(QStringLiteral("OTP code"));
54 m_codeLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
55 if (monospace) {
56 m_codeLabel->setStyleSheet("QLabel { font-family: monospace; }");
57 }
58 layout->addWidget(m_codeLabel);
59 layout->addStretch();
60
61 m_progress = new QProgressBar(this);
62 m_progress->setObjectName(QStringLiteral("otpCountdown"));
63 m_progress->setRange(0, static_cast<int>(m_settings.step));
64 // Number-only format: no translatable string, and no unit to mistranslate.
65 m_progress->setFormat(QStringLiteral("%v"));
66 m_progress->setFixedWidth(kProgressWidth);
67 m_progress->setMaximumHeight(kProgressHeight);
68 m_progress->setToolTip(tr("Seconds until the OTP code changes"));
69 layout->addWidget(m_progress);
70
71 // The timer is a child of this widget: deleting the row stops it, so a
72 // queued timeout can never reach a destroyed label.
73 auto *timer = new QTimer(this);
74 timer->setInterval(kRefreshIntervalMs);
75 connect(timer, &QTimer::timeout, this,
76 [this]() { refresh(Totp::currentUnixTime()); });
77 timer->start();
78
80}
81
82void OtpCodeWidget::refresh(quint64 unixTime) {
83 const quint64 counter = Totp::counter(m_settings, unixTime);
84 if (!m_hasCode || counter != m_counter) {
85 m_counter = counter;
86 m_hasCode = true;
87 m_code = Totp::generate(m_settings, unixTime);
88 m_codeLabel->setText(m_code);
89 if (m_copyButton != nullptr) {
91 }
92 }
93
95 m_progress->setValue(static_cast<int>(m_secondsRemaining));
96}
97
98auto OtpCodeWidget::code() const -> QString { return m_code; }
99
101 return m_secondsRemaining;
102}
QString m_code
The code last rendered, ungrouped.
quint64 m_counter
Time-step counter m_code was generated for; a tick only regenerates when the counter changes.
QPushButtonWithClipboard * m_copyButton
Copy button, or nullptr when built without one; child widget whose text is kept equal to m_code.
void refresh(quint64 unixTime)
Recompute the code and countdown for an explicit point in time.
QProgressBar * m_progress
Countdown bar from step down to 1 second; child widget.
OtpCodeWidget(Totp::Settings settings, bool withCopyButton, bool monospace, QWidget *parent=nullptr)
Build a live OTP code display and start its refresh timer.
QLabel * m_codeLabel
Shows the current code; child widget.
uint m_secondsRemaining
Seconds left on m_code as of the last refresh().
void copyRequested(const QString &text)
Emitted when the copy button is activated.
auto code() const -> QString
The current code, ungrouped, exactly as it is copied.
bool m_hasCode
False until the first refresh(), which must generate a code regardless of m_counter.
auto secondsRemaining() const -> uint
Seconds left on the current code, as last rendered.
Totp::Settings m_settings
Validated TOTP parameters for the entry; fixed at construction.
void clicked(const QString &text)
Emitted when the button is activated with the stored text.
void setTextToCopy(const QString &value)
Update the stored text used for copying.
QPushButtonWithClipboard(QString textToCopy="", QWidget *parent=nullptr)
Construct a QPushButtonWithClipboard with an optional initial text.
static auto counter(const Settings &settings, quint64 unixTime) -> quint64
Time-step counter for a point in time.
Definition totp.cpp:205
static auto currentUnixTime() -> quint64
Current wall-clock time.
Definition totp.cpp:318
static auto generate(const Settings &settings, quint64 unixTime) -> QString
Generate the code for a given point in time.
Definition totp.cpp:214
static auto secondsRemaining(const Settings &settings, quint64 unixTime) -> uint
Seconds until the code for unixTime expires.
Definition totp.cpp:209
Self-refreshing widget showing an entry's current TOTP code with a countdown bar and optional copy bu...
Copy-to-clipboard icon button that carries the text of the field it sits next to.
Validated TOTP parameters. Only Totp::parse() produces one.
Definition totp.h:59
uint step
Period in seconds, 1..MAX_STEP.
Definition totp.h:65