Setup wizard: implement an animated and interactive slide show

This commit is contained in:
J-P Nurmi 2018-10-29 11:17:04 +01:00
parent e88b81c6c9
commit 1d3d261e38
15 changed files with 301 additions and 65 deletions

View File

@ -116,6 +116,7 @@ set(client_SRCS
wizard/owncloudwizardresultpage.cpp
wizard/webviewpage.cpp
wizard/webview.cpp
wizard/slideshow.cpp
)
IF(NOT NO_SHIBBOLETH)

View File

@ -190,28 +190,6 @@
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="slideImage">
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../../theme.qrc">:/client/theme/colored/wizard-files.svg</pixmap>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
@ -229,7 +207,7 @@
</spacer>
</item>
<item row="2" column="0">
<widget class="QLabel" name="slideLabel">
<widget class="OCC::SlideShow" name="slideShow">
<property name="font">
<font>
<pointsize>12</pointsize>
@ -237,12 +215,6 @@
<bold>true</bold>
</font>
</property>
<property name="text">
<string>SlideshowLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
@ -437,6 +409,11 @@
<extends>QLineEdit</extends>
<header>wizard/postfixlineedit.h</header>
</customwidget>
<customwidget>
<class>OCC::SlideShow</class>
<extends>QWidget</extends>
<header>wizard/slideshow.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../theme.qrc"/>

View File

@ -31,6 +31,7 @@
#include "wizard/owncloudwizardcommon.h"
#include "wizard/owncloudsetuppage.h"
#include "wizard/owncloudconnectionmethoddialog.h"
#include "wizard/slideshow.h"
#include "theme.h"
#include "account.h"
#include "config.h"
@ -80,18 +81,16 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
connect(_ui.createAccountButton, &QPushButton::clicked, this, &OwncloudSetupPage::slotGotoProviderList);
_ui.login->hide();
_slideshow.append(qMakePair(QString("nextcloud"), tr("Keep your data secure and under your control")));
_slideshow.append(qMakePair(QString("files"), tr("Secure collaboration & file exchange")));
_slideshow.append(qMakePair(QString("groupware"), tr("Easy-to-use web mail, calendaring & contacts")));
_slideshow.append(qMakePair(QString("talk"), tr("Screensharing, online meetings & web conferences")));
_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::nextSlide);
_ui.slideShow->startShow(2500);
_ui.slideLabel->setStyleSheet(QString("color:%1;").arg(theme->wizardHeaderBackgroundColor().name()));
_currentSlide = -1;
nextSlide();
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(nextSlide()));
timer->start(2500);
QPalette pal = _ui.slideShow->palette();
pal.setColor(QPalette::WindowText, theme->wizardHeaderBackgroundColor());
_ui.slideShow->setPalette(pal);
#else
_ui.createAccountButton->hide();
_ui.slideImage->hide();
@ -102,20 +101,6 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
setStyleSheet(QString("background-color:%1; color:%2 QLabel { color:%2; } QSpacerItem { color: red; }").arg(theme->wizardHeaderBackgroundColor().name(), theme->wizardHeaderTitleColor().name()));
}
#ifdef WITH_PROVIDERS
void OwncloudSetupPage::nextSlide()
{
if (_currentSlide < _slideshow.length() - 1) {
_currentSlide++;
} else {
_currentSlide = 0;
}
QPixmap pixmap = QIcon(Theme::hidpiFileName(":/client/theme/colored/wizard-" + _slideshow.at(_currentSlide).first + ".svg")).pixmap(QSize(1024, 1024));
_ui.slideImage->setPixmap(pixmap.scaled(QSize(_ui.slideImage->size().height(), _ui.slideImage->size().height()), Qt::KeepAspectRatio, Qt::SmoothTransformation));
_ui.slideLabel->setText(_slideshow.at(_currentSlide).second);
}
#endif
void OwncloudSetupPage::setServerUrl(const QString &newUrl)
{
_ocWizard->setRegistration(false);

View File

@ -62,9 +62,6 @@ public slots:
void startSpinner();
void stopSpinner();
void slotCertificateAccepted();
#ifdef WITH_PROVIDERS
void nextSlide();
#endif
protected slots:
void slotUrlChanged(const QString &);
@ -96,10 +93,6 @@ private:
QString _remoteFolder;
AddCertificateDialog *addCertDial;
OwncloudWizard *_ocWizard;
QList<QPair<QString, QString>> _slideshow;
int _currentSlide;
};
} // namespace OCC

