Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: 增加应用内通知动画 #592

Merged
merged 1 commit into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/widgets/dfloatingmessage.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand Down Expand Up @@ -38,6 +38,7 @@ class DFloatingMessage : public DFloatingWidget

Q_SIGNALS:
void closeButtonClicked();
void messageClosed();

protected:
using DFloatingWidget::setWidget;
Expand Down
8 changes: 5 additions & 3 deletions include/widgets/dmessagemanager.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2022 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#ifndef DMESSAGEMANAGER_H
#define DMESSAGEMANAGER_H

#include <QObject>
#include <DObject>
#include <QWidget>
#include <dtkwidget_global.h>
#include <dtkgui_global.h>
Expand All @@ -16,20 +16,22 @@

DWIDGET_BEGIN_NAMESPACE
class DFloatingMessage;
class DMessageManager: public QObject
class DMessageManagerPrivate;
class DMessageManager: public QObject, public DCORE_NAMESPACE::DObject
{
Q_OBJECT
D_DECLARE_PRIVATE(DMessageManager)

private:
DMessageManager(); //构造函数是私有的

public:
static DMessageManager *instance();

Check warning on line 29 in include/widgets/dmessagemanager.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

function DMessageManager * DMessageManager::instance is not documented!

void sendMessage(QWidget *par, DFloatingMessage *floMsg);
void sendMessage(QWidget *par, const QIcon &icon, const QString &message);

Check warning on line 32 in include/widgets/dmessagemanager.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

function void DMessageManager::sendMessage is not documented!
void sendMessage(QWidget *par, const DGUI_NAMESPACE::DDciIcon &icon, const QString &message);

Check warning on line 33 in include/widgets/dmessagemanager.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

function void Dtk::Widget::DMessageManager::sendMessage is not documented!
bool setContentMargens(QWidget *par, const QMargins &margins);

Check warning on line 34 in include/widgets/dmessagemanager.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

function bool DMessageManager::setContentMargens is not documented!

protected:
bool eventFilter(QObject *watched, QEvent *event) override;
Expand Down
21 changes: 18 additions & 3 deletions src/widgets/dfloatingmessage.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand All @@ -11,6 +11,7 @@
#include <QTimer>
#include <QLabel>
#include <QDebug>
#include <QGraphicsDropShadowEffect>

class MessageLabel : public QLabel
{
Expand Down Expand Up @@ -54,13 +55,17 @@ void DFloatingMessagePrivate::init()
iconButton->setIconSize(DSizeModeHelper::element(QSize(20, 20), QSize(30, 30)));

hBoxLayout->addWidget(iconButton);
hBoxLayout->addSpacing(10);
hBoxLayout->addWidget(labMessage);

if (notifyType == DFloatingMessage::MessageType::TransientType) { //临时消息
timer = new QTimer(q);
timer->setInterval(4000);
timer->setSingleShot(true);
q->connect(timer, &QTimer::timeout, q, &DFloatingMessage::close);
q->connect(timer, &QTimer::timeout, q, [q]() {
q->close();
Q_EMIT q->messageClosed();
});
} else { //常驻消息
content = nullptr;
closeButton = new DDialogCloseButton(q);
Expand All @@ -69,8 +74,18 @@ void DFloatingMessagePrivate::init()

hBoxLayout->addWidget(closeButton);
q->connect(closeButton, &DIconButton::clicked, q, &DFloatingMessage::closeButtonClicked);
q->connect(closeButton, &DIconButton::clicked, q, &DFloatingMessage::close);
q->connect(closeButton, &DIconButton::clicked, q, [q]() {
q->close();
Q_EMIT q->messageClosed();
});
}

auto effect = new QGraphicsDropShadowEffect(q);
effect->setColor(QColor(0, 0, 0, 0.1 * 255));
effect->setBlurRadius(20);
effect->setXOffset(0);
effect->setYOffset(2);
q->setGraphicsEffect(effect);
}

/*!
Expand Down
127 changes: 111 additions & 16 deletions src/widgets/dmessagemanager.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2022 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "dmessagemanager.h"
#include "private/dmessagemanager_p.h"

#include <DFloatingMessage>
#include <DDciIcon>

#include <QVBoxLayout>
#include <QEvent>
#include <QPainter>

#define D_MESSAGE_MANAGER_CONTENT "_d_message_manager_content"
const int MARGIN = 20;
const int MESSGAE_HEIGHT = 50;
const int ANIMATION_DURATION = 400;

Q_DECLARE_METATYPE(QMargins)

class ImageLabel : public QLabel {
Q_OBJECT
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
public:
explicit ImageLabel(QWidget *parent=nullptr)
: QLabel (parent)
, m_opacity(0)
{
};
void setOpacity(qreal opac) { m_opacity = opac; }
qreal opacity() { return m_opacity ;}

protected:
void paintEvent(QPaintEvent *e) override
{
Q_UNUSED(e)
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
p.setOpacity(m_opacity);
p.drawPixmap(rect().marginsRemoved(contentsMargins()), *pixmap());
};
private:
qreal m_opacity;
};

// 仅仅为了接口兼容, 符号不会减少, 如果使用了这个接口,实际调用走的有namespace的
class Q_DECL_EXPORT DMessageManager: public QObject
{
Expand Down Expand Up @@ -91,7 +120,30 @@ static void sendMessage_helper(DMessageManager *manager, QWidget *par, IconType
manager->sendMessage(par, floMsg);
}

DMessageManagerPrivate::DMessageManagerPrivate(DMessageManager *qq)
: DObjectPrivate(qq)
, m_aniGeometry(new QPropertyAnimation(qq))
, m_aniOpacity(new QPropertyAnimation(qq))
, m_aniGroup(new QParallelAnimationGroup(qq))
, m_label(new ImageLabel)
{
m_aniGeometry->setPropertyName("geometry");
m_aniGeometry->setDuration(ANIMATION_DURATION);
m_aniGeometry->setEasingCurve(QEasingCurve::OutCubic);

m_aniOpacity->setPropertyName("opacity");
m_aniOpacity->setDuration(ANIMATION_DURATION);
m_aniOpacity->setEasingCurve(QEasingCurve::OutCubic);
m_aniOpacity->setTargetObject(m_label);
m_aniOpacity->setStartValue(0);
m_aniOpacity->setEndValue(1);

m_aniGroup->addAnimation(m_aniGeometry);
m_aniGroup->addAnimation(m_aniOpacity);
}

DMessageManager::DMessageManager() //私有静态构造函数
: DObject(*new DMessageManagerPrivate(this))
{
}

Expand All @@ -114,6 +166,7 @@ DMessageManager *DMessageManager::instance() //公有静态函数
*/
void DMessageManager::sendMessage(QWidget *par, DFloatingMessage *floMsg)
{
D_D(DMessageManager);
QWidget *content = par->findChild<QWidget *>(D_MESSAGE_MANAGER_CONTENT, Qt::FindDirectChildrenOnly);

if (!content) {
Expand All @@ -125,18 +178,68 @@ void DMessageManager::sendMessage(QWidget *par, DFloatingMessage *floMsg)
if (par->property("_d_margins").isValid())
content->setContentsMargins(magins);
else
content->setContentsMargins(QMargins(20, 0, 20, 0));
content->setContentsMargins(QMargins(MARGIN, 0, MARGIN, 0));

content->installEventFilter(this);
par->installEventFilter(this);
QVBoxLayout *layout = new QVBoxLayout(content);
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->setDirection(QBoxLayout::BottomToTop);
content->show();
}

if (content->layout()->count() >= 1) {
content->layout()->itemAt(content->layout()->count() - 1)->widget()->hide();
delete content->layout()->takeAt(content->layout()->count() - 1);
}

static_cast<QBoxLayout*>(content->layout())->addWidget(floMsg, 0, Qt::AlignHCenter);

// 限制通知消息的最大宽度
for (DFloatingMessage *message : content->findChildren<DFloatingMessage*>(QString(), Qt::FindDirectChildrenOnly)) {
message->setMaximumWidth(par->rect().marginsRemoved(content->contentsMargins()).width());
message->setMinimumHeight(message->sizeHint().height());
}

QRect geometry(QPoint(0, 0), floMsg->sizeHint() + QSize(MARGIN * 2, 0));
geometry.moveCenter(par->rect().center());
geometry.moveBottom(par->rect().bottom() - MESSGAE_HEIGHT);

content->setGeometry(geometry);
content->hide();

if (d->m_aniGeometry->state() == QPropertyAnimation::State::Running)
return;

d->m_label->setParent(par);
d->m_label->setAlignment(Qt::AlignCenter);
d->m_label->setContentsMargins(MARGIN, 0, MARGIN, 0);
d->m_label->setPixmap(floMsg->grab());
d->m_label->setScaledContents(true);
d->m_label->show();
d->m_aniGeometry->setTargetObject(d->m_label);
d->m_aniOpacity->setTargetObject(d->m_label);
d->m_aniGeometry->setStartValue(QRect(par->rect().center().x(), par->rect().bottom(), 0, 0));
d->m_aniGeometry->setEndValue(content->geometry());
d->m_aniGroup->start();
connect(d->m_aniGroup, &QPropertyAnimation::finished, this, [d, content]() {
if (d->m_aniGroup->direction() == QAbstractAnimation::Backward) {
d->m_aniGroup->setDirection(QAbstractAnimation::Forward);
} else {
content->show();
}
d->m_label->hide();
});

connect(floMsg, &DFloatingMessage::messageClosed, [=, this]() {
d->m_aniGeometry->setStartValue(QRect(par->rect().center().x(), par->rect().bottom(), 0, 0));
d->m_aniGeometry->setEndValue(content->geometry());
d->m_label->setPixmap(floMsg->grab());

d->m_aniGroup->setDirection(QAbstractAnimation::Backward);
d->m_label->show();
d->m_aniGroup->start();
});
}

/*!
Expand Down Expand Up @@ -184,27 +287,19 @@ bool DMessageManager::setContentMargens(QWidget *par, const QMargins &margins)
*/
bool DMessageManager::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::LayoutRequest || event->type() == QEvent::Resize) {
if (QWidget *widget = qobject_cast<QWidget *>(watched)) {
QWidget *content;

if (widget->objectName() == D_MESSAGE_MANAGER_CONTENT) {
content = widget;
} else {
content = widget->findChild<QWidget*>(D_MESSAGE_MANAGER_CONTENT, Qt::FindDirectChildrenOnly);
}
if (event->type() == QEvent::Resize) {
if (auto content = watched->findChild<QWidget *>(D_MESSAGE_MANAGER_CONTENT, Qt::FindDirectChildrenOnly)) {

QWidget *par = content->parentWidget();
auto par = qobject_cast<QWidget *>(watched);

// 限制通知消息的最大宽度
for (DFloatingMessage *message : content->findChildren<DFloatingMessage*>(QString(), Qt::FindDirectChildrenOnly)) {
message->setMaximumWidth(par->rect().marginsRemoved(content->contentsMargins()).width());
message->setMinimumHeight(message->sizeHint().height());
}

QRect geometry(QPoint(0, 0), content->sizeHint());
geometry.moveCenter(par->rect().center());
geometry.moveBottom(par->rect().bottom());
geometry.moveBottom(par->rect().bottom() - MESSGAE_HEIGHT);
content->setGeometry(geometry);
}
} else if (event->type() == QEvent::ChildRemoved) {
Expand Down
11 changes: 10 additions & 1 deletion src/widgets/dstyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,9 +1339,18 @@ void DStyle::drawPrimitive(const QStyle *style, DStyle::PrimitiveElement pe, con
//先绘画阴影
DDrawUtils::drawShadow(p, btn->rect + shadow_margin, frameRadius, frameRadius, QColor(0, 0, 0, 0.25 * 255), shadowRadius, QPoint(offsetX, offsetY));
//再绘画上面的待显示区域
p->setPen(QPen(btn->dpalette.frameShadowBorder(), 1));
p->setPen(Qt::NoPen);
p->setBrush(btn->noBackground ? Qt::NoBrush : p->background());
p->drawRoundedRect(opt->rect, frameRadius, frameRadius);

p->setBrush(Qt::NoBrush);
QPen pen;
pen.setWidth(1);
pen.setColor(DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::DarkType
? QColor(255, 255, 255, int(0.1 * 255))
: QColor(0, 0, 0, int(0.12 * 255)));
p->setPen(pen);
p->drawRoundedRect(opt->rect, frameRadius, frameRadius);
}
break;
}
Expand Down
33 changes: 33 additions & 0 deletions src/widgets/private/dmessagemanager_p.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#ifndef DABOUTDIALOG_P_H
#define DABOUTDIALOG_P_H

#include "dmessagemanager.h"

#include <DObjectPrivate>

#include <QLabel>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>

DWIDGET_BEGIN_NAMESPACE

class DMessageManagerPrivate : public DCORE_NAMESPACE::DObjectPrivate
{
public:
DMessageManagerPrivate(DMessageManager *qq);

Check warning on line 21 in src/widgets/private/dmessagemanager_p.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

function Dtk::Widget::DMessageManagerPrivate::DMessageManagerPrivate is not documented!

QPropertyAnimation *m_aniGeometry;

Check warning on line 23 in src/widgets/private/dmessagemanager_p.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

variable QPropertyAnimation* Dtk::Widget::DMessageManagerPrivate::m_aniGeometry is not documented!
QPropertyAnimation *m_aniOpacity;;

Check warning on line 24 in src/widgets/private/dmessagemanager_p.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

variable QPropertyAnimation* Dtk::Widget::DMessageManagerPrivate::m_aniOpacity is not documented!
QParallelAnimationGroup *m_aniGroup;

Check warning on line 25 in src/widgets/private/dmessagemanager_p.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

variable QParallelAnimationGroup* Dtk::Widget::DMessageManagerPrivate::m_aniGroup is not documented!
QLabel *m_label;

Check warning on line 26 in src/widgets/private/dmessagemanager_p.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

variable QLabel* Dtk::Widget::DMessageManagerPrivate::m_label is not documented!

D_DECLARE_PUBLIC(DMessageManager);

Check warning on line 28 in src/widgets/private/dmessagemanager_p.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

function Dtk::Widget::DMessageManagerPrivate::D_DECLARE_PUBLIC is not documented!
};

DWIDGET_END_NAMESPACE

#endif // DABOUTDIALOG_P_H
Loading