diff --git a/NEXTCLOUD.cmake b/NEXTCLOUD.cmake index e9edb7b80..82f1bd4b7 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 d69788752..13d4cdf08 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 346114074..13cde2ff9 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,8 @@ set(client_SRCS wizard/webviewpage.cpp wizard/webview.cpp wizard/slideshow.cpp + wizard/welcomepage.cpp + wizard/linklabel.cpp ) IF(BUILD_UPDATER) diff --git a/src/gui/owncloudsetupwizard.cpp b/src/gui/owncloudsetupwizard.cpp index ba7fecd29..2c964d5ce 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/linklabel.cpp b/src/gui/wizard/linklabel.cpp new file mode 100644 index 000000000..918e9dc7f --- /dev/null +++ b/src/gui/wizard/linklabel.cpp @@ -0,0 +1,58 @@ +/* + * 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 "linklabel.h" +#include "guiutility.h" + +namespace OCC { + +LinkLabel::LinkLabel(QWidget *parent) : QLabel(parent) +{ + +} + +void LinkLabel::setUrl(const QUrl &url) +{ + this->url = url; +} + +void LinkLabel::enterEvent(QEvent * /*event*/) +{ + setFontUnderline(true); + setCursor(Qt::PointingHandCursor); +} + +void LinkLabel::leaveEvent(QEvent * /*event*/) +{ + setFontUnderline(false); + setCursor(Qt::ArrowCursor); +} + +void LinkLabel::mouseReleaseEvent(QMouseEvent * /*event*/) +{ + if (url.isValid()) { + Utility::openBrowser(url); + } + + emit clicked(); +} + +void LinkLabel::setFontUnderline(bool value) +{ + auto labelFont = font(); + labelFont.setUnderline(value); + setFont(labelFont); +} + +} diff --git a/src/gui/wizard/linklabel.h b/src/gui/wizard/linklabel.h new file mode 100644 index 000000000..eb4ba0f81 --- /dev/null +++ b/src/gui/wizard/linklabel.h @@ -0,0 +1,46 @@ +/* + * 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 + +namespace OCC { + +class LinkLabel : public QLabel +{ + Q_OBJECT +public: + explicit LinkLabel(QWidget *parent = nullptr); + + void setUrl(const QUrl &url); + +signals: + void clicked(); + +protected: + void enterEvent(QEvent *event) override; + + void leaveEvent(QEvent *event) override; + + void mouseReleaseEvent(QMouseEvent *event) override; + +private: + void setFontUnderline(bool value); + + QUrl url; +}; + +} diff --git a/src/gui/wizard/owncloudwizard.cpp b/src/gui/wizard/owncloudwizard.cpp index d97b0b19f..4c57e96c1 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 947d5f679..3c6fb5c6e 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 @@ private: 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 56768209b..0f4735082 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,15 @@ namespace WizardCommon { errorLabel->setVisible(false); } + void customizeHintLabel(QLabel *label) + { + auto palette = label->palette(); + QColor textColor = palette.color(QPalette::Text); + textColor.setAlpha(128); + 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 d1f7c08be..eb68c9279 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,7 @@ namespace WizardCommon { QString titleTemplate(); QString subTitleTemplate(); void initErrorLabel(QLabel *errorLabel); + void customizeHintLabel(QLabel *label); enum SyncMode { SelectiveMode, @@ -34,6 +39,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 000000000..668c5b02f --- /dev/null +++ b/src/gui/wizard/welcomepage.cpp @@ -0,0 +1,120 @@ +/* + * 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 "welcomepage.h" +#include "theme.h" +#include "wizard/owncloudwizard.h" +#include "wizard/slideshow.h" +#include "ui_welcomepage.h" + +namespace OCC { + +WelcomePage::WelcomePage(OwncloudWizard *ocWizard) + : QWizardPage() + , _ui(new Ui::WelcomePage) + , _ocWizard(ocWizard) +{ + setupUi(); +} + +WelcomePage::~WelcomePage() = default; + +void WelcomePage::setupUi() +{ + _ui->setupUi(this); + setupSlideShow(); + setupLoginButton(); + setupCreateAccountButton(); + setupHostYourOwnServerLabel(); +} + +void WelcomePage::initializePage() +{ + customizeStyle(); +} + +void WelcomePage::setLoginButtonDefault() +{ + _ui->loginButton->setDefault(true); + _ui->loginButton->setFocus(); +} + +void WelcomePage::styleSlideShow() +{ + const auto theme = Theme::instance(); + const auto backgroundColor = palette().window().color(); + + const auto wizardNextcloudIconFileName = theme->isBranded() ? Theme::hidpiFileName("wizard-nextcloud.png", backgroundColor) + : Theme::hidpiFileName(":/client/theme/colored/wizard-nextcloud.png"); + const auto wizardFilesIconFileName = theme->isBranded() ? Theme::hidpiFileName("wizard-files.png", backgroundColor) + : Theme::hidpiFileName(":/client/theme/colored/wizard-files.png"); + const auto wizardGroupwareIconFileName = theme->isBranded() ? Theme::hidpiFileName("wizard-groupware.png", backgroundColor) + : Theme::hidpiFileName(":/client/theme/colored/wizard-groupware.png"); + const auto wizardTalkIconFileName = theme->isBranded() ? Theme::hidpiFileName("wizard-talk.png", backgroundColor) + : Theme::hidpiFileName(":/client/theme/colored/wizard-talk.png"); + + _ui->slideShow->addSlide(wizardNextcloudIconFileName, tr("Keep your data secure and under your control")); + _ui->slideShow->addSlide(wizardFilesIconFileName, tr("Secure collaboration & file exchange")); + _ui->slideShow->addSlide(wizardGroupwareIconFileName, tr("Easy-to-use web mail, calendaring & contacts")); + _ui->slideShow->addSlide(wizardTalkIconFileName, tr("Screensharing, online meetings & web conferences")); + + 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::setupHostYourOwnServerLabel() +{ + _ui->hostYourOwnServerLabel->setText(tr("Host your own server")); + _ui->hostYourOwnServerLabel->setAlignment(Qt::AlignCenter); + _ui->hostYourOwnServerLabel->setUrl(QUrl("https://docs.nextcloud.com/server/latest/admin_manual/installation/#installation")); +} + +int WelcomePage::nextId() const +{ + return _nextPage; +} + +void WelcomePage::customizeStyle() +{ + styleSlideShow(); +} +} diff --git a/src/gui/wizard/welcomepage.h b/src/gui/wizard/welcomepage.h new file mode 100644 index 000000000..9d0aa1c0a --- /dev/null +++ b/src/gui/wizard/welcomepage.h @@ -0,0 +1,54 @@ +/* + * 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 "wizard/owncloudwizardcommon.h" + +namespace OCC { + +class OwncloudWizard; + +namespace Ui { + class WelcomePage; +} + +class WelcomePage : public QWizardPage +{ + Q_OBJECT + +public: + explicit WelcomePage(OwncloudWizard *ocWizard); + ~WelcomePage() override; + int nextId() const override; + void initializePage() override; + void setLoginButtonDefault(); + +private: + void setupUi(); + void customizeStyle(); + void styleSlideShow(); + void setupSlideShow(); + void setupLoginButton(); + void setupCreateAccountButton(); + void setupHostYourOwnServerLabel(); + + QScopedPointer _ui; + + 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 000000000..1d54a8027 --- /dev/null +++ b/src/gui/wizard/welcomepage.ui @@ -0,0 +1,229 @@ + + + OCC::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 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + OCC::SlideShow + QWidget +
wizard/slideshow.h
+
+ + OCC::LinkLabel + QWidget +
wizard/linklabel.h
+ 1 +
+
+ + +
diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index be3bde5e6..b77a66655 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 +{ + if (!Theme::isBranded()) { + return QPixmap(Theme::hidpiFileName(":/client/theme/colored/wizard-nextcloud.png")); + } +#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 diff --git a/src/libsync/theme.h b/src/libsync/theme.h index 394cb8930..a06828b1f 100644 --- a/src/libsync/theme.h +++ b/src/libsync/theme.h @@ -132,6 +132,10 @@ public: #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 @@ public: /** @return color for the setup wizard. */ virtual QColor wizardHeaderBackgroundColor() const; + virtual QPixmap wizardApplicationLogo() const; + /** @return logo for the setup wizard. */ virtual QPixmap wizardHeaderLogo() const; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2297eb0da..9dcc1730d 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 000000000..52bc7b324 --- /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 000000000..763d58a1f --- /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 000000000..4e8327e54 --- /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; +};