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..13cde2ff9b86 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/application.cpp b/src/gui/application.cpp index 2813ae45fe70..d23be5c145f2 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -338,9 +338,6 @@ Application::Application(int &argc, char **argv) FolderMan::instance()->setupFolders(); _proxy.setupQtProxyFromConfig(); // folders have to be defined first, than we set up the Qt proxy. - // Enable word wrapping of QInputDialog (#4197) - setStyleSheet("QInputDialog QLabel { qproperty-wordWrap:1; }"); - connect(AccountManager::instance(), &AccountManager::accountAdded, this, &Application::slotAccountStateAdded); connect(AccountManager::instance(), &AccountManager::accountRemoved, diff --git a/src/gui/owncloudsetupwizard.cpp b/src/gui/owncloudsetupwizard.cpp index ba7fecd2916e..51c727208a14 100644 --- a/src/gui/owncloudsetupwizard.cpp +++ b/src/gui/owncloudsetupwizard.cpp @@ -116,7 +116,7 @@ void OwncloudSetupWizard::startWizard() // if its a relative path, prepend with users home dir, otherwise use as absolute path if (!QDir(localFolder).isAbsolute()) { - localFolder = QDir::homePath() + QDir::separator() + localFolder; + localFolder = QDir::homePath() + QLatin1Char('/') + localFolder; } _ocWizard->setProperty("localFolder", localFolder); @@ -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/flow2authcredspage.cpp b/src/gui/wizard/flow2authcredspage.cpp index 33bced5837b8..e03b9a50faba 100644 --- a/src/gui/wizard/flow2authcredspage.cpp +++ b/src/gui/wizard/flow2authcredspage.cpp @@ -33,9 +33,6 @@ Flow2AuthCredsPage::Flow2AuthCredsPage() { _layout = new QVBoxLayout(this); - setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(Theme::instance()->appNameGUI()))); - setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Login in your browser (Login Flow v2)"))); - _flow2AuthWidget = new Flow2AuthWidget(); _layout->addWidget(_flow2AuthWidget); @@ -59,6 +56,8 @@ void Flow2AuthCredsPage::initializePage() // Don't hide the wizard (avoid user confusion)! //wizard()->hide(); + + _flow2AuthWidget->slotStyleChanged(); } void OCC::Flow2AuthCredsPage::cleanupPage() diff --git a/src/gui/wizard/flow2authwidget.cpp b/src/gui/wizard/flow2authwidget.cpp index 86a6ebb4ad9b..04b78d5cca83 100644 --- a/src/gui/wizard/flow2authwidget.cpp +++ b/src/gui/wizard/flow2authwidget.cpp @@ -17,6 +17,8 @@ #include "common/utility.h" #include "account.h" #include "wizard/owncloudwizardcommon.h" +#include "theme.h" +#include "linklabel.h" #include "QProgressIndicator.h" @@ -34,13 +36,23 @@ Flow2AuthWidget::Flow2AuthWidget(QWidget *parent) WizardCommon::initErrorLabel(_ui.errorLabel); _ui.errorLabel->setTextFormat(Qt::RichText); - connect(_ui.openLinkButton, &QCommandLinkButton::clicked, this, &Flow2AuthWidget::slotOpenBrowser); - connect(_ui.copyLinkButton, &QCommandLinkButton::clicked, this, &Flow2AuthWidget::slotCopyLinkToClipboard); + connect(_ui.openLinkLabel, &LinkLabel::clicked, this, &Flow2AuthWidget::slotOpenBrowser); + connect(_ui.copyLinkLabel, &LinkLabel::clicked, this, &Flow2AuthWidget::slotCopyLinkToClipboard); - _ui.horizontalLayout->addWidget(_progressIndi); + auto sizePolicy = _progressIndi->sizePolicy(); + sizePolicy.setRetainSizeWhenHidden(true); + _progressIndi->setSizePolicy(sizePolicy); + + _ui.progressLayout->addWidget(_progressIndi); stopSpinner(false); +} - customizeStyle(); +void Flow2AuthWidget::setLogo() +{ + const auto backgroundColor = palette().window().color(); + const auto logoIconFileName = Theme::instance()->isBranded() ? Theme::hidpiFileName("external.png", backgroundColor) + : Theme::hidpiFileName(":/client/theme/colored/external.png"); + _ui.logoLabel->setPixmap(logoIconFileName); } void Flow2AuthWidget::startAuth(Account *account) @@ -160,24 +172,24 @@ void Flow2AuthWidget::slotStatusChanged(Flow2Auth::PollStatus status, int second void Flow2AuthWidget::startSpinner() { - _ui.horizontalLayout->setEnabled(true); + _ui.progressLayout->setEnabled(true); _ui.statusLabel->setVisible(true); _progressIndi->setVisible(true); _progressIndi->startAnimation(); - _ui.openLinkButton->setEnabled(false); - _ui.copyLinkButton->setEnabled(false); + _ui.openLinkLabel->setEnabled(false); + _ui.copyLinkLabel->setEnabled(false); } void Flow2AuthWidget::stopSpinner(bool showStatusLabel) { - _ui.horizontalLayout->setEnabled(false); + _ui.progressLayout->setEnabled(false); _ui.statusLabel->setVisible(showStatusLabel); _progressIndi->setVisible(false); _progressIndi->stopAnimation(); - _ui.openLinkButton->setEnabled(_statusUpdateSkipCount == 0); - _ui.copyLinkButton->setEnabled(_statusUpdateSkipCount == 0); + _ui.openLinkLabel->setEnabled(_statusUpdateSkipCount == 0); + _ui.copyLinkLabel->setEnabled(_statusUpdateSkipCount == 0); } void Flow2AuthWidget::slotStyleChanged() @@ -187,8 +199,24 @@ void Flow2AuthWidget::slotStyleChanged() void Flow2AuthWidget::customizeStyle() { - if(_progressIndi) - _progressIndi->setColor(QGuiApplication::palette().color(QPalette::Text)); + setLogo(); + + if (_progressIndi) { + const auto isDarkBackground = Theme::isDarkColor(palette().window().color()); + if (isDarkBackground) { + _progressIndi->setColor(Qt::white); + } else { + _progressIndi->setColor(Qt::black); + } + } + + _ui.openLinkLabel->setText(tr("Reopen Browser")); + _ui.openLinkLabel->setAlignment(Qt::AlignCenter); + + _ui.copyLinkLabel->setText(tr("Copy Link")); + _ui.copyLinkLabel->setAlignment(Qt::AlignCenter); + + WizardCommon::customizeHintLabel(_ui.statusLabel); } } // namespace OCC diff --git a/src/gui/wizard/flow2authwidget.h b/src/gui/wizard/flow2authwidget.h index 8c13806b1258..90095c79c14c 100644 --- a/src/gui/wizard/flow2authwidget.h +++ b/src/gui/wizard/flow2authwidget.h @@ -60,6 +60,7 @@ protected slots: void startSpinner(); void stopSpinner(bool showStatusLabel); void customizeStyle(); + void setLogo(); QProgressIndicator *_progressIndi; int _statusUpdateSkipCount = 0; diff --git a/src/gui/wizard/flow2authwidget.ui b/src/gui/wizard/flow2authwidget.ui index 57f23186d814..44961ddae1a2 100644 --- a/src/gui/wizard/flow2authwidget.ui +++ b/src/gui/wizard/flow2authwidget.ui @@ -27,44 +27,138 @@ - - - Please switch to your browser to proceed. - - - true - - - - - - - An error occurred while connecting. Please try again. + + + Qt::Vertical - - Qt::PlainText + + QSizePolicy::Expanding - - - - - - Re-open Browser + + + 20 + 80 + - + - - - - 50 - false - + + + 0 - - Copy link + + 0 - + + + + Logo + + + Qt::AlignCenter + + + + + + + + 12 + 75 + true + + + + Switch to your browser to connect your account + + + Qt::AlignCenter + + + true + + + + + + + Status + + + Qt::AlignCenter + + + 0 + + + + + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + An error occurred while connecting. Please try again. + + + Qt::PlainText + + + Qt::AlignCenter + + + + + + + @@ -79,19 +173,6 @@ - - - - TextLabel - - - Qt::AlignCenter - - - - - - @@ -100,13 +181,21 @@ 20 - 107 + 80 + + + OCC::LinkLabel + QWidget +
wizard/linklabel.h
+ 1 +
+
diff --git a/src/gui/wizard/linklabel.cpp b/src/gui/wizard/linklabel.cpp new file mode 100644 index 000000000000..918e9dc7f91c --- /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 000000000000..eb4ba0f814c6 --- /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/owncloudadvancedsetuppage.cpp b/src/gui/wizard/owncloudadvancedsetuppage.cpp index b3d45bb6152f..9249ea45a282 100644 --- a/src/gui/wizard/owncloudadvancedsetuppage.cpp +++ b/src/gui/wizard/owncloudadvancedsetuppage.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "QProgressIndicator.h" @@ -32,27 +33,31 @@ #include #include "creds/abstractcredentials.h" #include "networkjobs.h" +#include "wizard/owncloudwizard.h" namespace OCC { -OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage() +OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage(OwncloudWizard *wizard) : QWizardPage() , _progressIndi(new QProgressIndicator(this)) + , _ocWizard(wizard) { _ui.setupUi(this); - Theme *theme = Theme::instance(); - setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(theme->appNameGUI()))); - setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Setup local folder options"))); + setupResoultionWidget(); registerField(QLatin1String("OCSyncFromScratch"), _ui.cbSyncFromScratch); + auto sizePolicy = _progressIndi->sizePolicy(); + sizePolicy.setRetainSizeWhenHidden(true); + _progressIndi->setSizePolicy(sizePolicy); + _ui.resultLayout->addWidget(_progressIndi); stopSpinner(); setupCustomization(); connect(_ui.pbSelectLocalFolder, &QAbstractButton::clicked, this, &OwncloudAdvancedSetupPage::slotSelectFolder); - setButtonText(QWizard::NextButton, tr("Connect …")); + setButtonText(QWizard::NextButton, tr("Connect")); connect(_ui.rSyncEverything, &QAbstractButton::clicked, this, &OwncloudAdvancedSetupPage::slotSyncEverythingClicked); connect(_ui.rSelectiveSync, &QAbstractButton::clicked, this, &OwncloudAdvancedSetupPage::slotSelectiveSyncClicked); @@ -65,13 +70,11 @@ OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage() }); connect(_ui.bSelectiveSync, &QAbstractButton::clicked, this, &OwncloudAdvancedSetupPage::slotSelectiveSyncClicked); - QIcon appIcon = theme->applicationIcon(); - _ui.lServerIcon->setText(QString()); - _ui.lServerIcon->setPixmap(appIcon.pixmap(48)); - _ui.lLocalIcon->setText(QString()); - - // TO DO: File doesn't exist anymore - unneccessary or replacement needed? - _ui.lLocalIcon->setPixmap(QPixmap(Theme::hidpiFileName(":/client/theme/folder-sync.png"))); + const auto theme = Theme::instance(); + const auto appIcon = theme->applicationIcon(); + const auto appIconSize = Theme::isHidpi() ? 128 : 64; + + _ui.lServerIcon->setPixmap(appIcon.pixmap(appIconSize)); if (theme->wizardHideExternalStorageConfirmationCheckbox()) { _ui.confCheckBoxExternal->hide(); @@ -106,6 +109,11 @@ void OwncloudAdvancedSetupPage::setupCustomization() variant = theme->customMedia(Theme::oCSetupBottom); WizardCommon::setupCustomMedia(variant, _ui.bottomLabel); + + WizardCommon::customizeHintLabel(_ui.lFreeSpace); + WizardCommon::customizeHintLabel(_ui.lSyncEverythingSizeLabel); + WizardCommon::customizeHintLabel(_ui.lSelectiveSyncSizeLabel); + WizardCommon::customizeHintLabel(_ui.serverAddressLabel); } bool OwncloudAdvancedSetupPage::isComplete() const @@ -158,6 +166,69 @@ void OwncloudAdvancedSetupPage::initializePage() _ui.confCheckBoxSize->setChecked(newFolderLimit.first); _ui.confSpinBox->setValue(newFolderLimit.second); _ui.confCheckBoxExternal->setChecked(cfgFile.confirmExternalStorage()); + + fetchUserAvatar(); + fetchUserData(); + + customizeStyle(); + + auto nextButton = qobject_cast(_ocWizard->button(QWizard::NextButton)); + if (nextButton) { + nextButton->setDefault(true); + } +} + +void OwncloudAdvancedSetupPage::fetchUserAvatar() +{ + // Reset user avatar + const auto appIcon = Theme::instance()->applicationIcon(); + _ui.lServerIcon->setPixmap(appIcon.pixmap(48)); + // Fetch user avatar + const auto account = _ocWizard->account(); + auto avatarSize = 64; + if (Theme::isHidpi()) { + avatarSize *= 2; + } + const auto avatarJob = new AvatarJob(account, account->davUser(), avatarSize, this); + avatarJob->setTimeout(20 * 1000); + QObject::connect(avatarJob, &AvatarJob::avatarPixmap, this, [this](const QImage &avatarImage) { + if (avatarImage.isNull()) { + return; + } + const auto avatarPixmap = QPixmap::fromImage(AvatarJob::makeCircularAvatar(avatarImage)); + _ui.lServerIcon->setPixmap(avatarPixmap); + }); + avatarJob->start(); +} + +void OwncloudAdvancedSetupPage::fetchUserData() +{ + const auto account = _ocWizard->account(); + + // Fetch user data + const auto userJob = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/user"), this); + userJob->setTimeout(20 * 1000); + connect(userJob, &JsonApiJob::jsonReceived, this, [this](const QJsonDocument &json) { + const auto objData = json.object().value("ocs").toObject().value("data").toObject(); + const auto displayName = objData.value("display-name").toString(); + _ui.userNameLabel->setText(displayName); + }); + userJob->start(); + + const auto serverUrl = account->url().toString(); + setServerAddressLabelUrl(serverUrl); + const auto userName = account->davDisplayName(); + _ui.userNameLabel->setText(userName); +} + +void OwncloudAdvancedSetupPage::setServerAddressLabelUrl(const QUrl &url) +{ + if (!url.isValid()) { + return; + } + + const auto prettyUrl = url.toString().mid(url.scheme().size() + 3); // + 3 because we need to remove :// + _ui.serverAddressLabel->setText(prettyUrl); } // Called if the user changes the user- or url field. Adjust the texts and @@ -172,7 +243,8 @@ void OwncloudAdvancedSetupPage::updateStatus() QString t; - _ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(locFolder)); + setLocalFolderPushButtonPath(locFolder); + if (dataChanged()) { if (_remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/")) { t = ""; @@ -185,20 +257,18 @@ void OwncloudAdvancedSetupPage::updateStatus() const bool dirNotEmpty(QDir(locFolder).entryList(QDir::AllEntries | QDir::NoDotAndDotDot).count() > 0); if (dirNotEmpty) { - t += tr("

