diff --git a/NEXTCLOUD.cmake b/NEXTCLOUD.cmake index e9edb7b801ec..82f1bd4b7a5f 100644 --- a/NEXTCLOUD.cmake +++ b/NEXTCLOUD.cmake @@ -34,7 +34,8 @@ option( WITH_PROVIDERS "Build with providers list" ON ) ## Theming options -set( APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR "#0082c9" CACHE STRING "Hex color of the wizard header background") +set(NEXTCLOUD_BACKGROUND_COLOR "#0082c9" CACHE STRING "Default Nextcloud background color") +set( APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR ${NEXTCLOUD_BACKGROUND_COLOR} CACHE STRING "Hex color of the wizard header background") set( APPLICATION_WIZARD_HEADER_TITLE_COLOR "#ffffff" CACHE STRING "Hex color of the text in the wizard header") option( APPLICATION_WIZARD_USE_CUSTOM_LOGO "Use the logo from ':/client/theme/colored/wizard_logo.(png|svg)' else the default application icon is used" ON ) diff --git a/config.h.in b/config.h.in index d697887525dc..13d4cdf08c3a 100644 --- a/config.h.in +++ b/config.h.in @@ -25,6 +25,7 @@ #cmakedefine APPLICATION_SERVER_URL_ENFORCE "@APPLICATION_SERVER_URL_ENFORCE@" #cmakedefine LINUX_APPLICATION_ID "@LINUX_APPLICATION_ID@" #cmakedefine APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR "@APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR@" +#cmakedefine NEXTCLOUD_BACKGROUND_COLOR "@NEXTCLOUD_BACKGROUND_COLOR@" #cmakedefine APPLICATION_WIZARD_HEADER_TITLE_COLOR "@APPLICATION_WIZARD_HEADER_TITLE_COLOR@" #cmakedefine APPLICATION_WIZARD_USE_CUSTOM_LOGO "@APPLICATION_WIZARD_USE_CUSTOM_LOGO@" #cmakedefine APPLICATION_VIRTUALFILE_SUFFIX "@APPLICATION_VIRTUALFILE_SUFFIX@" diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 346114074f04..804e328ba736 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -51,6 +51,7 @@ set(client_UI_SRCS wizard/owncloudsetupnocredspage.ui wizard/owncloudwizardresultpage.ui wizard/webview.ui + wizard/welcomepage.ui ) set(client_SRCS @@ -134,6 +135,7 @@ set(client_SRCS wizard/webviewpage.cpp wizard/webview.cpp wizard/slideshow.cpp + wizard/welcomepage.cpp ) IF(BUILD_UPDATER) diff --git a/src/gui/owncloudsetupwizard.cpp b/src/gui/owncloudsetupwizard.cpp index ba7fecd2916e..2c964d5ced07 100644 --- a/src/gui/owncloudsetupwizard.cpp +++ b/src/gui/owncloudsetupwizard.cpp @@ -131,7 +131,12 @@ void OwncloudSetupWizard::startWizard() _ocWizard->setRemoteFolder(_remoteFolder); - _ocWizard->setStartId(WizardCommon::Page_ServerSetup); +#ifdef WITH_PROVIDERS + const auto startPage = WizardCommon::Page_Welcome; +#else // WITH_PROVIDERS + const auto startPage = WizardCommon::Page_ServerSetup; +#endif // WITH_PROVIDERS + _ocWizard->setStartId(startPage); _ocWizard->restart(); diff --git a/src/gui/wizard/owncloudwizard.cpp b/src/gui/wizard/owncloudwizard.cpp index d97b0b19fd50..4c57e96c1c67 100644 --- a/src/gui/wizard/owncloudwizard.cpp +++ b/src/gui/wizard/owncloudwizard.cpp @@ -20,6 +20,7 @@ #include "owncloudgui.h" #include "wizard/owncloudwizard.h" +#include "wizard/welcomepage.h" #include "wizard/owncloudsetuppage.h" #include "wizard/owncloudhttpcredspage.h" #include "wizard/owncloudoauthcredspage.h" @@ -46,6 +47,9 @@ Q_LOGGING_CATEGORY(lcWizard, "nextcloud.gui.wizard", QtInfoMsg) OwncloudWizard::OwncloudWizard(QWidget *parent) : QWizard(parent) , _account(nullptr) +#ifdef WITH_PROVIDERS + , _welcomePage(new WelcomePage(this)) +#endif // WITH_PROVIDERS , _setupPage(new OwncloudSetupPage(this)) , _httpCredsPage(new OwncloudHttpCredsPage(this)) , _browserCredsPage(new OwncloudOAuthCredsPage) @@ -57,6 +61,9 @@ OwncloudWizard::OwncloudWizard(QWidget *parent) setObjectName("owncloudWizard"); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); +#ifdef WITH_PROVIDERS + setPage(WizardCommon::Page_Welcome, _welcomePage); +#endif // WITH_PROVIDERS setPage(WizardCommon::Page_ServerSetup, _setupPage); setPage(WizardCommon::Page_HttpCreds, _httpCredsPage); setPage(WizardCommon::Page_OAuthCreds, _browserCredsPage); @@ -94,6 +101,12 @@ OwncloudWizard::OwncloudWizard(QWidget *parent) setSubTitleFormat(Qt::RichText); setButtonText(QWizard::CustomButton1, tr("Skip folders configuration")); + // Change the next buttons size policy since we hide it on the + // welcome page but want it to fill it's space that we don't get + // flickering when the page changes + auto nextButtonSizePolicy = button(QWizard::NextButton)->sizePolicy(); + nextButtonSizePolicy.setRetainSizeWhenHidden(true); + button(QWizard::NextButton)->setSizePolicy(nextButtonSizePolicy); // Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching) connect(this, &OwncloudWizard::styleChanged, _setupPage, &OwncloudSetupPage::slotStyleChanged); @@ -220,6 +233,29 @@ void OwncloudWizard::slotCurrentPageChanged(int id) { qCDebug(lcWizard) << "Current Wizard page changed to " << id; + const auto setNextButtonAsDefault = [this]() { + auto nextButton = qobject_cast(button(QWizard::NextButton)); + if (nextButton) { + nextButton->setDefault(true); + nextButton->setFocus(); + } + }; + + if (id == WizardCommon::Page_Welcome) { + // Set next button to just hidden so it retains it's layout + button(QWizard::NextButton)->setHidden(true); + // Need to set it from here, otherwise it has no effect + _welcomePage->setLoginButtonDefault(); + } else if (id == WizardCommon::Page_WebView || id == WizardCommon::Page_Flow2AuthCreds) { + setButtonLayout({ QWizard::Stretch, QWizard::BackButton }); + } else if (id == WizardCommon::Page_AdvancedSetup) { + setButtonLayout({ QWizard::Stretch, QWizard::CustomButton1, QWizard::BackButton, QWizard::NextButton }); + setNextButtonAsDefault(); + } else { + setButtonLayout({ QWizard::Stretch, QWizard::BackButton, QWizard::NextButton }); + setNextButtonAsDefault(); + } + if (id == WizardCommon::Page_ServerSetup) { emit clearPendingRequests(); } @@ -232,7 +268,6 @@ void OwncloudWizard::slotCurrentPageChanged(int id) done(Accepted); } - setOption(QWizard::HaveCustomButton1, id == WizardCommon::Page_AdvancedSetup); if (id == WizardCommon::Page_AdvancedSetup && (_credentialsPage == _browserCredsPage || _credentialsPage == _flow2CredsPage)) { // For OAuth, disable the back button in the Page_AdvancedSetup because we don't want // to re-open the browser. diff --git a/src/gui/wizard/owncloudwizard.h b/src/gui/wizard/owncloudwizard.h index 947d5f679ff2..3c6fb5c6e1f8 100644 --- a/src/gui/wizard/owncloudwizard.h +++ b/src/gui/wizard/owncloudwizard.h @@ -29,6 +29,7 @@ namespace OCC { Q_DECLARE_LOGGING_CATEGORY(lcWizard) +class WelcomePage; class OwncloudSetupPage; class OwncloudHttpCredsPage; class OwncloudOAuthCredsPage; @@ -115,6 +116,7 @@ public slots: void customizeStyle(); AccountPtr _account; + WelcomePage *_welcomePage; OwncloudSetupPage *_setupPage; OwncloudHttpCredsPage *_httpCredsPage; OwncloudOAuthCredsPage *_browserCredsPage; diff --git a/src/gui/wizard/owncloudwizardcommon.cpp b/src/gui/wizard/owncloudwizardcommon.cpp index 56768209bc99..4b019beaed76 100644 --- a/src/gui/wizard/owncloudwizardcommon.cpp +++ b/src/gui/wizard/owncloudwizardcommon.cpp @@ -16,6 +16,10 @@ #include #include #include +#include +#include +#include +#include #include "wizard/owncloudwizardcommon.h" #include "theme.h" @@ -68,6 +72,77 @@ namespace WizardCommon { errorLabel->setVisible(false); } + void customizeSpinBoxStyle(QSpinBox *spinBox) + { + auto spinBoxPalette = spinBox->palette(); +#ifdef Q_OS_WIN + // Windows always uses a SpinBox with a white background but we change the color of the text so we need + // to change the text color here + spinBoxPalette.setColor(QPalette::Text, Qt::black); + QColor colorTextDisabled(spinBoxPalette.color(QPalette::Text)); + colorTextDisabled.setAlpha(128); + spinBoxPalette.setColor(QPalette::Disabled, QPalette::Text, colorTextDisabled); +#endif +#ifdef Q_OS_LINUX + + spinBoxPalette.setColor(QPalette::WindowText, Theme::instance()->wizardHeaderBackgroundColor()); + QColor colorWindowTextDisabled(spinBoxPalette.color(QPalette::WindowText)); + colorWindowTextDisabled.setAlpha(128); + spinBoxPalette.setColor(QPalette::Disabled, QPalette::WindowText, colorWindowTextDisabled); +#endif + spinBox->setPalette(spinBoxPalette); + } + + void customizeSecondaryButtonStyle(QAbstractButton *button) + { +#ifdef Q_OS_LINUX + // Only style push buttons on Linux as on other platforms we are unable to style the background color + auto pushButtonPalette = button->palette(); + pushButtonPalette.setColor(QPalette::ButtonText, Theme::instance()->wizardHeaderTitleColor()); + pushButtonPalette.setColor(QPalette::Button, Theme::instance()->wizardHeaderBackgroundColor()); + button->setPalette(pushButtonPalette); +#endif + Q_UNUSED(button); + } + + void customizeLinkButtonStyle(QAbstractButton *button) + { + auto buttonPalette = button->palette(); + buttonPalette.setColor(QPalette::ButtonText, Theme::instance()->wizardHeaderTitleColor()); + button->setPalette(buttonPalette); + } + + void customizePrimaryButtonStyle(QAbstractButton *button) + { +#ifdef Q_OS_LINUX + // Only style push buttons on Linux as on other platforms we are unable to style the background color + auto pushButtonPalette = button->palette(); + + pushButtonPalette.setColor(QPalette::Button, Theme::instance()->wizardHeaderTitleColor()); + auto disabledButtonColor = pushButtonPalette.color(QPalette::Button); + disabledButtonColor.setAlpha(128); + pushButtonPalette.setColor(QPalette::Disabled, QPalette::Button, disabledButtonColor); + + pushButtonPalette.setColor(QPalette::ButtonText, Theme::instance()->wizardHeaderBackgroundColor()); + auto disabledButtonTextColor = pushButtonPalette.color(QPalette::ButtonText); + disabledButtonTextColor.setAlpha(128); + pushButtonPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledButtonTextColor); + + button->setPalette(pushButtonPalette); +#endif + Q_UNUSED(button); + } + + void customizeHintLabel(QLabel *label) + { + QColor textColor(Theme::instance()->wizardHeaderTitleColor()); + textColor.setAlpha(128); + + auto palette = label->palette(); + palette.setColor(QPalette::Text, textColor); + label->setPalette(palette); + } + } // ns WizardCommon } // namespace OCC diff --git a/src/gui/wizard/owncloudwizardcommon.h b/src/gui/wizard/owncloudwizardcommon.h index d1f7c08be07a..770a2aeff1f4 100644 --- a/src/gui/wizard/owncloudwizardcommon.h +++ b/src/gui/wizard/owncloudwizardcommon.h @@ -18,6 +18,10 @@ class QVariant; class QLabel; +class QRadioButton; +class QSpinBox; +class QCheckBox; +class QAbstractButton; namespace OCC { @@ -27,6 +31,11 @@ namespace WizardCommon { QString titleTemplate(); QString subTitleTemplate(); void initErrorLabel(QLabel *errorLabel); + void customizeSpinBoxStyle(QSpinBox *spinBox); + void customizeSecondaryButtonStyle(QAbstractButton *button); + void customizePrimaryButtonStyle(QAbstractButton *button); + void customizeLinkButtonStyle(QAbstractButton *button); + void customizeHintLabel(QLabel *label); enum SyncMode { SelectiveMode, @@ -34,6 +43,7 @@ namespace WizardCommon { }; enum Pages { + Page_Welcome, Page_ServerSetup, Page_HttpCreds, Page_ShibbolethCreds, diff --git a/src/gui/wizard/welcomepage.cpp b/src/gui/wizard/welcomepage.cpp new file mode 100644 index 000000000000..4d03a26236d1 --- /dev/null +++ b/src/gui/wizard/welcomepage.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2021 by Felix Weilbach + * + * 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 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include + +#include "welcomepage.h" +#include "theme.h" +#include "wizard/owncloudwizard.h" +#include "wizard/slideshow.h" + +namespace OCC { + +WelcomePage::WelcomePage(OwncloudWizard *ocWizard) + : QWizardPage() + , _ocWizard(ocWizard) +{ + setupUi(); +} + +void WelcomePage::setupUi() +{ + _ui.setupUi(this); + setupSlideShow(); + setupLoginButton(); + setupCreateAccountButton(); + setupHostYourOwnServerButton(); +} + +void WelcomePage::initializePage() +{ + customizeStyle(); +} + +void WelcomePage::setLoginButtonDefault(bool value) +{ + _ui.loginButton->setDefault(value); + _ui.loginButton->setFocus(); +} + +void WelcomePage::styleSlideShow() +{ + const auto backgroundColor = palette().window().color(); + _ui.slideShow->addSlide(Theme::hidpiFileName("wizard-nextcloud.png", backgroundColor), tr("Keep your data secure and under your control")); + _ui.slideShow->addSlide(Theme::hidpiFileName("wizard-files.png", backgroundColor), tr("Secure collaboration & file exchange")); + _ui.slideShow->addSlide(Theme::hidpiFileName("wizard-groupware.png", backgroundColor), tr("Easy-to-use web mail, calendaring & contacts")); + _ui.slideShow->addSlide(Theme::hidpiFileName("wizard-talk.png", backgroundColor), tr("Screensharing, online meetings & web conferences")); + + const auto theme = Theme::instance(); + const auto isDarkBackground = Theme::isDarkColor(backgroundColor); + _ui.slideShowNextButton->setIcon(theme->uiThemeIcon(QString("control-next.svg"), isDarkBackground)); + _ui.slideShowPreviousButton->setIcon(theme->uiThemeIcon(QString("control-prev.svg"), isDarkBackground)); +} + +void WelcomePage::setupSlideShow() +{ + connect(_ui.slideShow, &SlideShow::clicked, _ui.slideShow, &SlideShow::stopShow); + connect(_ui.slideShowNextButton, &QPushButton::clicked, _ui.slideShow, &SlideShow::nextSlide); + connect(_ui.slideShowPreviousButton, &QPushButton::clicked, _ui.slideShow, &SlideShow::prevSlide); +} + +void WelcomePage::setupLoginButton() +{ + const auto appName = Theme::instance()->appNameGUI(); + + _ui.loginButton->setText(tr("Log in to your %1").arg(appName)); + connect(_ui.loginButton, &QPushButton::clicked, this, [this](bool /*checked*/) { + _nextPage = WizardCommon::Page_ServerSetup; + _ocWizard->next(); + }); +} + +void WelcomePage::setupCreateAccountButton() +{ + connect(_ui.createAccountButton, &QPushButton::clicked, this, [this](bool /*checked*/) { + _ocWizard->setRegistration(true); + _nextPage = WizardCommon::Page_WebView; + _ocWizard->next(); + }); +} + +void WelcomePage::setupHostYourOwnServerButton() +{ + connect(_ui.hostYourOwnServerButton, &QPushButton::clicked, this, [] { + QDesktopServices::openUrl(QUrl("https://docs.nextcloud.com/server/latest/admin_manual/installation/#installation")); + }); +} + +int WelcomePage::nextId() const +{ + return _nextPage; +} + +void WelcomePage::customizeStyle() +{ + WizardCommon::customizeSecondaryButtonStyle(_ui.createAccountButton); + WizardCommon::customizePrimaryButtonStyle(_ui.loginButton); + WizardCommon::customizeLinkButtonStyle(_ui.hostYourOwnServerButton); + + styleSlideShow(); +} +} diff --git a/src/gui/wizard/welcomepage.h b/src/gui/wizard/welcomepage.h new file mode 100644 index 000000000000..8b1382d71226 --- /dev/null +++ b/src/gui/wizard/welcomepage.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 by Felix Weilbach + * + * 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 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#pragma once + +#include + +#include "ui_welcomepage.h" +#include "wizard/owncloudwizardcommon.h" + +namespace OCC { + +class OwncloudWizard; + +class WelcomePage : public QWizardPage +{ + Q_OBJECT + +public: + WelcomePage(OwncloudWizard *ocWizard); + int nextId() const override; + void initializePage() override; + void setLoginButtonDefault(bool value = true); + + Ui_WelcomePage _ui; + +private: + void setupUi(); + void customizeStyle(); + void styleSlideShow(); + void setupSlideShow(); + void setupLoginButton(); + void setupCreateAccountButton(); + void setupHostYourOwnServerButton(); + + OwncloudWizard *_ocWizard; + WizardCommon::Pages _nextPage = WizardCommon::Page_ServerSetup; +}; +} diff --git a/src/gui/wizard/welcomepage.ui b/src/gui/wizard/welcomepage.ui new file mode 100644 index 000000000000..d567cdd4a883 --- /dev/null +++ b/src/gui/wizard/welcomepage.ui @@ -0,0 +1,236 @@ + + + WelcomePage + + + + 0 + 0 + 500 + 500 + + + + + 0 + 0 + + + + Form + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 80 + + + + + + + + 0 + + + + + + 40 + 16777215 + + + + + + + false + + + false + + + true + + + + + + + + 12 + 75 + true + + + + + + + + + 40 + 16777215 + + + + + + + false + + + false + + + true + + + + + + + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Log in to your %1 + + + true + + + true + + + + + + + Create account with Provider + + + true + + + false + + + + + + + Host your own server + + + false + + + false + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + OCC::SlideShow + QWidget +
wizard/slideshow.h
+
+
+ + +
diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index be3bde5e6a5d..fbfdeed10873 100644 --- a/src/libsync/theme.cpp +++ b/src/libsync/theme.cpp @@ -246,6 +246,12 @@ QString Theme::themeImagePath(const QString &name, int size, bool sysTray) const } } +bool Theme::isHidpi(QPaintDevice *dev) +{ + const auto devicePixelRatio = dev ? dev->devicePixelRatio() : qApp->primaryScreen()->devicePixelRatio(); + return devicePixelRatio > 1; +} + QIcon Theme::uiThemeIcon(const QString &iconName, bool uiHasDarkBg) const { QString themeResBasePath = ":/client/theme/"; @@ -256,8 +262,7 @@ QIcon Theme::uiThemeIcon(const QString &iconName, bool uiHasDarkBg) const QString Theme::hidpiFileName(const QString &fileName, QPaintDevice *dev) { - qreal devicePixelRatio = dev ? dev->devicePixelRatio() : qApp->primaryScreen()->devicePixelRatio(); - if (devicePixelRatio <= 1.0) { + if (!Theme::isHidpi(dev)) { return fileName; } // try to find a 2x version @@ -274,6 +279,16 @@ QString Theme::hidpiFileName(const QString &fileName, QPaintDevice *dev) return fileName; } +QString Theme::hidpiFileName(const QString &iconName, const QColor &backgroundColor, QPaintDevice *dev) +{ + const auto isDarkBackground = Theme::isDarkColor(backgroundColor); + + const QString themeResBasePath = ":/client/theme/"; + const QString iconPath = themeResBasePath + (isDarkBackground ? "white/" : "black/") + iconName; + + return Theme::hidpiFileName(iconPath, dev); +} + #endif @@ -541,6 +556,29 @@ QColor Theme::wizardHeaderBackgroundColor() const return {APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR}; } +QPixmap Theme::wizardApplicationLogo(const QColor &backgroundColor) const +{ + if (!Theme::isBranded()) { + return QPixmap(Theme::hidpiFileName("wizard-nextcloud.png", backgroundColor)); + } +#ifdef APPLICATION_WIZARD_USE_CUSTOM_LOGO + const auto useSvg = shouldPreferSvg(); + const auto logoBasePath = QStringLiteral(":/client/theme/colored/wizard_logo"); + if (useSvg) { + const auto maxHeight = Theme::isHidpi() ? 200 : 100; + const auto maxWidth = 2 * maxHeight; + const auto icon = QIcon(logoBasePath + ".svg"); + const auto size = icon.actualSize(QSize(maxWidth, maxHeight)); + return icon.pixmap(size); + } else { + return QPixmap(hidpiFileName(logoBasePath + ".png")); + } +#else + const auto size = Theme::isHidpi() ?: 200 : 100; + return applicationIcon().pixmap(size); +#endif +} + QPixmap Theme::wizardHeaderLogo() const { #ifdef APPLICATION_WIZARD_USE_CUSTOM_LOGO @@ -673,6 +711,11 @@ QString Theme::versionSwitchOutput() const bool Theme::isDarkColor(const QColor &color) { + // We want light icons on Nextcloud blue + if (color == NEXTCLOUD_BACKGROUND_COLOR) { + return true; + } + // account for different sensitivity of the human eye to certain colors double treshold = 1.0 - (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255.0; return treshold > 0.5; diff --git a/src/libsync/theme.h b/src/libsync/theme.h index 394cb8930537..b33147041edd 100644 --- a/src/libsync/theme.h +++ b/src/libsync/theme.h @@ -132,6 +132,10 @@ class OWNCLOUDSYNC_EXPORT Theme : public QObject #ifndef TOKEN_AUTH_ONLY static QString hidpiFileName(const QString &fileName, QPaintDevice *dev = nullptr); + static QString hidpiFileName(const QString &iconName, const QColor &backgroundColor, QPaintDevice *dev = nullptr); + + static bool isHidpi(QPaintDevice *dev = nullptr); + /** * get an sync state icon */ @@ -231,6 +235,8 @@ class OWNCLOUDSYNC_EXPORT Theme : public QObject /** @return color for the setup wizard. */ virtual QColor wizardHeaderBackgroundColor() const; + virtual QPixmap wizardApplicationLogo(const QColor &backgroundColor = QColor("#ffffff")) const; + /** @return logo for the setup wizard. */ virtual QPixmap wizardHeaderLogo() const; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2297eb0da89e..9dcc1730de11 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(testutils STATIC syncenginetestutils.cpp pushnotificationstestutils.cpp + themeutils.cpp ) target_link_libraries(testutils PUBLIC ${APPLICATION_EXECUTABLE}sync Qt5::Test) @@ -54,6 +55,7 @@ nextcloud_add_test(LockedFiles) nextcloud_add_test(FolderWatcher) nextcloud_add_test(Capabilities) nextcloud_add_test(PushNotifications) +nextcloud_add_test(Theme) if( UNIX AND NOT APPLE ) nextcloud_add_test(InotifyWatcher) diff --git a/test/testtheme.cpp b/test/testtheme.cpp new file mode 100644 index 000000000000..52bc7b324d49 --- /dev/null +++ b/test/testtheme.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021 by Felix Weilbach + * + * 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 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include + +#include "theme.h" +#include "themeutils.h" + +class TestTheme : public QObject +{ + Q_OBJECT + +public: + TestTheme() + { + Q_INIT_RESOURCE(resources); + Q_INIT_RESOURCE(theme); + } + +private slots: + void testHidpiFileName_darkBackground_returnPathToWhiteIcon() + { + FakePaintDevice paintDevice; + const QColor backgroundColor("#000000"); + const QString iconName("icon-name"); + + const auto iconPath = OCC::Theme::hidpiFileName(iconName + ".png", backgroundColor, &paintDevice); + + QCOMPARE(iconPath, ":/client/theme/white/" + iconName + ".png"); + } + + void testHidpiFileName_lightBackground_returnPathToBlackIcon() + { + FakePaintDevice paintDevice; + const QColor backgroundColor("#ffffff"); + const QString iconName("icon-name"); + + const auto iconPath = OCC::Theme::hidpiFileName(iconName + ".png", backgroundColor, &paintDevice); + + QCOMPARE(iconPath, ":/client/theme/black/" + iconName + ".png"); + } + + void testHidpiFileName_hidpiDevice_returnHidpiIconPath() + { + FakePaintDevice paintDevice; + paintDevice.setHidpi(true); + const QColor backgroundColor("#000000"); + const QString iconName("wizard-files"); + + const auto iconPath = OCC::Theme::hidpiFileName(iconName + ".png", backgroundColor, &paintDevice); + + QCOMPARE(iconPath, ":/client/theme/white/" + iconName + "@2x.png"); + } + + void testIsDarkColor_nextcloudBlue_returnTrue() + { + const QColor color(0, 130, 201); + + const auto result = OCC::Theme::isDarkColor(color); + + QCOMPARE(result, true); + } + + void testIsDarkColor_lightColor_returnFalse() + { + const QColor color(255, 255, 255); + + const auto result = OCC::Theme::isDarkColor(color); + + QCOMPARE(result, false); + } + + void testIsDarkColor_darkColor_returnTrue() + { + const QColor color(0, 0, 0); + + const auto result = OCC::Theme::isDarkColor(color); + + QCOMPARE(result, true); + } + + void testIsHidpi_hidpi_returnTrue() + { + FakePaintDevice paintDevice; + paintDevice.setHidpi(true); + + QCOMPARE(OCC::Theme::isHidpi(&paintDevice), true); + } + + void testIsHidpi_lowdpi_returnFalse() + { + FakePaintDevice paintDevice; + paintDevice.setHidpi(false); + + QCOMPARE(OCC::Theme::isHidpi(&paintDevice), false); + } +}; + +QTEST_GUILESS_MAIN(TestTheme) +#include "testtheme.moc" diff --git a/test/themeutils.cpp b/test/themeutils.cpp new file mode 100644 index 000000000000..763d58a1f997 --- /dev/null +++ b/test/themeutils.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 by Felix Weilbach + * + * 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 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "themeutils.h" + +FakePaintDevice::FakePaintDevice() = default; + +QPaintEngine *FakePaintDevice::paintEngine() const +{ + return nullptr; +} + +void FakePaintDevice::setHidpi(bool value) +{ + _hidpi = value; +} + +int FakePaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + switch (metric) { + case QPaintDevice::PdmDevicePixelRatio: + if (_hidpi) { + return 2; + } + return 1; + default: + return QPaintDevice::metric(metric); + } +} diff --git a/test/themeutils.h b/test/themeutils.h new file mode 100644 index 000000000000..4e8327e54a14 --- /dev/null +++ b/test/themeutils.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) by Felix Weilbach + * + * 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 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#pragma once + +#include +#include + +class FakePaintDevice : public QPaintDevice +{ +public: + FakePaintDevice(); + + QPaintEngine *paintEngine() const override; + + void setHidpi(bool value); + +protected: + int metric(QPaintDevice::PaintDeviceMetric metric) const override; + +private: + bool _hidpi = false; +};