QtPass Developer documentation
QtPass test coverage
Current view: top level - src/otpcodewidget.cpp (source / functions) Coverage Total Hit
Test: QtPass Lines: 98.0 % 50 49
Test Date: 2026-11-14 13:19:18 Functions: 100.0 % 5 5

            Line data    Source code
       1              : // SPDX-FileCopyrightText: 2026 Anne Jan Brouwer
       2              : // SPDX-License-Identifier: GPL-3.0-or-later
       3              : 
       4              : /**
       5              :  * @file
       6              :  * @brief Implements OtpCodeWidget: builds the code label, copy button and
       7              :  * countdown bar, and owns the one-second refresh timer.
       8              :  *
       9              :  * @see otpcodewidget.h
      10              :  */
      11              : 
      12              : #include "otpcodewidget.h"
      13              : #include "qpushbuttonwithclipboard.h"
      14              : 
      15              : #include <QHBoxLayout>
      16              : #include <QLabel>
      17              : #include <QProgressBar>
      18              : #include <QTimer>
      19              : #include <utility>
      20              : 
      21              : namespace {
      22              : 
      23              : /// Refresh cadence: the countdown is shown in whole seconds.
      24              : constexpr int kRefreshIntervalMs = 1000;
      25              : /// Matches the action-button visual height used elsewhere in the field rows.
      26              : constexpr int kProgressHeight = 18;
      27              : /// Enough for a three-digit countdown without the bar dominating the row.
      28              : constexpr int kProgressWidth = 52;
      29              : 
      30              : } // namespace
      31              : 
      32           15 : OtpCodeWidget::OtpCodeWidget(Totp::Settings settings, bool withCopyButton,
      33           15 :                              bool monospace, QWidget *parent)
      34           15 :     : 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           15 :       "margin: 0; icon-size: 16px; color: inherit; }";
      39              : 
      40           15 :   auto *layout = new QHBoxLayout(this);
      41           15 :   layout->setContentsMargins(0, 0, 0, 0);
      42           15 :   layout->setSpacing(4);
      43              : 
      44           15 :   if (withCopyButton) {
      45            6 :     m_copyButton = new QPushButtonWithClipboard(QString(), this);
      46            6 :     m_copyButton->setStyleSheet(buttonStyle);
      47            6 :     connect(m_copyButton, &QPushButtonWithClipboard::clicked, this,
      48            6 :             &OtpCodeWidget::copyRequested);
      49            6 :     layout->addWidget(m_copyButton);
      50              :   }
      51              : 
      52           15 :   m_codeLabel = new QLabel(this);
      53           30 :   m_codeLabel->setObjectName(QStringLiteral("OTP code"));
      54           15 :   m_codeLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
      55           15 :   if (monospace) {
      56            0 :     m_codeLabel->setStyleSheet("QLabel { font-family: monospace; }");
      57              :   }
      58           15 :   layout->addWidget(m_codeLabel);
      59           15 :   layout->addStretch();
      60              : 
      61           15 :   m_progress = new QProgressBar(this);
      62           30 :   m_progress->setObjectName(QStringLiteral("otpCountdown"));
      63           15 :   m_progress->setRange(0, static_cast<int>(m_settings.step));
      64              :   // Number-only format: no translatable string, and no unit to mistranslate.
      65           30 :   m_progress->setFormat(QStringLiteral("%v"));
      66           15 :   m_progress->setFixedWidth(kProgressWidth);
      67           15 :   m_progress->setMaximumHeight(kProgressHeight);
      68           15 :   m_progress->setToolTip(tr("Seconds until the OTP code changes"));
      69           15 :   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           15 :   auto *timer = new QTimer(this);
      74           15 :   timer->setInterval(kRefreshIntervalMs);
      75           15 :   connect(timer, &QTimer::timeout, this,
      76           15 :           [this]() { refresh(Totp::currentUnixTime()); });
      77           15 :   timer->start();
      78              : 
      79           15 :   refresh(Totp::currentUnixTime());
      80           15 : }
      81              : 
      82           20 : void OtpCodeWidget::refresh(quint64 unixTime) {
      83           20 :   const quint64 counter = Totp::counter(m_settings, unixTime);
      84           20 :   if (!m_hasCode || counter != m_counter) {
      85           20 :     m_counter = counter;
      86           20 :     m_hasCode = true;
      87           20 :     m_code = Totp::generate(m_settings, unixTime);
      88           20 :     m_codeLabel->setText(m_code);
      89           20 :     if (m_copyButton != nullptr) {
      90            7 :       m_copyButton->setTextToCopy(m_code);
      91              :     }
      92              :   }
      93              : 
      94           20 :   m_secondsRemaining = Totp::secondsRemaining(m_settings, unixTime);
      95           20 :   m_progress->setValue(static_cast<int>(m_secondsRemaining));
      96           20 : }
      97              : 
      98           10 : auto OtpCodeWidget::code() const -> QString { return m_code; }
      99              : 
     100            2 : auto OtpCodeWidget::secondsRemaining() const -> uint {
     101            2 :   return m_secondsRemaining;
     102              : }
        

Generated by: LCOV version 2.0-1