Warning: The local folder is not empty. " - "Pick a resolution!

"); + t += tr("Warning: The local folder is not empty. Pick a resolution!"); } - _ui.resolutionWidget->setVisible(dirNotEmpty); + setResolutionGuiVisible(dirNotEmpty); } else { - _ui.resolutionWidget->setVisible(false); + setResolutionGuiVisible(false); } QString lfreeSpaceStr = Utility::octetsToString(availableLocalSpace()); - _ui.lFreeSpace->setText(QString(tr("Free space: %1")).arg(lfreeSpaceStr)); + _ui.lFreeSpace->setText(QString(tr("%1 free space", "%1 gets replaced with the size and a matching unit. Example: 3 MB or 5 GB")).arg(lfreeSpaceStr)); _ui.syncModeLabel->setText(t); _ui.syncModeLabel->setFixedHeight(_ui.syncModeLabel->sizeHint().height()); - wizard()->resize(wizard()->sizeHint()); qint64 rSpace = _ui.rSyncEverything->isChecked() ? _rSize : _rSelectedSize; @@ -211,6 +281,13 @@ void OwncloudAdvancedSetupPage::updateStatus() emit completeChanged(); } +void OwncloudAdvancedSetupPage::setResolutionGuiVisible(bool value) +{ + _ui.syncModeLabel->setVisible(value); + _ui.rKeepLocal->setVisible(value); + _ui.cbSyncFromScratch->setVisible(value); +} + /* obsolete */ bool OwncloudAdvancedSetupPage::dataChanged() { @@ -334,7 +411,7 @@ void OwncloudAdvancedSetupPage::slotSelectFolder() { QString dir = QFileDialog::getExistingDirectory(nullptr, tr("Local Sync Folder"), QDir::homePath()); if (!dir.isEmpty()) { - _ui.pbSelectLocalFolder->setText(dir); + setLocalFolderPushButtonPath(dir); wizard()->setProperty("localFolder", dir); updateStatus(); } @@ -344,6 +421,22 @@ void OwncloudAdvancedSetupPage::slotSelectFolder() setErrorString(errorStr); } + +void OwncloudAdvancedSetupPage::setLocalFolderPushButtonPath(const QString &path) +{ + const auto homeDir = QDir::homePath().endsWith('/') ? QDir::homePath() : QDir::homePath() + QLatin1Char('/'); + + if (!path.startsWith(homeDir)) { + _ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(path)); + return; + } + + auto prettyPath = path; + prettyPath.remove(0, homeDir.size()); + + _ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(prettyPath)); +} + void OwncloudAdvancedSetupPage::slotSelectiveSyncClicked() { AccountPtr acc = static_cast(wizard())->account(); @@ -384,6 +477,8 @@ void OwncloudAdvancedSetupPage::slotSelectiveSyncClicked() wizard()->setProperty("blacklist", _selectiveSyncBlacklist); } + updateStatus(); + }); dlg->open(); } @@ -439,8 +534,25 @@ void OwncloudAdvancedSetupPage::slotStyleChanged() void OwncloudAdvancedSetupPage::customizeStyle() { - if(_progressIndi) - _progressIndi->setColor(QGuiApplication::palette().color(QPalette::Text)); + if (_progressIndi) { + const auto isDarkBackground = Theme::isDarkColor(palette().window().color()); + if (isDarkBackground) { + _progressIndi->setColor(Qt::white); + } else { + _progressIndi->setColor(Qt::black); + } + } + + styleSyncLogo(); + styleLocalFolderLabel(); +} + +void OwncloudAdvancedSetupPage::styleLocalFolderLabel() +{ + const auto backgroundColor = palette().window().color(); + const auto folderIconFileName = Theme::instance()->isBranded() ? Theme::hidpiFileName("folder.png", backgroundColor) + : Theme::hidpiFileName(":/client/theme/colored/folder.png"); + _ui.lLocal->setPixmap(folderIconFileName); } void OwncloudAdvancedSetupPage::setRadioChecked(QRadioButton *radio) @@ -457,4 +569,24 @@ void OwncloudAdvancedSetupPage::setRadioChecked(QRadioButton *radio) _ui.rVirtualFileSync->setCheckable(false); } +void OwncloudAdvancedSetupPage::styleSyncLogo() +{ + const auto syncArrowIcon = Theme::createColorAwareIcon(QLatin1String(":/client/theme/sync-arrow.svg"), palette()); + _ui.syncLogoLabel->setPixmap(syncArrowIcon.pixmap(QSize(50, 50))); +} + +void OwncloudAdvancedSetupPage::setupResoultionWidget() +{ + for (int i = 0; i < _ui.resolutionWidgetLayout->count(); ++i) { + auto widget = _ui.resolutionWidgetLayout->itemAt(i)->widget(); + if (!widget) { + continue; + } + + auto sizePolicy = widget->sizePolicy(); + sizePolicy.setRetainSizeWhenHidden(true); + widget->setSizePolicy(sizePolicy); + } +} + } // namespace OCC diff --git a/src/gui/wizard/owncloudadvancedsetuppage.h b/src/gui/wizard/owncloudadvancedsetuppage.h index 7fcde225a716..8af948d9cc47 100644 --- a/src/gui/wizard/owncloudadvancedsetuppage.h +++ b/src/gui/wizard/owncloudadvancedsetuppage.h @@ -25,6 +25,8 @@ class QProgressIndicator; namespace OCC { +class OwncloudWizard; + /** * @brief The OwncloudAdvancedSetupPage class * @ingroup gui @@ -33,7 +35,7 @@ class OwncloudAdvancedSetupPage : public QWizardPage { Q_OBJECT public: - OwncloudAdvancedSetupPage(); + OwncloudAdvancedSetupPage(OwncloudWizard *wizard); bool isComplete() const override; void initializePage() override; @@ -73,6 +75,14 @@ private slots: qint64 availableLocalSpace() const; QString checkLocalSpace(qint64 remoteSize) const; void customizeStyle(); + void setServerAddressLabelUrl(const QUrl &url); + void setLocalFolderPushButtonPath(const QString &path); + void styleSyncLogo(); + void styleLocalFolderLabel(); + void setResolutionGuiVisible(bool value); + void setupResoultionWidget(); + void fetchUserAvatar(); + void fetchUserData(); Ui_OwncloudAdvancedSetupPage _ui; bool _checking = false; @@ -83,6 +93,7 @@ private slots: QStringList _selectiveSyncBlacklist; qint64 _rSize = -1; qint64 _rSelectedSize = -1; + OwncloudWizard *_ocWizard; }; } // namespace OCC diff --git a/src/gui/wizard/owncloudadvancedsetuppage.ui b/src/gui/wizard/owncloudadvancedsetuppage.ui index 3b3b688dd80f..075de08409c7 100644 --- a/src/gui/wizard/owncloudadvancedsetuppage.ui +++ b/src/gui/wizard/owncloudadvancedsetuppage.ui @@ -11,7 +11,7 @@ - + 0 0 @@ -48,7 +48,7 @@ Qt::Vertical - QSizePolicy::Fixed + QSizePolicy::Expanding @@ -59,9 +59,291 @@ - - - + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + Avatar + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + User name + + + Qt::AlignCenter + + + + + + + Server address + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + Sync Logo + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + &Local Folder + + + Qt::AlignCenter + + + pbSelectLocalFolder + + + + + + + + 75 + true + + + + Local Folder + + + Qt::AlignCenter + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 0 + 20 + + + + + + + + + 0 + 0 + + + + pbSelectLocalFolder + + + true + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 0 + 20 + + + + + + + + + + + 0 + 0 + + + + Free space + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal @@ -73,378 +355,428 @@ - - - - - 0 - - - 0 - - - + + + + + + QLayout::SetMinimumSize + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + 0 + + + + + 0 + + + 0 + + + + + 0 + + + + + Synchronize everything from server + + + true + + + + + + + Size + + + Qt::PlainText + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + Ask before syncing folders larger than + + + + + + + + 0 + 0 + + + + Qt::StrongFocus + + + 999999 + + + 99 + + + + + + + MB + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + Ask before syncing external storages + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + + + + false + + + + + + + Choose what to sync + + + true + + + false + + + + + + + TextLabel + + + Qt::PlainText + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + Use virtual files !PLACEHOLDER! + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + 6 + + + QLayout::SetMinimumSize + + + 0 + + + 2 + + + 0 + + + 0 + - - - S&ynchronize everything from server + + + + 0 + 0 + - - true + + + 9 + 75 + true + + + + 1 - - - - - TextLabel + Status message - Qt::PlainText + Qt::AutoText - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - Qt::Horizontal + + Qt::AlignCenter - - QSizePolicy::Minimum - - - - 10 - 20 - - - - - - - - - - Ask for confirmation before synchroni&zing folders larger than - - - - - - - 999999 - - - 99 - - - - - - - MB - - - - - - - - - Ask for confirmation before synchronizing e&xternal storages + + false - - - - - + - + 0 0 - - - - false - - - - - - - Choose what to sync - - - - - - - TextLabel + Keep local data - - Qt::PlainText + + true - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - + - + 0 0 + + <html><head/><body><p>If this box is checked, existing content in the local folder will be erased to start a clean sync from the server.</p><p>Do not check this if the local content should be uploaded to the servers folder.</p></body></html> + - Use &virtual files !PLACEHOLDER! + Erase local folder and start a clean sync - false + true - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - &Local Folder - - - Qt::AlignCenter - - - pbSelectLocalFolder - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 0 - - - - pbSelectLocalFolder - - - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - Server - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - 0 - 0 - - - - - QLayout::SetMinimumSize - - - QFormLayout::ExpandingFieldsGrow - - - - - &Keep local data - - - true - - - - - - - <html><head/><body><p>If this box is checked, existing content in the local folder will be erased to start a clean sync from the server.</p><p>Do not check this if the local content should be uploaded to the servers folder.</p></body></html> - - - Start a &clean sync (Erases the local folder!) - - - true - - - - - - - - + + - Qt::Vertical - - - QSizePolicy::MinimumExpanding + Qt::Horizontal - 20 - 40 + 40 + 20 - - - - TextLabel - - - - - - TextLabel + + + Qt::Vertical - + + QSizePolicy::Expanding + + + + 20 + 40 + + + - + - Status message - - - Qt::RichText - - - Qt::AlignCenter - - - true + TextLabel diff --git a/src/gui/wizard/owncloudsetupnocredspage.ui b/src/gui/wizard/owncloudsetupnocredspage.ui index d3e62595e06d..d67873450da9 100644 --- a/src/gui/wizard/owncloudsetupnocredspage.ui +++ b/src/gui/wizard/owncloudsetupnocredspage.ui @@ -6,12 +6,12 @@ 0 0 - 802 - 629 + 556 + 489 - + 0 0 @@ -27,102 +27,84 @@ - + + + TextLabel + + + + + Qt::Vertical - QSizePolicy::MinimumExpanding + QSizePolicy::Expanding 20 - 20 + 80 - - - - 0 - 0 - - - - TextLabel - - - Qt::RichText - - - Qt::AlignCenter - - - true + + + 0 - - - - - - - - 40 - 0 - + + + Qt::Horizontal - + - 40 - 16777215 + 0 + 0 - - - - - true - - + - - - - 12 - 75 - true - + + + Logo - - - - 40 - 0 - + + + Qt::Horizontal - + - 40 - 16777215 + 0 + 0 - - - - - true - - + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 0 + 0 + + + + @@ -143,38 +125,28 @@ + + 0 + QLayout::SetDefaultConstraint - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 40 - 0 - - - - + + 6 + Qt::Vertical - QSizePolicy::MinimumExpanding + QSizePolicy::Minimum - 20 + 0 0 @@ -182,73 +154,138 @@ + + 0 + - - - - 0 - 0 - + + + Qt::Horizontal - - Server Address + + + 0 + 0 + - - leUrl + + + + + + + 12 + 75 + true + + + + Server address - - - - 0 - 0 - + + + Qt::Horizontal - - + + + 0 + 0 + - + + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 80 + 0 + + + - - + + + 8 + + 0 + + + + + 0 + 0 + + + + + 200 + 0 + + + + https://try.nextcloud.com + + + + + + + + 0 + 0 + + + + This is the link to your %1 web interface when you open it in the browser. + + + Qt::AlignCenter + + + true + + + - - - - 0 - 0 - + + + Qt::Horizontal + + + QSizePolicy::Expanding - + - 24 - 24 + 80 + 0 - - - - + - - - - This is the link to your %1 web interface when you open it in the browser.<br/>It looks like https://cloud.example.com or https://example.com/cloud - - - true - - - @@ -268,6 +305,9 @@ + + + @@ -278,7 +318,7 @@ - 20 + 0 0 @@ -286,22 +326,6 @@ - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 40 - 0 - - - - @@ -317,163 +341,26 @@ - 20 - 20 + 0 + 0 - - - 6 - - - 20 + + + TextLabel - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 150 - 0 - - - - false - - - Sign up with a provider - - - false - - - - - - - - 0 - 0 - - - - - 150 - 0 - - - - Log in to your %1 - - - false - - - true - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + 0 - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - <a href="https://docs.nextcloud.com/server/latest/admin_manual/installation/#installation"><span style=" text-decoration: underline; color:#7a7a7a;">Host your own server</span></a> - - - true - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - TextLabel - - - Qt::RichText - - - @@ -482,11 +369,6 @@ QLineEdit
wizard/postfixlineedit.h
- - OCC::SlideShow - QWidget -
wizard/slideshow.h
-
diff --git a/src/gui/wizard/owncloudsetuppage.cpp b/src/gui/wizard/owncloudsetuppage.cpp index eff655e000c3..800d965d65df 100644 --- a/src/gui/wizard/owncloudsetuppage.cpp +++ b/src/gui/wizard/owncloudsetuppage.cpp @@ -45,10 +45,9 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent) { _ui.setupUi(this); - Theme *theme = Theme::instance(); - setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(theme->appNameGUI()))); - setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Setup %1 server").arg(theme->appNameGUI()))); + setupServerAddressDescriptionLabel(); + Theme *theme = Theme::instance(); if (theme->overrideServerUrl().isEmpty()) { _ui.leUrl->setPostfix(theme->wizardUrlPostfix()); _ui.leUrl->setPlaceholderText(theme->wizardUrlHint()); @@ -59,7 +58,11 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent) registerField(QLatin1String("OCUrl*"), _ui.leUrl); - _ui.resultLayout->addWidget(_progressIndi); + auto sizePolicy = _progressIndi->sizePolicy(); + sizePolicy.setRetainSizeWhenHidden(true); + _progressIndi->setSizePolicy(sizePolicy); + + _ui.progressLayout->addWidget(_progressIndi); stopSpinner(); setupCustomization(); @@ -70,35 +73,17 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent) addCertDial = new AddCertificateDialog(this); connect(addCertDial, &QDialog::accepted, this, &OwncloudSetupPage::slotCertificateAccepted); +} -#ifdef WITH_PROVIDERS - connect(_ui.loginButton, &QPushButton::clicked, this, &OwncloudSetupPage::slotLogin); - connect(_ui.createAccountButton, &QPushButton::clicked, this, &OwncloudSetupPage::slotGotoProviderList); - - _ui.login->hide(); - _ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-nextcloud.png"), tr("Keep your data secure and under your control")); - _ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-files.png"), tr("Secure collaboration & file exchange")); - _ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-groupware.png"), tr("Easy-to-use web mail, calendaring & contacts")); - _ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-talk.png"), tr("Screensharing, online meetings & web conferences")); - - connect(_ui.slideShow, &SlideShow::clicked, _ui.slideShow, &SlideShow::stopShow); - connect(_ui.nextButton, &QPushButton::clicked, _ui.slideShow, &SlideShow::nextSlide); - connect(_ui.prevButton, &QPushButton::clicked, _ui.slideShow, &SlideShow::prevSlide); - - _ui.slideShow->startShow(); -#else - _ui.createAccountButton->hide(); - _ui.loginButton->hide(); - _ui.installLink->hide(); - _ui.slideShow->hide(); -#endif +void OwncloudSetupPage::setLogo() +{ + _ui.logoLabel->setPixmap(Theme::instance()->wizardApplicationLogo()); +} +void OwncloudSetupPage::setupServerAddressDescriptionLabel() +{ const auto appName = Theme::instance()->appNameGUI(); - _ui.loginButton->setText(tr("Log in to your %1").arg(appName)); - _ui.addressDescriptionLabel->setText(tr("This is the link to your %1 web interface when you open it in the browser.
" - "It looks like https://cloud.example.com or https://example.com/cloud").arg(appName)); - - customizeStyle(); + _ui.serverAddressDescriptionLabel->setText(tr("The link to your %1 web interface when you open it in the browser.", "%1 will be replaced with the application name").arg(appName)); } void OwncloudSetupPage::setServerUrl(const QString &newUrl) @@ -127,25 +112,17 @@ void OwncloudSetupPage::setupCustomization() variant = theme->customMedia(Theme::oCSetupBottom); WizardCommon::setupCustomMedia(variant, _ui.bottomLabel); + + auto leUrlPalette = _ui.leUrl->palette(); + leUrlPalette.setColor(QPalette::Text, Qt::black); + leUrlPalette.setColor(QPalette::Base, Qt::white); + _ui.leUrl->setPalette(leUrlPalette); } #ifdef WITH_PROVIDERS void OwncloudSetupPage::slotLogin() { - _ui.slideShow->hide(); - _ui.nextButton->hide(); - _ui.prevButton->hide(); - _ocWizard->setRegistration(false); - _ui.login->setMaximumHeight(0); - auto *animation = new QPropertyAnimation(_ui.login, "maximumHeight"); - animation->setDuration(0); - animation->setStartValue(500); - animation->setEndValue(500); - _ui.login->show(); - _ui.loginButton->hide(); - wizard()->resize(wizard()->sizeHint()); - animation->start(); } void OwncloudSetupPage::slotGotoProviderList() { @@ -160,6 +137,14 @@ void OwncloudSetupPage::slotGotoProviderList() // slot hit from textChanged of the url entry field. void OwncloudSetupPage::slotUrlChanged(const QString &url) { + // Need to set next button as default button here because + // otherwise the on OSX the next button does not stay the default + // button + auto nextButton = qobject_cast(_ocWizard->button(QWizard::NextButton)); + if (nextButton) { + nextButton->setDefault(true); + } + _authTypeKnown = false; QString newUrl = url; @@ -181,16 +166,6 @@ void OwncloudSetupPage::slotUrlChanged(const QString &url) if (newUrl != url) { _ui.leUrl->setText(newUrl); } - - const auto isSecure = url.startsWith(QLatin1String("https://")); - const auto toolTip = isSecure ? tr("This URL is secure. You can use it.") - : tr("This URL is NOT secure as it is not encrypted.\n" - "It is not advisable to use it."); - const auto pixmap = isSecure ? QPixmap(Theme::hidpiFileName(":/client/theme/lock-https.svg")) - : QPixmap(Theme::hidpiFileName(":/client/theme/lock-http.svg")); - - _ui.urlLabel->setToolTip(toolTip); - _ui.urlLabel->setPixmap(pixmap.scaled(_ui.urlLabel->size(), Qt::KeepAspectRatio)); } void OwncloudSetupPage::slotUrlEditFinished() @@ -210,6 +185,8 @@ bool OwncloudSetupPage::isComplete() const void OwncloudSetupPage::initializePage() { + customizeStyle(); + WizardCommon::initErrorLabel(_ui.errorLabel); _authTypeKnown = false; @@ -217,26 +194,29 @@ void OwncloudSetupPage::initializePage() QAbstractButton *nextButton = wizard()->button(QWizard::NextButton); auto *pushButton = qobject_cast(nextButton); - if (pushButton) + if (pushButton) { pushButton->setDefault(true); + } + + _ui.leUrl->setFocus(); - // If url is overriden by theme, it's already set and - // we just check the server type and switch to second page - // immediately. - if (Theme::instance()->overrideServerUrl().isEmpty()) { - _ui.leUrl->setFocus(); - } else if (!Theme::instance()->forceOverrideServerUrl()) { + const auto isServerUrlOverridden = !Theme::instance()->overrideServerUrl().isEmpty(); + if (isServerUrlOverridden && !Theme::instance()->forceOverrideServerUrl()) { + // If the url is overwritten but we don't force to use that url + // Just focus the next button to let the user navigate quicker if (nextButton) { nextButton->setFocus(); } - } else { + } else if (isServerUrlOverridden) { + // If the overwritten url is not empty and we force this overwritten url + // we just check the server type and switch to next page + // immediately. setCommitPage(true); // Hack: setCommitPage() changes caption, but after an error this page could still be visible setButtonText(QWizard::CommitButton, tr("&Next >")); validatePage(); setVisible(false); } - wizard()->resize(wizard()->sizeHint()); } int OwncloudSetupPage::nextId() const @@ -269,7 +249,7 @@ bool OwncloudSetupPage::validatePage() QString u = url(); QUrl qurl(u); if (!qurl.isValid() || qurl.host().isEmpty()) { - setErrorString(tr("Invalid URL"), false); + setErrorString(tr("Server address does not seem to be valid"), false); return false; } @@ -338,21 +318,18 @@ void OwncloudSetupPage::setErrorString(const QString &err, bool retryHTTPonly) _checking = false; emit completeChanged(); stopSpinner(); - wizard()->resize(wizard()->sizeHint()); } void OwncloudSetupPage::startSpinner() { - _ui.resultLayout->setEnabled(true); - _ui.urlLabel->setVisible(false); + _ui.progressLayout->setEnabled(true); _progressIndi->setVisible(true); _progressIndi->startAnimation(); } void OwncloudSetupPage::stopSpinner() { - _ui.resultLayout->setEnabled(false); - _ui.urlLabel->setVisible(true); + _ui.progressLayout->setEnabled(false); _progressIndi->setVisible(false); _progressIndi->stopAnimation(); } @@ -397,24 +374,19 @@ void OwncloudSetupPage::slotStyleChanged() void OwncloudSetupPage::customizeStyle() { -#ifdef WITH_PROVIDERS - Theme *theme = Theme::instance(); - - bool widgetHasDarkBg = Theme::isDarkColor(QGuiApplication::palette().base().color()); - _ui.nextButton->setIcon(theme->uiThemeIcon(QString("control-next.svg"), widgetHasDarkBg)); - _ui.prevButton->setIcon(theme->uiThemeIcon(QString("control-prev.svg"), widgetHasDarkBg)); - - // QPushButtons are a mess when it comes to consistent background coloring without stylesheets, - // so we do it here even though this is an exceptional styling method here - _ui.createAccountButton->setStyleSheet("QPushButton {background-color: #0082C9; color: white}"); + setLogo(); + + if (_progressIndi) { + const auto isDarkBackground = Theme::isDarkColor(palette().window().color()); + if (isDarkBackground) { + _progressIndi->setColor(Qt::white); + } else { + _progressIndi->setColor(Qt::black); + } + } - QPalette pal = _ui.slideShow->palette(); - pal.setColor(QPalette::WindowText, theme->wizardHeaderBackgroundColor()); - _ui.slideShow->setPalette(pal); -#endif - if(_progressIndi) - _progressIndi->setColor(QGuiApplication::palette().color(QPalette::Text)); + WizardCommon::customizeHintLabel(_ui.serverAddressDescriptionLabel); } } // namespace OCC diff --git a/src/gui/wizard/owncloudsetuppage.h b/src/gui/wizard/owncloudsetuppage.h index 18b9c0135dc0..485a2bd62203 100644 --- a/src/gui/wizard/owncloudsetuppage.h +++ b/src/gui/wizard/owncloudsetuppage.h @@ -78,7 +78,9 @@ protected slots: void determineAuthType(const QString &); private: + void setLogo(); void customizeStyle(); + void setupServerAddressDescriptionLabel(); Ui_OwncloudSetupPage _ui; diff --git a/src/gui/wizard/owncloudwizard.cpp b/src/gui/wizard/owncloudwizard.cpp index d97b0b19fd50..4a8e3866204d 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,17 +47,19 @@ Q_LOGGING_CATEGORY(lcWizard, "nextcloud.gui.wizard", QtInfoMsg) OwncloudWizard::OwncloudWizard(QWidget *parent) : QWizard(parent) , _account(nullptr) + , _welcomePage(new WelcomePage(this)) , _setupPage(new OwncloudSetupPage(this)) , _httpCredsPage(new OwncloudHttpCredsPage(this)) , _browserCredsPage(new OwncloudOAuthCredsPage) , _flow2CredsPage(new Flow2AuthCredsPage) - , _advancedSetupPage(new OwncloudAdvancedSetupPage) + , _advancedSetupPage(new OwncloudAdvancedSetupPage(this)) , _resultPage(new OwncloudWizardResultPage) , _webViewPage(new WebViewPage(this)) { setObjectName("owncloudWizard"); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setPage(WizardCommon::Page_Welcome, _welcomePage); setPage(WizardCommon::Page_ServerSetup, _setupPage); setPage(WizardCommon::Page_HttpCreds, _httpCredsPage); setPage(WizardCommon::Page_OAuthCreds, _browserCredsPage); @@ -69,7 +72,6 @@ OwncloudWizard::OwncloudWizard(QWidget *parent) // note: start Id is set by the calling class depending on if the // welcome text is to be shown or not. - setWizardStyle(QWizard::ModernStyle); connect(this, &QWizard::currentIdChanged, this, &OwncloudWizard::slotCurrentPageChanged); connect(_setupPage, &OwncloudSetupPage::determineAuthType, this, &OwncloudWizard::determineAuthType); @@ -83,17 +85,19 @@ OwncloudWizard::OwncloudWizard(QWidget *parent) Theme *theme = Theme::instance(); - setWindowTitle(tr("%1 Connection Wizard").arg(theme->appNameGUI())); + setWindowTitle(tr("Add %1 account").arg(theme->appNameGUI())); setWizardStyle(QWizard::ModernStyle); - setPixmap(QWizard::BannerPixmap, theme->wizardHeaderBanner()); - setPixmap(QWizard::LogoPixmap, theme->wizardHeaderLogo()); setOption(QWizard::NoBackButtonOnStartPage); setOption(QWizard::NoBackButtonOnLastPage); setOption(QWizard::NoCancelButton); - setTitleFormat(Qt::RichText); - 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); @@ -104,6 +108,48 @@ OwncloudWizard::OwncloudWizard(QWidget *parent) // allow Flow2 page to poll on window activation connect(this, &OwncloudWizard::onActivate, _flow2CredsPage, &Flow2AuthCredsPage::slotPollNow); + + adjustWizardSize(); + centerWindow(); +} + +void OwncloudWizard::centerWindow() +{ + const auto wizardWindow = window(); + const auto screenGeometry = QGuiApplication::screenAt(wizardWindow->pos())->geometry(); + const auto windowGeometry = wizardWindow->geometry(); + const auto newWindowPosition = screenGeometry.center() - QPoint(windowGeometry.width() / 2, windowGeometry.height() / 2); + wizardWindow->move(newWindowPosition); +} + + +void OwncloudWizard::adjustWizardSize() +{ + const auto pageSizes = calculateWizardPageSizes(); + const auto longestSide = calculateLongestSideOfWizardPages(pageSizes); + + resize(QSize(longestSide, longestSide)); +} + +QList OwncloudWizard::calculateWizardPageSizes() const +{ + QList pageSizes; + const auto pIds = pageIds(); + + std::transform(pIds.cbegin(), pIds.cend(), std::back_inserter(pageSizes), [this](int pageId) { + auto p = page(pageId); + p->adjustSize(); + return p->sizeHint(); + }); + + return pageSizes; +} + +int OwncloudWizard::calculateLongestSideOfWizardPages(const QList &pageSizes) const +{ + return std::accumulate(std::cbegin(pageSizes), std::cend(pageSizes), 0, [](int current, const QSize &size) { + return std::max({ current, size.width(), size.height() }); + }); } void OwncloudWizard::setAccount(AccountPtr account) @@ -220,6 +266,28 @@ 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); + } + }; + + 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 +300,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. @@ -302,6 +369,15 @@ void OwncloudWizard::changeEvent(QEvent *e) void OwncloudWizard::customizeStyle() { // HINT: Customize wizard's own style here, if necessary in the future (Dark-/Light-Mode switching) + + // Set background colors + auto wizardPalette = palette(); + const auto backgroundColor = wizardPalette.color(QPalette::Window); + wizardPalette.setColor(QPalette::Base, backgroundColor); + // Set separator color + wizardPalette.setColor(QPalette::Mid, backgroundColor); + + setPalette(wizardPalette); } void OwncloudWizard::bringToTop() diff --git a/src/gui/wizard/owncloudwizard.h b/src/gui/wizard/owncloudwizard.h index 947d5f679ff2..e8480d3bda70 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; @@ -73,6 +74,7 @@ class OwncloudWizard : public QWizard AbstractCredentials *getCredentials() const; void bringToTop(); + void centerWindow(); /** * Shows a dialog explaining the virtual files mode and warning about it @@ -113,8 +115,12 @@ public slots: private: void customizeStyle(); + void adjustWizardSize(); + int calculateLongestSideOfWizardPages(const QList &pageSizes) const; + QList calculateWizardPageSizes() const; 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..0f473508243b 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 d1f7c08be07a..5ebcca01fc95 100644 --- a/src/gui/wizard/owncloudwizardcommon.h +++ b/src/gui/wizard/owncloudwizardcommon.h @@ -16,8 +16,14 @@ #ifndef MIRALL_OWNCLOUD_WIZARD_COMMON_H #define MIRALL_OWNCLOUD_WIZARD_COMMON_H +#include + class QVariant; class QLabel; +class QRadioButton; +class QSpinBox; +class QCheckBox; +class QAbstractButton; namespace OCC { @@ -27,6 +33,7 @@ namespace WizardCommon { QString titleTemplate(); QString subTitleTemplate(); void initErrorLabel(QLabel *errorLabel); + void customizeHintLabel(QLabel *label); enum SyncMode { SelectiveMode, @@ -34,6 +41,7 @@ namespace WizardCommon { }; enum Pages { + Page_Welcome, Page_ServerSetup, Page_HttpCreds, Page_ShibbolethCreds, diff --git a/src/gui/wizard/webview.ui b/src/gui/wizard/webview.ui index ba3588ca8776..8ab0665b7871 100644 --- a/src/gui/wizard/webview.ui +++ b/src/gui/wizard/webview.ui @@ -11,15 +11,15 @@ - + 0 0 - 800 - 650 + 0 + 0 diff --git a/src/gui/wizard/webviewpage.cpp b/src/gui/wizard/webviewpage.cpp index 01311e839bf6..7aae73fc8866 100644 --- a/src/gui/wizard/webviewpage.cpp +++ b/src/gui/wizard/webviewpage.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "owncloudwizard.h" #include "creds/webflowcredentials.h" @@ -24,6 +25,7 @@ WebViewPage::WebViewPage(QWidget *parent) _webView = new WebView(this); auto *layout = new QVBoxLayout(this); + layout->setMargin(0); layout->addWidget(_webView); setLayout(layout); @@ -52,6 +54,44 @@ void WebViewPage::initializePage() { } qCInfo(lcWizardWebiewPage()) << "Url to auth at: " << url; _webView->setUrl(QUrl(url)); + + _originalWizardSize = _ocWizard->size(); + resizeWizard(); +} + +void WebViewPage::resizeWizard() +{ + // The webview needs a little bit more space + auto wizardSizeChanged = tryToSetWizardSize(_originalWizardSize.width() * 2, _originalWizardSize.height() * 2); + + if (!wizardSizeChanged) { + wizardSizeChanged = tryToSetWizardSize(static_cast(_originalWizardSize.width() * 1.5), static_cast(_originalWizardSize.height() * 1.5)); + } + + if (wizardSizeChanged) { + _ocWizard->centerWindow(); + } +} + +bool WebViewPage::tryToSetWizardSize(int width, int height) +{ + const auto window = _ocWizard->window(); + const auto screenGeometry = QGuiApplication::screenAt(window->pos())->geometry(); + const auto windowWidth = screenGeometry.width(); + const auto windowHeight = screenGeometry.height(); + + if (width < windowWidth && height < windowHeight) { + _ocWizard->resize(width, height); + return true; + } + + return false; +} + +void WebViewPage::cleanupPage() +{ + _ocWizard->resize(_originalWizardSize); + _ocWizard->centerWindow(); } int WebViewPage::nextId() const { diff --git a/src/gui/wizard/webviewpage.h b/src/gui/wizard/webviewpage.h index 65f00c33bb96..c621e99f1e26 100644 --- a/src/gui/wizard/webviewpage.h +++ b/src/gui/wizard/webviewpage.h @@ -17,6 +17,7 @@ class WebViewPage : public AbstractCredentialsWizardPage ~WebViewPage(); void initializePage() override; + void cleanupPage() override; int nextId() const override; bool isComplete() const override; @@ -30,6 +31,9 @@ private slots: void urlCatched(QString user, QString pass, QString host); private: + void resizeWizard(); + bool tryToSetWizardSize(int width, int height); + OwncloudWizard *_ocWizard; WebView *_webView; @@ -37,6 +41,8 @@ private slots: QString _pass; bool _useSystemProxy; + + QSize _originalWizardSize; }; } diff --git a/src/gui/wizard/welcomepage.cpp b/src/gui/wizard/welcomepage.cpp new file mode 100644 index 000000000000..668c5b02f56f --- /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 000000000000..9d0aa1c0a849 --- /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 000000000000..1d54a802754d --- /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/nextcloudtheme.cpp b/src/libsync/nextcloudtheme.cpp index 0ec3f2d27398..2a709564c6e4 100644 --- a/src/libsync/nextcloudtheme.cpp +++ b/src/libsync/nextcloudtheme.cpp @@ -35,7 +35,7 @@ NextcloudTheme::NextcloudTheme() QString NextcloudTheme::wizardUrlHint() const { - return QString("https://host:port"); + return QString("https://try.nextcloud.com"); } } diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index be3bde5e6a5d..b77a6665593e 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 394cb8930537..a06828b1fcb4 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; + /** @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; +}; diff --git a/theme.qrc b/theme.qrc index 7d0c732b8e23..620a406027b9 100644 --- a/theme.qrc +++ b/theme.qrc @@ -80,6 +80,12 @@ theme/colored/state-warning-64.png theme/colored/state-warning-128.png theme/colored/state-warning-256.png + theme/black/folder.png + theme/black/folder@2x.png + theme/white/folder.png + theme/white/folder@2x.png + theme/colored/folder.png + theme/colored/folder@2x.png theme/black/control-next.svg theme/black/control-prev.svg theme/black/state-error.svg @@ -124,6 +130,23 @@ theme/white/state-warning-64.png theme/white/state-warning-128.png theme/white/state-warning-256.png + theme/white/wizard-files.png + theme/white/wizard-files@2x.png + theme/white/wizard-groupware.png + theme/white/wizard-groupware@2x.png + theme/white/wizard-nextcloud.png + theme/white/wizard-nextcloud@2x.png + theme/white/wizard-talk.png + theme/white/wizard-talk@2x.png + theme/black/wizard-files.png + theme/black/wizard-files@2x.png + theme/black/wizard-groupware.png + theme/black/wizard-groupware@2x.png + theme/black/wizard-nextcloud.png + theme/black/wizard-nextcloud@2x.png + theme/black/wizard-talk.png + theme/black/wizard-talk@2x.png + theme/black/wizard-files.png theme/colored/wizard-files.png theme/colored/wizard-files@2x.png theme/colored/wizard-groupware.png @@ -132,6 +155,13 @@ theme/colored/wizard-nextcloud@2x.png theme/colored/wizard-talk.png theme/colored/wizard-talk@2x.png + theme/sync-arrow.svg + theme/white/external.png + theme/white/external@2x.png + theme/black/external.png + theme/black/external@2x.png + theme/colored/external.png + theme/colored/external@2x.png theme/white/folder.svg theme/white/more-apps.svg theme/white/talk-app.svg diff --git a/theme/black/external.png b/theme/black/external.png new file mode 100644 index 000000000000..db82098ecd55 Binary files /dev/null and b/theme/black/external.png differ diff --git a/theme/black/external.svg b/theme/black/external.svg new file mode 100644 index 000000000000..79c9cebf5889 --- /dev/null +++ b/theme/black/external.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/black/external@2x.png b/theme/black/external@2x.png new file mode 100644 index 000000000000..04779d85945a Binary files /dev/null and b/theme/black/external@2x.png differ diff --git a/theme/black/folder.png b/theme/black/folder.png new file mode 100644 index 000000000000..3d67f6ec2f0a Binary files /dev/null and b/theme/black/folder.png differ diff --git a/theme/black/folder.svg b/theme/black/folder.svg new file mode 100644 index 000000000000..9289fb05d74c --- /dev/null +++ b/theme/black/folder.svg @@ -0,0 +1 @@ + diff --git a/theme/black/folder@2x.png b/theme/black/folder@2x.png new file mode 100644 index 000000000000..2ac972b9a830 Binary files /dev/null and b/theme/black/folder@2x.png differ diff --git a/theme/black/wizard-files.png b/theme/black/wizard-files.png new file mode 100644 index 000000000000..01c6a2540ce7 Binary files /dev/null and b/theme/black/wizard-files.png differ diff --git a/theme/black/wizard-files.svg b/theme/black/wizard-files.svg new file mode 100644 index 000000000000..6c3ff3761017 --- /dev/null +++ b/theme/black/wizard-files.svg @@ -0,0 +1 @@ + diff --git a/theme/black/wizard-files@2x.png b/theme/black/wizard-files@2x.png new file mode 100644 index 000000000000..30a6ddfaff34 Binary files /dev/null and b/theme/black/wizard-files@2x.png differ diff --git a/theme/black/wizard-groupware.png b/theme/black/wizard-groupware.png new file mode 100644 index 000000000000..f560466a2733 Binary files /dev/null and b/theme/black/wizard-groupware.png differ diff --git a/theme/black/wizard-groupware.svg b/theme/black/wizard-groupware.svg new file mode 100644 index 000000000000..f7f31340b043 --- /dev/null +++ b/theme/black/wizard-groupware.svg @@ -0,0 +1 @@ + diff --git a/theme/black/wizard-groupware@2x.png b/theme/black/wizard-groupware@2x.png new file mode 100644 index 000000000000..b9d544966db5 Binary files /dev/null and b/theme/black/wizard-groupware@2x.png differ diff --git a/theme/black/wizard-nextcloud.png b/theme/black/wizard-nextcloud.png new file mode 100644 index 000000000000..1a7a6d83c709 Binary files /dev/null and b/theme/black/wizard-nextcloud.png differ diff --git a/theme/black/wizard-nextcloud.svg b/theme/black/wizard-nextcloud.svg new file mode 100644 index 000000000000..7b2a28341d54 --- /dev/null +++ b/theme/black/wizard-nextcloud.svg @@ -0,0 +1,81 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/theme/black/wizard-nextcloud@2x.png b/theme/black/wizard-nextcloud@2x.png new file mode 100644 index 000000000000..0fbfc99f048d Binary files /dev/null and b/theme/black/wizard-nextcloud@2x.png differ diff --git a/theme/black/wizard-talk.png b/theme/black/wizard-talk.png new file mode 100644 index 000000000000..5b512630f9a5 Binary files /dev/null and b/theme/black/wizard-talk.png differ diff --git a/theme/black/wizard-talk.svg b/theme/black/wizard-talk.svg new file mode 100644 index 000000000000..f81beb060fdf --- /dev/null +++ b/theme/black/wizard-talk.svg @@ -0,0 +1 @@ + diff --git a/theme/black/wizard-talk@2x.png b/theme/black/wizard-talk@2x.png new file mode 100644 index 000000000000..8f77d93e559e Binary files /dev/null and b/theme/black/wizard-talk@2x.png differ diff --git a/theme/colored/external.png b/theme/colored/external.png new file mode 100644 index 000000000000..21bb821e945a Binary files /dev/null and b/theme/colored/external.png differ diff --git a/theme/colored/external.svg b/theme/colored/external.svg new file mode 100644 index 000000000000..7fa8f1a61f0a --- /dev/null +++ b/theme/colored/external.svg @@ -0,0 +1 @@ + diff --git a/theme/colored/external@2x.png b/theme/colored/external@2x.png new file mode 100644 index 000000000000..9e23cc497900 Binary files /dev/null and b/theme/colored/external@2x.png differ diff --git a/theme/colored/folder.png b/theme/colored/folder.png new file mode 100644 index 000000000000..2a5b34246740 Binary files /dev/null and b/theme/colored/folder.png differ diff --git a/theme/colored/folder.svg b/theme/colored/folder.svg index c311e426b664..2ee3ca7c8951 100644 --- a/theme/colored/folder.svg +++ b/theme/colored/folder.svg @@ -1 +1 @@ - + diff --git a/theme/colored/folder@2x.png b/theme/colored/folder@2x.png new file mode 100644 index 000000000000..1f79228397da Binary files /dev/null and b/theme/colored/folder@2x.png differ diff --git a/theme/colored/wizard-files.png b/theme/colored/wizard-files.png index 236bfa773706..54b13fb15326 100644 Binary files a/theme/colored/wizard-files.png and b/theme/colored/wizard-files.png differ diff --git a/theme/colored/wizard-files@2x.png b/theme/colored/wizard-files@2x.png index 4f1eb74acb8b..58a648cd613c 100644 Binary files a/theme/colored/wizard-files@2x.png and b/theme/colored/wizard-files@2x.png differ diff --git a/theme/colored/wizard-groupware.png b/theme/colored/wizard-groupware.png index 417629bb9df1..034c078d5525 100644 Binary files a/theme/colored/wizard-groupware.png and b/theme/colored/wizard-groupware.png differ diff --git a/theme/colored/wizard-groupware@2x.png b/theme/colored/wizard-groupware@2x.png index cea41d3c614b..1aa5999a0031 100644 Binary files a/theme/colored/wizard-groupware@2x.png and b/theme/colored/wizard-groupware@2x.png differ diff --git a/theme/colored/wizard-nextcloud.png b/theme/colored/wizard-nextcloud.png index 321f83e31ab4..1f7903a655bc 100644 Binary files a/theme/colored/wizard-nextcloud.png and b/theme/colored/wizard-nextcloud.png differ diff --git a/theme/colored/wizard-nextcloud.svg b/theme/colored/wizard-nextcloud.svg index e92362c5455b..bc48cd582ee7 100644 --- a/theme/colored/wizard-nextcloud.svg +++ b/theme/colored/wizard-nextcloud.svg @@ -1 +1,81 @@ - + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/theme/colored/wizard-nextcloud@2x.png b/theme/colored/wizard-nextcloud@2x.png index a73e467d8a12..da68bc6fbf99 100644 Binary files a/theme/colored/wizard-nextcloud@2x.png and b/theme/colored/wizard-nextcloud@2x.png differ diff --git a/theme/colored/wizard-talk.png b/theme/colored/wizard-talk.png index e1c3839a1692..8231b27e0dba 100644 Binary files a/theme/colored/wizard-talk.png and b/theme/colored/wizard-talk.png differ diff --git a/theme/colored/wizard-talk@2x.png b/theme/colored/wizard-talk@2x.png index 92a368062294..ccaa62f9491c 100644 Binary files a/theme/colored/wizard-talk@2x.png and b/theme/colored/wizard-talk@2x.png differ diff --git a/theme/colored/wizard_logo.svg b/theme/colored/wizard_logo.svg index f2c08adbf22c..8d86581d3a0f 100644 --- a/theme/colored/wizard_logo.svg +++ b/theme/colored/wizard_logo.svg @@ -1,2 +1,2 @@ - + diff --git a/theme/sync-arrow.svg b/theme/sync-arrow.svg new file mode 100644 index 000000000000..56108b6d84f0 --- /dev/null +++ b/theme/sync-arrow.svg @@ -0,0 +1 @@ + diff --git a/theme/white/external.png b/theme/white/external.png new file mode 100644 index 000000000000..bac44b1d8113 Binary files /dev/null and b/theme/white/external.png differ diff --git a/theme/white/external.svg b/theme/white/external.svg new file mode 100644 index 000000000000..892a4e5afc38 --- /dev/null +++ b/theme/white/external.svg @@ -0,0 +1 @@ + diff --git a/theme/white/external@2x.png b/theme/white/external@2x.png new file mode 100644 index 000000000000..5c49e615ae90 Binary files /dev/null and b/theme/white/external@2x.png differ diff --git a/theme/white/folder.png b/theme/white/folder.png new file mode 100644 index 000000000000..cfeb3e1f6b41 Binary files /dev/null and b/theme/white/folder.png differ diff --git a/theme/white/folder.svg b/theme/white/folder.svg index 003e8b3fb80d..a32ffc8570c2 100644 --- a/theme/white/folder.svg +++ b/theme/white/folder.svg @@ -1 +1 @@ - + diff --git a/theme/white/folder@2x.png b/theme/white/folder@2x.png new file mode 100644 index 000000000000..03a919e6c2b1 Binary files /dev/null and b/theme/white/folder@2x.png differ diff --git a/theme/white/wizard-files.png b/theme/white/wizard-files.png new file mode 100644 index 000000000000..673a4bde28cb Binary files /dev/null and b/theme/white/wizard-files.png differ diff --git a/theme/white/wizard-files.svg b/theme/white/wizard-files.svg new file mode 100644 index 000000000000..e01fb5b88937 --- /dev/null +++ b/theme/white/wizard-files.svg @@ -0,0 +1 @@ + diff --git a/theme/white/wizard-files@2x.png b/theme/white/wizard-files@2x.png new file mode 100644 index 000000000000..810030290dee Binary files /dev/null and b/theme/white/wizard-files@2x.png differ diff --git a/theme/white/wizard-groupware.png b/theme/white/wizard-groupware.png new file mode 100644 index 000000000000..e348accb2f34 Binary files /dev/null and b/theme/white/wizard-groupware.png differ diff --git a/theme/white/wizard-groupware.svg b/theme/white/wizard-groupware.svg new file mode 100644 index 000000000000..0cd9a33e5469 --- /dev/null +++ b/theme/white/wizard-groupware.svg @@ -0,0 +1 @@ + diff --git a/theme/white/wizard-groupware@2x.png b/theme/white/wizard-groupware@2x.png new file mode 100644 index 000000000000..ae5024e44249 Binary files /dev/null and b/theme/white/wizard-groupware@2x.png differ diff --git a/theme/white/wizard-nextcloud.png b/theme/white/wizard-nextcloud.png new file mode 100644 index 000000000000..8022b79a331a Binary files /dev/null and b/theme/white/wizard-nextcloud.png differ diff --git a/theme/white/wizard-nextcloud.svg b/theme/white/wizard-nextcloud.svg new file mode 100644 index 000000000000..a0330d783f9c --- /dev/null +++ b/theme/white/wizard-nextcloud.svg @@ -0,0 +1,81 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/theme/white/wizard-nextcloud@2x.png b/theme/white/wizard-nextcloud@2x.png new file mode 100644 index 000000000000..ad10827c2b88 Binary files /dev/null and b/theme/white/wizard-nextcloud@2x.png differ diff --git a/theme/white/wizard-talk.png b/theme/white/wizard-talk.png new file mode 100644 index 000000000000..fc4646fe0f41 Binary files /dev/null and b/theme/white/wizard-talk.png differ diff --git a/theme/white/wizard-talk.svg b/theme/white/wizard-talk.svg new file mode 100644 index 000000000000..45ab71d990f5 --- /dev/null +++ b/theme/white/wizard-talk.svg @@ -0,0 +1 @@ + diff --git a/theme/white/wizard-talk@2x.png b/theme/white/wizard-talk@2x.png new file mode 100644 index 000000000000..b576ec365970 Binary files /dev/null and b/theme/white/wizard-talk@2x.png differ