File indexing completed on 2024-12-15 03:45:05

0001 /*
0002     SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "notificationpopup.h"
0008 #include "ui_notificationpopup.h"
0009 #include "feedbackconfigdialog.h"
0010 
0011 #include <provider.h>
0012 #include <surveyinfo.h>
0013 
0014 #include <QApplication>
0015 #include <QDebug>
0016 #include <QDesktopServices>
0017 #include <QKeyEvent>
0018 #include <QPropertyAnimation>
0019 #include <QStyle>
0020 
0021 using namespace KUserFeedback;
0022 
0023 namespace KUserFeedback {
0024 namespace Ui
0025 {
0026 class NotificationPopup;
0027 }
0028 
0029 class NotificationPopupPrivate {
0030 public:
0031     NotificationPopupPrivate(QWidget *qq);
0032     void showEncouragement();
0033     void surveyAvailable(const SurveyInfo &info);
0034 
0035     void showPopup();
0036     void hidePopup();
0037     void action();
0038     void reposition();
0039     int xPosition() const;
0040 
0041     static QString appName();
0042 
0043     Provider *provider;
0044     SurveyInfo survey;
0045     QPropertyAnimation *animation;
0046     std::unique_ptr<Ui::NotificationPopup> ui;
0047     QWidget *q;
0048 };
0049 
0050 }
0051 
0052 NotificationPopupPrivate::NotificationPopupPrivate(QWidget *qq) :
0053     provider(nullptr),
0054     animation(nullptr),
0055     q(qq)
0056 {
0057 }
0058 
0059 void NotificationPopupPrivate::showEncouragement()
0060 {
0061     if (q->isVisible())
0062         return;
0063 
0064     survey = SurveyInfo();
0065     const auto name = appName();
0066     if (name.isEmpty()) {
0067         ui->title->setText(NotificationPopup::tr("Help us make this application better!"));
0068         ui->message->setText(NotificationPopup::tr("You can help us improving this application by sharing statistics and participate in surveys."));
0069     } else {
0070         ui->title->setText(NotificationPopup::tr("Help us make %1 better!").arg(name));
0071         ui->message->setText(NotificationPopup::tr("You can help us improving %1 by sharing statistics and participate in surveys.").arg(name));
0072     }
0073     ui->actionButton->setText(NotificationPopup::tr("Contribute..."));
0074     showPopup();
0075 }
0076 
0077 void NotificationPopupPrivate::surveyAvailable(const SurveyInfo &info)
0078 {
0079     if (q->isVisible())
0080         return;
0081 
0082     survey = info;
0083     const auto name = appName();
0084     ui->title->setText(NotificationPopup::tr("We are looking for your feedback!"));
0085     if (name.isEmpty())
0086         ui->message->setText(NotificationPopup::tr("We would like a few minutes of your time to provide feedback about this application in a survey."));
0087     else
0088         ui->message->setText(NotificationPopup::tr("We would like a few minutes of your time to provide feedback about %1 in a survey.").arg(name));
0089     ui->actionButton->setText(NotificationPopup::tr("Participate"));
0090     showPopup();
0091 }
0092 
0093 void NotificationPopupPrivate::showPopup()
0094 {
0095     q->show();
0096 
0097     q->resize(q->sizeHint());
0098     const auto startPos = QPoint(xPosition(), q->parentWidget()->height());
0099     q->move(startPos);
0100 
0101     if (!animation)
0102         animation = new QPropertyAnimation(q, "pos", q);
0103     animation->setStartValue(startPos);
0104     animation->setEndValue(QPoint(xPosition(), q->parentWidget()->height() - q->height()));
0105     animation->setDuration(100);
0106     animation->setEasingCurve(QEasingCurve::InQuad);
0107     animation->start();
0108 
0109     ui->actionButton->setFocus();
0110 }
0111 
0112 void NotificationPopupPrivate::hidePopup()
0113 {
0114     if (animation)
0115         animation->stop();
0116     q->hide();
0117 }
0118 
0119 void NotificationPopupPrivate::action()
0120 {
0121     if (survey.isValid()) {
0122         QDesktopServices::openUrl(survey.url());
0123         provider->surveyCompleted(survey);
0124     } else {
0125         FeedbackConfigDialog dlg(q);
0126         dlg.setFeedbackProvider(provider);
0127         dlg.exec();
0128     }
0129 
0130     hidePopup();
0131 }
0132 
0133 void NotificationPopupPrivate::reposition()
0134 {
0135     const auto pos = QPoint(xPosition(), q->parentWidget()->height() - q->height());
0136     if (animation->state() == QAbstractAnimation::Running)
0137         animation->setEndValue(pos);
0138     else
0139         q->move(pos);
0140 }
0141 
0142 int NotificationPopupPrivate::xPosition() const
0143 {
0144     if (QApplication::layoutDirection() == Qt::LeftToRight) {
0145         return q->parentWidget()->width() - q->width();
0146     }
0147     return 0;
0148 }
0149 
0150 QString NotificationPopupPrivate::appName()
0151 {
0152     return QGuiApplication::applicationDisplayName();
0153 }
0154 
0155 
0156 NotificationPopup::NotificationPopup(QWidget* parent)
0157     : QWidget(parent)
0158     , d(new NotificationPopupPrivate(this))
0159 {
0160     Q_ASSERT(parent);
0161 
0162     d->ui.reset(new Ui::NotificationPopup);
0163     d->ui->setupUi(this);
0164 
0165     d->ui->frame->setAutoFillBackground(true);
0166     d->ui->closeButton->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
0167     connect(d->ui->actionButton, &QPushButton::clicked, this, [this]() { d->action(); });
0168     connect(d->ui->closeButton, &QPushButton::clicked, this, [this]() { d->hidePopup(); });
0169 
0170     parent->installEventFilter(this);
0171     setVisible(false);
0172 }
0173 
0174 NotificationPopup::~NotificationPopup()
0175 {
0176 }
0177 
0178 void NotificationPopup::setFeedbackProvider(Provider* provider)
0179 {
0180     Q_ASSERT(provider);
0181     d->provider = provider;
0182     connect(provider, &Provider::showEncouragementMessage, this, [this]() { d->showEncouragement(); });
0183     connect(provider, &Provider::surveyAvailable, this, [this](const SurveyInfo &info) { d->surveyAvailable(info); });
0184 }
0185 
0186 void NotificationPopup::keyReleaseEvent(QKeyEvent* event)
0187 {
0188     if (isVisible() && event->key() == Qt::Key_Escape)
0189         d->hidePopup();
0190 }
0191 
0192 bool NotificationPopup::eventFilter(QObject* receiver, QEvent* event)
0193 {
0194     if (receiver == parentWidget() && isVisible()) {
0195         d->reposition();
0196     }
0197     return QWidget::eventFilter(receiver, event);
0198 }
0199 
0200 #include "moc_notificationpopup.cpp"