mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
Notifications: Handle Notifications without an action.
The policy that was said is that if a notification has no action, the client can and should display a close-button. This patch does it. In additon to that, the client needs a blacklist of closed notifcations otherwise they would re-appear next time the server notifications are fetched again. Also, changed the cleanup of not-longer-used widgets to be more robust.
This commit is contained in:
parent
0c944a06f9
commit
1fe5d6bb0c
@ -94,6 +94,9 @@ ActivityWidget::ActivityWidget(QWidget *parent) :
|
||||
|
||||
connect( _ui->_activityList, SIGNAL(activated(QModelIndex)), this,
|
||||
SLOT(slotOpenFile(QModelIndex)));
|
||||
|
||||
connect( &_removeTimer, SIGNAL(timeout()), this, SLOT(slotCheckToCleanWidgets()) );
|
||||
_removeTimer.setInterval(1000);
|
||||
}
|
||||
|
||||
ActivityWidget::~ActivityWidget()
|
||||
@ -231,18 +234,26 @@ void ActivityWidget::slotBuildNotificationDisplay(const ActivityList& list)
|
||||
QString listAccountName;
|
||||
|
||||
foreach( auto activity, list ) {
|
||||
if( _blacklistedActivities.contains(activity)) {
|
||||
qDebug() << Q_FUNC_INFO << "Activity in blacklist, skip";
|
||||
continue;
|
||||
}
|
||||
|
||||
NotificationWidget *widget = 0;
|
||||
|
||||
if( _widgetForNotifId.contains(activity._id) ) {
|
||||
widget = _widgetForNotifId[activity._id];
|
||||
if( _widgetForNotifId.contains( activity.ident()) ) {
|
||||
widget = _widgetForNotifId[activity.ident()];
|
||||
} else {
|
||||
widget = new NotificationWidget(this);
|
||||
connect(widget, SIGNAL(sendNotificationRequest(QString, QString, QString)),
|
||||
this, SLOT(slotSendNotificationRequest(QString, QString, QString)));
|
||||
connect(widget, SIGNAL(requestCleanupAndBlacklist(Activity)),
|
||||
this, SLOT(slotRequestCleanupAndBlacklist(Activity)));
|
||||
|
||||
_notificationsLayout->addWidget(widget);
|
||||
// _ui->_notifyScroll->setMinimumHeight( widget->height());
|
||||
_ui->_notifyScroll->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
|
||||
_widgetForNotifId[activity._id] = widget;
|
||||
_widgetForNotifId[activity.ident()] = widget;
|
||||
}
|
||||
|
||||
widget->setActivity( activity );
|
||||
@ -280,19 +291,20 @@ void ActivityWidget::slotBuildNotificationDisplay(const ActivityList& list)
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have widgets that have no corresponding activity from
|
||||
// check if there are widgets that have no corresponding activity from
|
||||
// the server any more. Collect them in a list
|
||||
QList<int> strayCats;
|
||||
QList< Activity::Identifier > strayCats;
|
||||
foreach( auto id, _widgetForNotifId.keys() ) {
|
||||
bool found = false;
|
||||
NotificationWidget *widget = _widgetForNotifId[id];
|
||||
|
||||
bool found = false;
|
||||
// do not mark widgets of other accounts to delete.
|
||||
if( widget->accountName() != listAccountName ) {
|
||||
if( widget->activity()._accName != listAccountName ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach( auto activity, list ) {
|
||||
if( activity._id == id ) {
|
||||
if( activity.ident() == id ) {
|
||||
// found an activity
|
||||
found = true;
|
||||
break;
|
||||
@ -307,8 +319,7 @@ void ActivityWidget::slotBuildNotificationDisplay(const ActivityList& list)
|
||||
// .. and now delete all these stray cat widgets.
|
||||
foreach( auto strayCatId, strayCats ) {
|
||||
NotificationWidget *widgetToGo = _widgetForNotifId[strayCatId];
|
||||
widgetToGo->deleteLater();
|
||||
_widgetForNotifId.remove(strayCatId);
|
||||
scheduleWidgetToRemove(widgetToGo, 0);
|
||||
}
|
||||
|
||||
_ui->_notifyLabel->setHidden( _widgetForNotifId.isEmpty() );
|
||||
@ -410,21 +421,60 @@ void ActivityWidget::slotNotifyServerFinished( const QString& reply, int replyCo
|
||||
// Add 200 millisecs to the predefined value to make sure that the timer in
|
||||
// widget's method readyToClose() has elapsed.
|
||||
if( replyCode == OCS_SUCCESS_STATUS_CODE ) {
|
||||
QTimer::singleShot(NOTIFICATION_WIDGET_CLOSE_AFTER_MILLISECS+200, this, SLOT(slotCleanWidgetList()));
|
||||
scheduleWidgetToRemove( job->widget() );
|
||||
}
|
||||
}
|
||||
|
||||
void ActivityWidget::slotCleanWidgetList()
|
||||
// blacklist the activity coming in here.
|
||||
void ActivityWidget::slotRequestCleanupAndBlacklist(const Activity& blacklistActivity)
|
||||
{
|
||||
foreach( int id, _widgetForNotifId.keys() ) {
|
||||
Q_ASSERT(_widgetForNotifId[id]);
|
||||
if( _widgetForNotifId[id]->readyToClose() ) {
|
||||
auto *widget = _widgetForNotifId[id];
|
||||
if ( ! _blacklistedActivities.contains(blacklistActivity) ) {
|
||||
_blacklistedActivities.append(blacklistActivity);
|
||||
}
|
||||
|
||||
NotificationWidget *widget = _widgetForNotifId[ blacklistActivity.ident() ];
|
||||
scheduleWidgetToRemove(widget);
|
||||
}
|
||||
|
||||
void ActivityWidget::scheduleWidgetToRemove(NotificationWidget *widget, int milliseconds)
|
||||
{
|
||||
if( !widget ) {
|
||||
return;
|
||||
}
|
||||
// in fife seconds from now, remove the widget.
|
||||
QDateTime removeTime = QDateTime::currentDateTime().addMSecs(milliseconds);
|
||||
|
||||
QPair<QDateTime, NotificationWidget*> removeInfo = qMakePair(removeTime, widget);
|
||||
if( !_widgetsToRemove.contains(removeInfo) ) {
|
||||
_widgetsToRemove.insert( removeInfo );
|
||||
if( !_removeTimer.isActive() ) {
|
||||
_removeTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called every second to see if widgets need to be removed.
|
||||
void ActivityWidget::slotCheckToCleanWidgets()
|
||||
{
|
||||
// loop over all widgets in the to-remove queue
|
||||
foreach( auto toRemove, _widgetsToRemove ) {
|
||||
QDateTime t = toRemove.first;
|
||||
NotificationWidget *widget = toRemove.second;
|
||||
|
||||
if( QDateTime::currentDateTime() > t ) {
|
||||
// found one to remove!
|
||||
Activity::Identifier id = widget->activity().ident();
|
||||
_widgetForNotifId.remove(id);
|
||||
delete widget;
|
||||
widget->deleteLater();
|
||||
_widgetsToRemove.remove(toRemove);
|
||||
}
|
||||
}
|
||||
|
||||
if( _widgetsToRemove.isEmpty() ) {
|
||||
_removeTimer.stop();
|
||||
}
|
||||
|
||||
// check to see if the whole notification pane should be hidden
|
||||
if( _widgetForNotifId.isEmpty() ) {
|
||||
_ui->_notifyLabel->setHidden(true);
|
||||
_ui->_notifyScroll->setHidden(true);
|
||||
|
||||
@ -66,6 +66,7 @@ public slots:
|
||||
void slotRefreshNotifications(AccountState *ptr);
|
||||
void slotRemoveAccount( AccountState *ptr );
|
||||
void slotAccountActivityStatus(AccountState *ast, int statusCode);
|
||||
void slotRequestCleanupAndBlacklist(const Activity& blacklistActivity);
|
||||
|
||||
signals:
|
||||
void guiLog(const QString&, const QString&);
|
||||
@ -80,7 +81,8 @@ private slots:
|
||||
void slotNotifyNetworkError( QNetworkReply* );
|
||||
void slotNotifyServerFinished( const QString& reply, int replyCode );
|
||||
void endNotificationRequest(NotificationWidget *widget , int replyCode);
|
||||
void slotCleanWidgetList();
|
||||
void scheduleWidgetToRemove(NotificationWidget *widget, int milliseconds = 4500);
|
||||
void slotCheckToCleanWidgets();
|
||||
|
||||
private:
|
||||
void showLabels();
|
||||
@ -89,9 +91,13 @@ private:
|
||||
QPushButton *_copyBtn;
|
||||
|
||||
QSet<QString> _accountsWithoutActivities;
|
||||
QMap<int, NotificationWidget*> _widgetForNotifId;
|
||||
QMap<Activity::Identifier, NotificationWidget*> _widgetForNotifId;
|
||||
QElapsedTimer _guiLogTimer;
|
||||
QSet<int> _guiLoggedNotifications;
|
||||
ActivityList _blacklistedActivities;
|
||||
|
||||
QSet< QPair<QDateTime, NotificationWidget*> > _widgetsToRemove;
|
||||
QTimer _removeTimer;
|
||||
|
||||
// number of currently running notification requests. If non zero,
|
||||
// no query for notifications is started.
|
||||
|
||||
@ -54,13 +54,22 @@ void NotificationWidget::setActivity(const Activity& activity)
|
||||
foreach( auto button, _ui._buttonBox->buttons() ) {
|
||||
_ui._buttonBox->removeButton(button);
|
||||
}
|
||||
_buttons.clear();
|
||||
|
||||
// display buttons for the links
|
||||
foreach( auto link, activity._links ) {
|
||||
QPushButton *b = _ui._buttonBox->addButton( link._label, QDialogButtonBox::AcceptRole);
|
||||
b->setDefault(link._isPrimary);
|
||||
if( activity._links.isEmpty() ) {
|
||||
// in case there is no action defined, do a close button.
|
||||
QPushButton *b = _ui._buttonBox->addButton( QDialogButtonBox::Close );
|
||||
b->setDefault(true);
|
||||
connect(b, SIGNAL(clicked()), this, SLOT(slotButtonClicked()));
|
||||
_buttons.append(b);
|
||||
} else {
|
||||
foreach( auto link, activity._links ) {
|
||||
QPushButton *b = _ui._buttonBox->addButton(link._label, QDialogButtonBox::AcceptRole);
|
||||
b->setDefault(link._isPrimary);
|
||||
connect(b, SIGNAL(clicked()), this, SLOT(slotButtonClicked()));
|
||||
_buttons.append(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,12 +93,24 @@ void NotificationWidget::slotButtonClicked()
|
||||
}
|
||||
|
||||
// if the button was found, the link must be called
|
||||
if( index > -1 && _myActivity._links.count() == 0 ) {
|
||||
// no links, that means it was the close button
|
||||
// empty link. Just close and remove the widget.
|
||||
QString doneText = tr("Closing in a few seconds...");
|
||||
_ui._timeLabel->setText(doneText);
|
||||
emit requestCleanupAndBlacklist(_myActivity);
|
||||
return;
|
||||
}
|
||||
|
||||
if( index > -1 && index < _myActivity._links.count() ) {
|
||||
ActivityLink triggeredLink = _myActivity._links.at(index);
|
||||
_actionLabel = triggeredLink._label;
|
||||
qDebug() << Q_FUNC_INFO << "Notification Link: "<< triggeredLink._verb << triggeredLink._link;
|
||||
_progressIndi->startAnimation();
|
||||
emit sendNotificationRequest( _accountName, triggeredLink._link, triggeredLink._verb );
|
||||
|
||||
if( ! triggeredLink._link.isEmpty() ) {
|
||||
qDebug() << Q_FUNC_INFO << "Notification Link: "<< triggeredLink._verb << triggeredLink._link;
|
||||
_progressIndi->startAnimation();
|
||||
emit sendNotificationRequest( _accountName, triggeredLink._link, triggeredLink._verb );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,12 +137,6 @@ void NotificationWidget::slotNotificationRequestFinished(int statusCode)
|
||||
|
||||
//* The second parameter is a time, such as 'selected at 09:58pm'
|
||||
doneText = tr("'%1' selected at %2").arg(_actionLabel).arg(timeStr);
|
||||
|
||||
// start a timer, so that activity widget can remove this widget after a
|
||||
// certain time. It needs to be done by ActivityWidget because it also
|
||||
// needs to hide the scrollview if no widget is left any more.
|
||||
// method readyToClose() checks for the timer value to see if it is expired
|
||||
_closeTimer.start();
|
||||
}
|
||||
_ui._timeLabel->setText( doneText );
|
||||
|
||||
@ -129,9 +144,4 @@ void NotificationWidget::slotNotificationRequestFinished(int statusCode)
|
||||
|
||||
}
|
||||
|
||||
bool NotificationWidget::readyToClose()
|
||||
{
|
||||
return _closeTimer.isValid() && _closeTimer.elapsed() > NOTIFICATION_WIDGET_CLOSE_AFTER_MILLISECS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ public:
|
||||
|
||||
signals:
|
||||
void sendNotificationRequest( const QString&, const QString& link, const QString& verb);
|
||||
void requestCleanupAndBlacklist( const Activity& activity );
|
||||
|
||||
public slots:
|
||||
void setActivity(const Activity& activity);
|
||||
@ -52,7 +53,6 @@ private:
|
||||
QString _accountName;
|
||||
QProgressIndicator *_progressIndi;
|
||||
QString _actionLabel;
|
||||
QElapsedTimer _closeTimer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user