mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-10-30 09:30:47 +03:00
Add spinner to hide uninitialized layout after login
This commit is contained in:
parent
58936cd67b
commit
415ef7e9c7
9 changed files with 494 additions and 9 deletions
|
@ -100,7 +100,9 @@ set(SRC_FILES
|
|||
|
||||
src/ui/Avatar.cc
|
||||
src/ui/Badge.cc
|
||||
src/ui/CircularProgress.cc
|
||||
src/ui/FlatButton.cc
|
||||
src/ui/OverlayModal.cc
|
||||
src/ui/RaisedButton.cc
|
||||
src/ui/Ripple.cc
|
||||
src/ui/RippleOverlay.cc
|
||||
|
@ -142,6 +144,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
|||
|
||||
include/ui/Avatar.h
|
||||
include/ui/Badge.h
|
||||
include/ui/CircularProgress.h
|
||||
include/ui/FlatButton.h
|
||||
include/ui/OverlayWidget.h
|
||||
include/ui/RaisedButton.h
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
#include <QSharedPointer>
|
||||
|
||||
#include "ChatPage.h"
|
||||
#include "CircularProgress.h"
|
||||
#include "LoginPage.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "OverlayModal.h"
|
||||
#include "RegisterPage.h"
|
||||
#include "SlidingStackWidget.h"
|
||||
#include "WelcomePage.h"
|
||||
|
@ -41,7 +43,7 @@ public:
|
|||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
public slots:
|
||||
private slots:
|
||||
// Show the welcome page in the main window.
|
||||
void showWelcomePage();
|
||||
|
||||
|
@ -54,6 +56,8 @@ public slots:
|
|||
// Show the chat page and start communicating with the given access token.
|
||||
void showChatPage(QString user_id, QString home_server, QString token);
|
||||
|
||||
void removeOverlayProgressBar();
|
||||
|
||||
private:
|
||||
// The UI component of the main window.
|
||||
Ui::MainWindow *ui_;
|
||||
|
@ -73,6 +77,10 @@ private:
|
|||
// The main chat area.
|
||||
ChatPage *chat_page_;
|
||||
|
||||
// Used to hide undefined states between page transitions.
|
||||
OverlayModal *progress_modal_;
|
||||
CircularProgress *spinner_;
|
||||
|
||||
// Matrix Client API provider.
|
||||
QSharedPointer<MatrixClient> client_;
|
||||
};
|
||||
|
|
114
include/ui/CircularProgress.h
Normal file
114
include/ui/CircularProgress.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
#ifndef UI_CIRCULAR_PROGRESS_H
|
||||
#define UI_CIRCULAR_PROGRESS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProgressBar>
|
||||
|
||||
#include "Theme.h"
|
||||
|
||||
class CircularProgressDelegate;
|
||||
|
||||
class CircularProgress : public QProgressBar
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(qreal lineWidth WRITE setLineWidth READ lineWidth)
|
||||
Q_PROPERTY(qreal size WRITE setSize READ size)
|
||||
Q_PROPERTY(QColor color WRITE setColor READ color)
|
||||
|
||||
public:
|
||||
explicit CircularProgress(QWidget *parent = nullptr);
|
||||
~CircularProgress();
|
||||
|
||||
void setProgressType(ui::ProgressType type);
|
||||
void setLineWidth(qreal width);
|
||||
void setSize(int size);
|
||||
void setColor(const QColor &color);
|
||||
|
||||
ui::ProgressType progressType() const;
|
||||
qreal lineWidth() const;
|
||||
int size() const;
|
||||
QColor color() const;
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
CircularProgressDelegate *delegate_;
|
||||
|
||||
ui::ProgressType progress_type_;
|
||||
|
||||
QColor color_;
|
||||
|
||||
// Circle width.
|
||||
qreal width_;
|
||||
|
||||
// Circle radius.
|
||||
int size_;
|
||||
};
|
||||
|
||||
class CircularProgressDelegate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(qreal dashOffset WRITE setDashOffset READ dashOffset)
|
||||
Q_PROPERTY(qreal dashLength WRITE setDashLength READ dashLength)
|
||||
Q_PROPERTY(int angle WRITE setAngle READ angle)
|
||||
|
||||
public:
|
||||
explicit CircularProgressDelegate(CircularProgress *parent);
|
||||
~CircularProgressDelegate();
|
||||
|
||||
inline void setDashOffset(qreal offset);
|
||||
inline void setDashLength(qreal length);
|
||||
inline void setAngle(int angle);
|
||||
|
||||
inline qreal dashOffset() const;
|
||||
inline qreal dashLength() const;
|
||||
inline int angle() const;
|
||||
|
||||
private:
|
||||
CircularProgress *const progress_;
|
||||
|
||||
qreal dash_offset_;
|
||||
qreal dash_length_;
|
||||
|
||||
int angle_;
|
||||
};
|
||||
|
||||
inline void CircularProgressDelegate::setDashOffset(qreal offset)
|
||||
{
|
||||
dash_offset_ = offset;
|
||||
progress_->update();
|
||||
}
|
||||
|
||||
inline void CircularProgressDelegate::setDashLength(qreal length)
|
||||
{
|
||||
dash_length_ = length;
|
||||
progress_->update();
|
||||
}
|
||||
|
||||
inline void CircularProgressDelegate::setAngle(int angle)
|
||||
{
|
||||
angle_ = angle;
|
||||
progress_->update();
|
||||
}
|
||||
|
||||
inline qreal CircularProgressDelegate::dashOffset() const
|
||||
{
|
||||
return dash_offset_;
|
||||
}
|
||||
|
||||
inline qreal CircularProgressDelegate::dashLength() const
|
||||
{
|
||||
return dash_length_;
|
||||
}
|
||||
|
||||
inline int CircularProgressDelegate::angle() const
|
||||
{
|
||||
return angle_;
|
||||
}
|
||||
|
||||
#endif // UI_CIRCULAR_PROGRESS_H
|
60
include/ui/OverlayModal.h
Normal file
60
include/ui/OverlayModal.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 3 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_OVERLAY_MODAL_H
|
||||
#define UI_OVERLAY_MODAL_H
|
||||
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QPaintEvent>
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
#include "OverlayWidget.h"
|
||||
|
||||
class OverlayModal : public OverlayWidget
|
||||
{
|
||||
public:
|
||||
explicit OverlayModal(QWidget *parent, QWidget *content);
|
||||
|
||||
void fadeIn();
|
||||
void fadeOut();
|
||||
|
||||
public:
|
||||
inline void setDuration(int duration);
|
||||
inline void setColor(QColor color);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
int duration_;
|
||||
QColor color_;
|
||||
|
||||
QGraphicsOpacityEffect *opacity_;
|
||||
QPropertyAnimation *animation_;
|
||||
};
|
||||
|
||||
inline void OverlayModal::setDuration(int duration)
|
||||
{
|
||||
duration_ = duration;
|
||||
}
|
||||
|
||||
inline void OverlayModal::setColor(QColor color)
|
||||
{
|
||||
color_ = color;
|
||||
}
|
||||
|
||||
#endif // UI_OVERLAY_MODAL_H
|
|
@ -2,7 +2,6 @@
|
|||
#define UI_OVERLAY_WIDGET_H
|
||||
|
||||
#include <QEvent>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
|
||||
class OverlayWidget : public QWidget
|
||||
|
@ -10,8 +9,7 @@ class OverlayWidget : public QWidget
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OverlayWidget(QWidget *parent = 0);
|
||||
~OverlayWidget();
|
||||
explicit OverlayWidget(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
bool event(QEvent *event) override;
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui_(new Ui::MainWindow)
|
||||
, progress_modal_{nullptr}
|
||||
, spinner_{nullptr}
|
||||
{
|
||||
ui_->setupUi(this);
|
||||
client_ = QSharedPointer<MatrixClient>(new MatrixClient("matrix.org"));
|
||||
|
@ -53,12 +55,40 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
connect(chat_page_, SIGNAL(close()), this, SLOT(showWelcomePage()));
|
||||
connect(chat_page_, SIGNAL(changeWindowTitle(QString)), this, SLOT(setWindowTitle(QString)));
|
||||
|
||||
connect(client_.data(),
|
||||
SIGNAL(initialSyncCompleted(const SyncResponse &)),
|
||||
this,
|
||||
SLOT(removeOverlayProgressBar()));
|
||||
|
||||
connect(client_.data(),
|
||||
SIGNAL(loginSuccess(QString, QString, QString)),
|
||||
this,
|
||||
SLOT(showChatPage(QString, QString, QString)));
|
||||
}
|
||||
|
||||
void MainWindow::removeOverlayProgressBar()
|
||||
{
|
||||
QTimer *timer = new QTimer(this);
|
||||
timer->setSingleShot(true);
|
||||
|
||||
connect(timer, &QTimer::timeout, [=]() {
|
||||
timer->deleteLater();
|
||||
|
||||
if (progress_modal_ != nullptr) {
|
||||
progress_modal_->deleteLater();
|
||||
progress_modal_->fadeOut();
|
||||
}
|
||||
|
||||
if (progress_modal_ != nullptr)
|
||||
spinner_->deleteLater();
|
||||
|
||||
progress_modal_ = nullptr;
|
||||
spinner_ = nullptr;
|
||||
});
|
||||
|
||||
timer->start(500);
|
||||
}
|
||||
|
||||
void MainWindow::showChatPage(QString userid, QString homeserver, QString token)
|
||||
{
|
||||
QSettings settings;
|
||||
|
@ -69,6 +99,17 @@ void MainWindow::showChatPage(QString userid, QString homeserver, QString token)
|
|||
int index = sliding_stack_->getWidgetIndex(chat_page_);
|
||||
sliding_stack_->slideInIndex(index, SlidingStackWidget::AnimationDirection::LEFT_TO_RIGHT);
|
||||
|
||||
if (spinner_ == nullptr) {
|
||||
spinner_ = new CircularProgress(this);
|
||||
spinner_->setColor("#acc7dc");
|
||||
spinner_->setSize(100);
|
||||
}
|
||||
|
||||
if (progress_modal_ == nullptr) {
|
||||
progress_modal_ = new OverlayModal(this, spinner_);
|
||||
progress_modal_->fadeIn();
|
||||
}
|
||||
|
||||
login_page_->reset();
|
||||
chat_page_->bootstrap(userid, homeserver, token);
|
||||
}
|
||||
|
|
190
src/ui/CircularProgress.cc
Normal file
190
src/ui/CircularProgress.cc
Normal file
|
@ -0,0 +1,190 @@
|
|||
#include <QPainter>
|
||||
#include <QParallelAnimationGroup>
|
||||
#include <QPen>
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
#include "CircularProgress.h"
|
||||
#include "Theme.h"
|
||||
|
||||
CircularProgress::CircularProgress(QWidget *parent)
|
||||
: QProgressBar{parent}
|
||||
, progress_type_{ui::ProgressType::IndeterminateProgress}
|
||||
, width_{6.25}
|
||||
, size_{64}
|
||||
{
|
||||
delegate_ = new CircularProgressDelegate(this);
|
||||
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
|
||||
auto group = new QParallelAnimationGroup(this);
|
||||
group->setLoopCount(-1);
|
||||
|
||||
auto length_animation = new QPropertyAnimation(this);
|
||||
length_animation->setPropertyName("dashLength");
|
||||
length_animation->setTargetObject(delegate_);
|
||||
length_animation->setEasingCurve(QEasingCurve::InOutQuad);
|
||||
length_animation->setStartValue(0.1);
|
||||
length_animation->setKeyValueAt(0.15, 0.2);
|
||||
length_animation->setKeyValueAt(0.6, 20);
|
||||
length_animation->setKeyValueAt(0.7, 20);
|
||||
length_animation->setEndValue(20);
|
||||
length_animation->setDuration(2050);
|
||||
|
||||
auto offset_animation = new QPropertyAnimation(this);
|
||||
offset_animation->setPropertyName("dashOffset");
|
||||
offset_animation->setTargetObject(delegate_);
|
||||
offset_animation->setEasingCurve(QEasingCurve::InOutSine);
|
||||
offset_animation->setStartValue(0);
|
||||
offset_animation->setKeyValueAt(0.15, 0);
|
||||
offset_animation->setKeyValueAt(0.6, -7);
|
||||
offset_animation->setKeyValueAt(0.7, -7);
|
||||
offset_animation->setEndValue(-25);
|
||||
offset_animation->setDuration(2050);
|
||||
|
||||
auto angle_animation = new QPropertyAnimation(this);
|
||||
angle_animation->setPropertyName("angle");
|
||||
angle_animation->setTargetObject(delegate_);
|
||||
angle_animation->setStartValue(0);
|
||||
angle_animation->setEndValue(719);
|
||||
angle_animation->setDuration(2050);
|
||||
|
||||
group->addAnimation(length_animation);
|
||||
group->addAnimation(offset_animation);
|
||||
group->addAnimation(angle_animation);
|
||||
|
||||
group->start();
|
||||
}
|
||||
|
||||
void CircularProgress::setProgressType(ui::ProgressType type)
|
||||
{
|
||||
progress_type_ = type;
|
||||
update();
|
||||
}
|
||||
|
||||
void CircularProgress::setLineWidth(qreal width)
|
||||
{
|
||||
width_ = width;
|
||||
update();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void CircularProgress::setSize(int size)
|
||||
{
|
||||
size_ = size;
|
||||
update();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
ui::ProgressType CircularProgress::progressType() const
|
||||
{
|
||||
return progress_type_;
|
||||
}
|
||||
|
||||
qreal CircularProgress::lineWidth() const
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
|
||||
int CircularProgress::size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
void CircularProgress::setColor(const QColor &color)
|
||||
{
|
||||
color_ = color;
|
||||
}
|
||||
|
||||
QColor CircularProgress::color() const
|
||||
{
|
||||
if (!color_.isValid()) {
|
||||
return QColor("red");
|
||||
}
|
||||
|
||||
return color_;
|
||||
}
|
||||
|
||||
QSize CircularProgress::sizeHint() const
|
||||
{
|
||||
const qreal s = size_ + width_ + 8;
|
||||
return QSize(s, s);
|
||||
}
|
||||
|
||||
void CircularProgress::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
/*
|
||||
* If the progress bar is disabled draw an X instead
|
||||
*/
|
||||
if (!isEnabled()) {
|
||||
QPen pen;
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
pen.setWidthF(lineWidth());
|
||||
pen.setColor("gray");
|
||||
|
||||
auto center = rect().center();
|
||||
|
||||
painter.setPen(pen);
|
||||
painter.drawLine(center - QPointF(20, 20), center + QPointF(20, 20));
|
||||
painter.drawLine(center + QPointF(20, -20), center - QPointF(20, -20));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (progress_type_ == ui::ProgressType::IndeterminateProgress) {
|
||||
painter.translate(width() / 2, height() / 2);
|
||||
painter.rotate(delegate_->angle());
|
||||
}
|
||||
|
||||
QPen pen;
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
pen.setWidthF(width_);
|
||||
pen.setColor(color());
|
||||
|
||||
if (ui::IndeterminateProgress == progress_type_) {
|
||||
QVector<qreal> pattern;
|
||||
pattern << delegate_->dashLength() * size_ / 50 << 30 * size_ / 50;
|
||||
|
||||
pen.setDashOffset(delegate_->dashOffset() * size_ / 50);
|
||||
pen.setDashPattern(pattern);
|
||||
|
||||
painter.setPen(pen);
|
||||
|
||||
painter.drawEllipse(QPoint(0, 0), size_ / 2, size_ / 2);
|
||||
} else {
|
||||
painter.setPen(pen);
|
||||
|
||||
const qreal x = (width() - size_) / 2;
|
||||
const qreal y = (height() - size_) / 2;
|
||||
|
||||
const qreal a = 360 * (value() - minimum()) / (maximum() - minimum());
|
||||
|
||||
QPainterPath path;
|
||||
path.arcMoveTo(x, y, size_, size_, 0);
|
||||
path.arcTo(x, y, size_, size_, 0, a);
|
||||
|
||||
painter.drawPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
CircularProgress::~CircularProgress()
|
||||
{
|
||||
}
|
||||
|
||||
CircularProgressDelegate::CircularProgressDelegate(CircularProgress *parent)
|
||||
: QObject(parent)
|
||||
, progress_(parent)
|
||||
, dash_offset_(0)
|
||||
, dash_length_(89)
|
||||
, angle_(0)
|
||||
{
|
||||
Q_ASSERT(parent);
|
||||
}
|
||||
|
||||
CircularProgressDelegate::~CircularProgressDelegate()
|
||||
{
|
||||
}
|
72
src/ui/OverlayModal.cc
Normal file
72
src/ui/OverlayModal.cc
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 3 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "OverlayModal.h"
|
||||
|
||||
OverlayModal::OverlayModal(QWidget *parent, QWidget *content)
|
||||
: OverlayWidget(parent)
|
||||
, duration_{500}
|
||||
, color_{QColor(55, 55, 55)}
|
||||
{
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(content);
|
||||
layout->setAlignment(Qt::AlignCenter);
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
opacity_ = new QGraphicsOpacityEffect(this);
|
||||
setGraphicsEffect(opacity_);
|
||||
|
||||
opacity_->setOpacity(1);
|
||||
animation_ = new QPropertyAnimation(opacity_, "opacity", this);
|
||||
animation_->setStartValue(1);
|
||||
animation_->setEndValue(0);
|
||||
animation_->setDuration(duration_);
|
||||
animation_->setEasingCurve(QEasingCurve::Linear);
|
||||
|
||||
connect(animation_, &QPropertyAnimation::finished, [this]() {
|
||||
if (animation_->direction() == QAbstractAnimation::Forward)
|
||||
this->close();
|
||||
});
|
||||
}
|
||||
|
||||
void OverlayModal::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
painter.fillRect(rect(), color_);
|
||||
}
|
||||
|
||||
void OverlayModal::fadeIn()
|
||||
{
|
||||
animation_->setDirection(QAbstractAnimation::Backward);
|
||||
animation_->start();
|
||||
show();
|
||||
}
|
||||
|
||||
void OverlayModal::fadeOut()
|
||||
{
|
||||
animation_->setDirection(QAbstractAnimation::Forward);
|
||||
animation_->start();
|
||||
}
|
|
@ -4,12 +4,11 @@
|
|||
OverlayWidget::OverlayWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
if (parent)
|
||||
if (parent) {
|
||||
parent->installEventFilter(this);
|
||||
}
|
||||
|
||||
OverlayWidget::~OverlayWidget()
|
||||
{
|
||||
setGeometry(overlayGeometry());
|
||||
raise();
|
||||
}
|
||||
}
|
||||
|
||||
bool OverlayWidget::event(QEvent *event)
|
||||
|
|
Loading…
Reference in a new issue