Add central colour palette for widget states.

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.
This commit is contained in:
Janek Bevendorff 2020-04-11 17:01:50 +02:00
parent 2f12294639
commit 34483a1287
6 changed files with 142 additions and 26 deletions

View File

@ -88,6 +88,7 @@ set(keepassx_SOURCES
format/OpVaultReaderBandEntry.cpp format/OpVaultReaderBandEntry.cpp
format/OpVaultReaderSections.cpp format/OpVaultReaderSections.cpp
gui/styles/styles.qrc gui/styles/styles.qrc
gui/styles/StateColorPalette.cpp
gui/styles/base/phantomcolor.cpp gui/styles/base/phantomcolor.cpp
gui/styles/base/BaseStyle.cpp gui/styles/base/BaseStyle.cpp
gui/styles/dark/DarkStyle.cpp gui/styles/dark/DarkStyle.cpp

View File

@ -20,19 +20,15 @@
#include "core/Config.h" #include "core/Config.h"
#include "core/Resources.h" #include "core/Resources.h"
#include "gui/Application.h"
#include "gui/Font.h" #include "gui/Font.h"
#include "gui/PasswordGeneratorWidget.h" #include "gui/PasswordGeneratorWidget.h"
#include "gui/styles/StateColorPalette.h"
#include <QDialog> #include <QDialog>
#include <QVBoxLayout> #include <QVBoxLayout>
namespace 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 } // namespace
@ -147,9 +143,10 @@ void PasswordEdit::updateRepeatStatus()
const auto password = text(); const auto password = text();
if (otherPassword != password) { if (otherPassword != password) {
bool isCorrect = false; bool isCorrect = false;
QColor color = kpxcApp->isDarkTheme() ? ErrorColorDark : ErrorColor; StateColorPalette statePalette;
QColor color = statePalette.color(StateColorPalette::ColorRole::Error);
if (!password.isEmpty() && otherPassword.startsWith(password)) { if (!password.isEmpty() && otherPassword.startsWith(password)) {
color = kpxcApp->isDarkTheme() ? CorrectSoFarColorDark : CorrectSoFarColor; color = statePalette.color(StateColorPalette::ColorRole::Incomplete);
isCorrect = true; isCorrect = true;
} }
setStyleSheet(stylesheetTemplate.arg(color.name())); setStyleSheet(stylesheetTemplate.arg(color.name()));

View File

@ -27,8 +27,8 @@
#include "core/PasswordGenerator.h" #include "core/PasswordGenerator.h"
#include "core/PasswordHealth.h" #include "core/PasswordHealth.h"
#include "core/Resources.h" #include "core/Resources.h"
#include "gui/Application.h"
#include "gui/Clipboard.h" #include "gui/Clipboard.h"
#include "gui/styles/StateColorPalette.h"
PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
: QWidget(parent) : QWidget(parent)
@ -376,34 +376,28 @@ void PasswordGeneratorWidget::colorStrengthIndicator(const PasswordHealth& healt
QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption); QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption);
style.replace(re, "\\1 %1;"); style.replace(re, "\\1 %1;");
// Set the color and background based on entropy StateColorPalette statePalette;
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");
}
switch (health.quality()) { switch (health.quality()) {
case PasswordHealth::Quality::Bad: case PasswordHealth::Quality::Bad:
case PasswordHealth::Quality::Poor: 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"))); m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Poor", "Password quality")));
break; break;
case PasswordHealth::Quality::Weak: 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"))); m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Weak", "Password quality")));
break; break;
case PasswordHealth::Quality::Good: 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"))); m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Good", "Password quality")));
break; break;
case PasswordHealth::Quality::Excellent: 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"))); m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Excellent", "Password quality")));
break; break;
} }

View File

@ -23,10 +23,10 @@
#include "core/Group.h" #include "core/Group.h"
#include "core/PasswordHealth.h" #include "core/PasswordHealth.h"
#include "core/Resources.h" #include "core/Resources.h"
#include "gui/styles/StateColorPalette.h"
#include <QSharedPointer> #include <QSharedPointer>
#include <QStandardItemModel> #include <QStandardItemModel>
#include <QVector>
namespace namespace
{ {
@ -124,29 +124,30 @@ void ReportsWidgetHealthcheck::addHealthRow(QSharedPointer<PasswordHealth> healt
{ {
QString descr, tip; QString descr, tip;
QColor qualityColor; QColor qualityColor;
StateColorPalette statePalette;
const auto quality = health->quality(); const auto quality = health->quality();
switch (quality) { switch (quality) {
case PasswordHealth::Quality::Bad: case PasswordHealth::Quality::Bad:
descr = tr("Bad", "Password quality"); descr = tr("Bad", "Password quality");
tip = tr("Bad — password must be changed"); tip = tr("Bad — password must be changed");
qualityColor.setNamedColor("red"); qualityColor = statePalette.color(StateColorPalette::HealthCritical);
break; break;
case PasswordHealth::Quality::Poor: case PasswordHealth::Quality::Poor:
descr = tr("Poor", "Password quality"); descr = tr("Poor", "Password quality");
tip = tr("Poor — password should be changed"); tip = tr("Poor — password should be changed");
qualityColor.setNamedColor("orange"); qualityColor = statePalette.color(StateColorPalette::HealthBad);
break; break;
case PasswordHealth::Quality::Weak: case PasswordHealth::Quality::Weak:
descr = tr("Weak", "Password quality"); descr = tr("Weak", "Password quality");
tip = tr("Weak — consider changing the password"); tip = tr("Weak — consider changing the password");
qualityColor.setNamedColor("yellow"); qualityColor = statePalette.color(StateColorPalette::HealthWeak);
break; break;
case PasswordHealth::Quality::Good: case PasswordHealth::Quality::Good:
case PasswordHealth::Quality::Excellent: case PasswordHealth::Quality::Excellent:
qualityColor.setNamedColor("green"); qualityColor = statePalette.color(StateColorPalette::HealthOk);
break; break;
} }

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
*
* 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"));
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
*
* 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