Skip to content

Commit

Permalink
Add central colour palette for widget states.
Browse files Browse the repository at this point in the history
Hard-coded widget state colours (error, warning, health etc.)
are replace by a central palette class, which also takes care
of determining if KeePassXC is in dark or light mode.

Colours expected to be used as background for normal text
were tested for WCAG level A compliance. Health colours were
adjusted for better harmony with the application theme and
tested for sufficient contrast with a colour blindness simulator.
  • Loading branch information
phoerious committed Apr 28, 2020
1 parent 2f12294 commit 34483a1
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 26 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ set(keepassx_SOURCES
format/OpVaultReaderBandEntry.cpp
format/OpVaultReaderSections.cpp
gui/styles/styles.qrc
gui/styles/StateColorPalette.cpp
gui/styles/base/phantomcolor.cpp
gui/styles/base/BaseStyle.cpp
gui/styles/dark/DarkStyle.cpp
Expand Down
11 changes: 4 additions & 7 deletions src/gui/PasswordEdit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,15 @@

#include "core/Config.h"
#include "core/Resources.h"
#include "gui/Application.h"
#include "gui/Font.h"
#include "gui/PasswordGeneratorWidget.h"
#include "gui/styles/StateColorPalette.h"

#include <QDialog>
#include <QVBoxLayout>

namespace
{
const QColor CorrectSoFarColor(255, 205, 15);
const QColor CorrectSoFarColorDark(115, 104, 46);
const QColor ErrorColor(255, 125, 125);
const QColor ErrorColorDark(128, 45, 45);

} // namespace

Expand Down Expand Up @@ -147,9 +143,10 @@ void PasswordEdit::updateRepeatStatus()
const auto password = text();
if (otherPassword != password) {
bool isCorrect = false;
QColor color = kpxcApp->isDarkTheme() ? ErrorColorDark : ErrorColor;
StateColorPalette statePalette;
QColor color = statePalette.color(StateColorPalette::ColorRole::Error);
if (!password.isEmpty() && otherPassword.startsWith(password)) {
color = kpxcApp->isDarkTheme() ? CorrectSoFarColorDark : CorrectSoFarColor;
color = statePalette.color(StateColorPalette::ColorRole::Incomplete);
isCorrect = true;
}
setStyleSheet(stylesheetTemplate.arg(color.name()));
Expand Down
22 changes: 8 additions & 14 deletions src/gui/PasswordGeneratorWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
#include "core/PasswordGenerator.h"
#include "core/PasswordHealth.h"
#include "core/Resources.h"
#include "gui/Application.h"
#include "gui/Clipboard.h"
#include "gui/styles/StateColorPalette.h"

PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
: QWidget(parent)
Expand Down Expand Up @@ -376,34 +376,28 @@ void PasswordGeneratorWidget::colorStrengthIndicator(const PasswordHealth& healt
QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption);
style.replace(re, "\\1 %1;");

// Set the color and background based on entropy
QList<QString> qualityColors;
if (kpxcApp->isDarkTheme()) {
qualityColors << QStringLiteral("#C43F31") << QStringLiteral("#DB9837") << QStringLiteral("#608A22")
<< QStringLiteral("#1F8023");
} else {
qualityColors << QStringLiteral("#C43F31") << QStringLiteral("#E09932") << QStringLiteral("#5EA10E")
<< QStringLiteral("#118f17");
}
StateColorPalette statePalette;
switch (health.quality()) {
case PasswordHealth::Quality::Bad:
case PasswordHealth::Quality::Poor:
m_ui->entropyProgressBar->setStyleSheet(style.arg(qualityColors[0]));
m_ui->entropyProgressBar->setStyleSheet(
style.arg(statePalette.color(StateColorPalette::HealthCritical).name()));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Poor", "Password quality")));
break;

case PasswordHealth::Quality::Weak:
m_ui->entropyProgressBar->setStyleSheet(style.arg(qualityColors[1]));
m_ui->entropyProgressBar->setStyleSheet(style.arg(statePalette.color(StateColorPalette::HealthBad).name()));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Weak", "Password quality")));
break;

case PasswordHealth::Quality::Good:
m_ui->entropyProgressBar->setStyleSheet(style.arg(qualityColors[2]));
m_ui->entropyProgressBar->setStyleSheet(style.arg(statePalette.color(StateColorPalette::HealthOk).name()));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Good", "Password quality")));
break;

case PasswordHealth::Quality::Excellent:
m_ui->entropyProgressBar->setStyleSheet(style.arg(qualityColors[3]));
m_ui->entropyProgressBar->setStyleSheet(
style.arg(statePalette.color(StateColorPalette::HealthExcellent).name()));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Excellent", "Password quality")));
break;
}
Expand Down
11 changes: 6 additions & 5 deletions src/gui/reports/ReportsWidgetHealthcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
#include "core/Group.h"
#include "core/PasswordHealth.h"
#include "core/Resources.h"
#include "gui/styles/StateColorPalette.h"

#include <QSharedPointer>
#include <QStandardItemModel>
#include <QVector>

namespace
{
Expand Down Expand Up @@ -124,29 +124,30 @@ void ReportsWidgetHealthcheck::addHealthRow(QSharedPointer<PasswordHealth> healt
{
QString descr, tip;
QColor qualityColor;
StateColorPalette statePalette;
const auto quality = health->quality();
switch (quality) {
case PasswordHealth::Quality::Bad:
descr = tr("Bad", "Password quality");
tip = tr("Bad — password must be changed");
qualityColor.setNamedColor("red");
qualityColor = statePalette.color(StateColorPalette::HealthCritical);
break;

case PasswordHealth::Quality::Poor:
descr = tr("Poor", "Password quality");
tip = tr("Poor — password should be changed");
qualityColor.setNamedColor("orange");
qualityColor = statePalette.color(StateColorPalette::HealthBad);
break;

case PasswordHealth::Quality::Weak:
descr = tr("Weak", "Password quality");
tip = tr("Weak — consider changing the password");
qualityColor.setNamedColor("yellow");
qualityColor = statePalette.color(StateColorPalette::HealthWeak);
break;

case PasswordHealth::Quality::Good:
case PasswordHealth::Quality::Excellent:
qualityColor.setNamedColor("green");
qualityColor = statePalette.color(StateColorPalette::HealthOk);
break;
}

Expand Down
57 changes: 57 additions & 0 deletions src/gui/styles/StateColorPalette.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 KeePassXC Team <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StateColorPalette.h"

#include "gui/Application.h"

StateColorPalette::StateColorPalette()
{
if (kpxcApp->isDarkTheme()) {
initDefaultPaletteDark();
} else {
initDefaultPaletteLight();
}
}

void StateColorPalette::initDefaultPaletteLight()
{
setColor(ColorRole::Error, QStringLiteral("#FF7D7D"));
setColor(ColorRole::Warning, QStringLiteral("#FFD30F"));
setColor(ColorRole::Info, QStringLiteral("#84D0E1"));
setColor(ColorRole::Incomplete, QStringLiteral("#FFD30F"));

setColor(ColorRole::HealthCritical, QStringLiteral("#C43F31"));
setColor(ColorRole::HealthBad, QStringLiteral("#E07F16"));
setColor(ColorRole::HealthWeak, QStringLiteral("#FFD30F"));
setColor(ColorRole::HealthOk, QStringLiteral("#5EA10E"));
setColor(ColorRole::HealthExcellent, QStringLiteral("#118f17"));
}

void StateColorPalette::initDefaultPaletteDark()
{
setColor(ColorRole::Error, QStringLiteral("#802D2D"));
setColor(ColorRole::Warning, QStringLiteral("#73682E"));
setColor(ColorRole::Info, QStringLiteral("#207183"));
setColor(ColorRole::Incomplete, QStringLiteral("#665124"));

setColor(ColorRole::HealthCritical, QStringLiteral("#C43F31"));
setColor(ColorRole::HealthBad, QStringLiteral("#DB9837"));
setColor(ColorRole::HealthWeak, QStringLiteral("#F0C400"));
setColor(ColorRole::HealthOk, QStringLiteral("#608A22"));
setColor(ColorRole::HealthExcellent, QStringLiteral("#1F8023"));
}
66 changes: 66 additions & 0 deletions src/gui/styles/StateColorPalette.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2020 KeePassXC Team <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef KEEPASSXC_STATECOLORPALETTE_H
#define KEEPASSXC_STATECOLORPALETTE_H

#include <QColor>
#include <QHash>
#include <QObject>

/**
* Extended color palette for indicating custom widget states.
*/
class StateColorPalette
{
Q_GADGET

public:
StateColorPalette();

enum ColorRole
{
Error,
Warning,
Info,
Incomplete,
HealthCritical,
HealthBad,
HealthPoor,
HealthWeak,
HealthOk,
HealthExcellent
};

inline void setColor(ColorRole role, const QColor& color)
{
m_colorMap[role] = color;
}

inline QColor color(ColorRole role) const
{
return m_colorMap.value(role);
}

private:
void initDefaultPaletteLight();
void initDefaultPaletteDark();

QHash<ColorRole, QColor> m_colorMap;
};

#endif // KEEPASSXC_STATECOLORPALETTE_H

0 comments on commit 34483a1

Please sign in to comment.