View File

@ -0,0 +1,193 @@
/*
* Copyright (C) 2018 by J-P Nurmi <jpnurmi@gmail.com>
*
* 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 "slideshow.h"
#include <QGuiApplication>
#include <QMouseEvent>
#include <QPainter>
#include <QStyle>
#include <QStyleHints>
namespace OCC {
static const int Spacing = 6;
static const int SlideDuration = 250;
static const int SlideDistance = 200;
SlideShow::SlideShow(QWidget *parent) : QWidget(parent)
{
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
}
void SlideShow::addSlide(const QPixmap &pixmap, const QString &label)
{
_labels += label;
_pixmaps += pixmap;
updateGeometry();
}
bool SlideShow::isActive() const
{
return _timer.isActive();
}
int SlideShow::interval() const
{
return _interval;
}
void SlideShow::setInterval(int interval)
{
if (_interval == interval)
return;
_interval = interval;
maybeRestartTimer();
}
int SlideShow::currentSlide() const
{
return _currentIndex;
}
void SlideShow::setCurrentSlide(int index)
{
if (_currentIndex == index)
return;
if (!_animation) {
_animation = new QVariantAnimation(this);
_animation->setDuration(SlideDuration);
_animation->setEasingCurve(QEasingCurve::OutCubic);
_animation->setStartValue(static_cast<qreal>(_currentIndex));
connect(_animation.data(), SIGNAL(valueChanged(QVariant)), this, SLOT(update()));
}
_animation->setEndValue(static_cast<qreal>(index));
_animation->start(QAbstractAnimation::DeleteWhenStopped);
_reverse = index < _currentIndex;
_currentIndex = index;
maybeRestartTimer();
update();
emit currentSlideChanged(index);
}
QSize SlideShow::sizeHint() const
{
QFontMetrics fm = fontMetrics();
QSize labelSize(0, fm.height());
for (const QString &label : _labels) {
labelSize.setWidth(std::max(fm.width(label), labelSize.width()));
}
QSize pixmapSize;
for (const QPixmap &pixmap : _pixmaps) {
pixmapSize.setWidth(std::max(pixmap.width(), pixmapSize.width()));
pixmapSize.setHeight(std::max(pixmap.height(), pixmapSize.height()));
}
return QSize(std::max(labelSize.width(), pixmapSize.width()), labelSize.height() + Spacing + pixmapSize.height());
}
void SlideShow::startShow(int interval)
{
if (interval > 0)
_interval = interval;
_timer.start(_interval, this);
}
void SlideShow::stopShow()
{
_timer.stop();
}
void SlideShow::nextSlide()
{
setCurrentSlide((_currentIndex + 1) % _labels.count());
_reverse = false;
}
void SlideShow::previousSlide()
{
setCurrentSlide((_currentIndex > 0 ? _currentIndex : _labels.count()) - 1);
_reverse = true;
}
void SlideShow::reset()
{
stopShow();
_pixmaps.clear();
_labels.clear();
updateGeometry();
update();
}
void SlideShow::mousePressEvent(QMouseEvent *event)
{
_pressPoint = event->pos();
}
void SlideShow::mouseReleaseEvent(QMouseEvent *event)
{
if (QLineF(_pressPoint, event->pos()).length() < QGuiApplication::styleHints()->startDragDistance())
emit clicked();
}
void SlideShow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
if (_animation) {
int from = _animation->startValue().toInt();
int to = _animation->endValue().toInt();
qreal progress = _animation->easingCurve().valueForProgress(_animation->currentTime() / static_cast<qreal>(_animation->duration()));
painter.save();
painter.setOpacity(1.0 - progress);
painter.translate(progress * (_reverse ? SlideDistance : -SlideDistance), 0);
drawSlide(&painter, from);
painter.restore();
painter.setOpacity(progress);
painter.translate((1.0 - progress) * (_reverse ? -SlideDistance : SlideDistance), 0);
drawSlide(&painter, to);
} else {
drawSlide(&painter, _currentIndex);
}
}
void SlideShow::timerEvent(QTimerEvent *event)
{
if (event->timerId() == _timer.timerId())
nextSlide();
}
void SlideShow::maybeRestartTimer()
{
if (!isActive())
return;
startShow();
}
void SlideShow::drawSlide(QPainter *painter, int index)
{
QString label = _labels.value(index);
QRect labelRect = style()->itemTextRect(fontMetrics(), rect(), Qt::AlignBottom | Qt::AlignHCenter, isEnabled(), label);
style()->drawItemText(painter, labelRect, Qt::AlignCenter, palette(), isEnabled(), label, QPalette::WindowText);
QPixmap pixmap = _pixmaps.value(index);
QRect pixmapRect = style()->itemPixmapRect(QRect(0, 0, width(), labelRect.top() - Spacing), Qt::AlignCenter, pixmap);
style()->drawItemPixmap(painter, pixmapRect, Qt::AlignCenter, pixmap);
}
} // namespace OCC

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2018 by J-P Nurmi <jpnurmi@gmail.com>
*
* 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.
*/
#ifndef OCC_SLIDESHOW_H
#define OCC_SLIDESHOW_H
#include <QWidget>
#include <QBasicTimer>
#include <QPointer>
#include <QVariantAnimation>
namespace OCC {
/**
* @brief The SlideShow class
* @ingroup gui
*/
class SlideShow : public QWidget
{
Q_OBJECT
Q_PROPERTY(int interval READ interval WRITE setInterval)
Q_PROPERTY(int currentSlide READ currentSlide WRITE setCurrentSlide NOTIFY currentSlideChanged)
public:
explicit SlideShow(QWidget* parent = nullptr);
void addSlide(const QPixmap &pixmap, const QString &label);
bool isActive() const;
int interval() const;
void setInterval(int interval);
int currentSlide() const;
void setCurrentSlide(int index);
QSize sizeHint() const override;
public slots:
void startShow(int interval = 0);
void stopShow();
void nextSlide();
void previousSlide();
void reset();
signals:
void clicked();
void currentSlideChanged(int index);
protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
void timerEvent(QTimerEvent *event);
private:
void maybeRestartTimer();
void drawSlide(QPainter *painter, int index);
bool _reverse = false;
int _interval = 2500;
int _currentIndex = 0;
QPoint _pressPoint;
QBasicTimer _timer;
QStringList _labels;
QVector<QPixmap> _pixmaps;
QPointer<QVariantAnimation> _animation = nullptr;
};
} // namespace OCC
#endif // OCC_SLIDESHOW_H

View File

@ -117,9 +117,13 @@
<file>theme/white/state-warning-64.png</file>
<file>theme/white/state-warning-128.png</file>
<file>theme/white/state-warning-256.png</file>
<file>theme/colored/wizard-files.svg</file>
<file>theme/colored/wizard-groupware.svg</file>
<file>theme/colored/wizard-nextcloud.svg</file>
<file>theme/colored/wizard-talk.svg</file>
<file>theme/colored/wizard-files.png</file>
<file>theme/colored/wizard-files@2x.png</file>
<file>theme/colored/wizard-groupware.png</file>
<file>theme/colored/wizard-groupware@2x.png</file>
<file>theme/colored/wizard-nextcloud.png</file>
<file>theme/colored/wizard-nextcloud@2x.png</file>
<file>theme/colored/wizard-talk.png</file>
<file>theme/colored/wizard-talk@2x.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB