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"