[Pkg-owncloud-commits] [owncloud-client] 129/470: Display server notifications on the client (#3733)

Sandro Knauß hefee-guest at moszumanska.debian.org
Thu May 12 16:24:54 UTC 2016


This is an automated email from the git hooks/post-receive script.

hefee-guest pushed a commit to branch master
in repository owncloud-client.

commit 32e16b323c24f4b90da8cf31831a1b875675b676
Author: Klaas Freitag <freitag at owncloud.com>
Date:   Fri Mar 4 17:41:57 2016 +0100

    Display server notifications on the client (#3733)
    
    As interaction is required, the notifications are displayed in a
    separate widget above the server activity list.
    
    Note that design and also where we display the notifications can
    still be discussed and changed.
---
 src/gui/CMakeLists.txt     |   3 +
 src/gui/activitywidget.cpp | 164 +++++++++++++++++++++++++++++++++++++++++++++
 src/gui/activitywidget.h   |  38 ++++++++++-
 src/gui/activitywidget.ui  |  43 +++++++++++-
 4 files changed, 244 insertions(+), 4 deletions(-)

diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 2cf4886..d7c12b8 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -32,6 +32,7 @@ set(client_UI
     owncloudsetuppage.ui
     addcertificatedialog.ui
     proxyauthdialog.ui
+    notificationwidget.ui
     wizard/owncloudadvancedsetuppage.ui
     wizard/owncloudconnectionmethoddialog.ui
     wizard/owncloudhttpcredspage.ui
@@ -84,6 +85,8 @@ set(client_SRCS
     proxyauthhandler.cpp
     proxyauthdialog.cpp
     synclogdialog.cpp
+    notificationwidget.cpp
+    notificationconfirmjob.cpp
     creds/credentialsfactory.cpp
     creds/httpcredentialsgui.cpp
     creds/shibbolethcredentials.cpp
diff --git a/src/gui/activitywidget.cpp b/src/gui/activitywidget.cpp
index 2fa67fa..0347b43 100644
--- a/src/gui/activitywidget.cpp
+++ b/src/gui/activitywidget.cpp
@@ -33,6 +33,8 @@
 #include "activityitemdelegate.h"
 #include "protocolwidget.h"
 #include "QProgressIndicator.h"
+#include "notificationwidget.h"
+#include "notificationconfirmjob.h"
 
 #include "ui_activitywidget.h"
 
@@ -52,6 +54,20 @@ QString ActivityList::accountName() const
 
 /* ==================================================================== */
 
+QHash <QString, QVariant> ActivityLink::toVariantHash()
+{
+    QHash<QString, QVariant> hash;
+
+    hash["label"] = _label;
+    hash["link"]  = _link;
+    hash["verb"]  = _verb;
+    hash["primary"] = _isPrimary;
+
+    return hash;
+}
+
+/* ==================================================================== */
+
 ActivityListModel::ActivityListModel(QWidget *parent)
     :QAbstractListModel(parent)
 {
@@ -176,6 +192,7 @@ void ActivityListModel::slotActivitiesReceived(const QVariantMap& json, int stat
         auto json = activ.toMap();
 
         Activity a;
+        a._type = Activity::ActivityType;
         a._accName  = ast->account()->displayName();
         a._id       = json.value("id").toLongLong();
         a._subject  = json.value("subject").toString();
@@ -277,6 +294,16 @@ ActivityWidget::ActivityWidget(QWidget *parent) :
     _ui->_activityList->setAlternatingRowColors(true);
     _ui->_activityList->setModel(_model);
 
+    _ui->_notifyLabel->hide();
+    _ui->_notifyScroll->hide();
+
+    // Create a widget container for the notifications. The ui file defines
+    // a scroll area that get a widget with a layout as children
+    QWidget *w = new QWidget(this);
+    _notificationsLayout = new QVBoxLayout(this);
+    w->setLayout(_notificationsLayout);
+    _ui->_notifyScroll->setWidget(w);
+
     showLabels();
 
     connect(_model, SIGNAL(activityJobStatusCode(AccountState*,int)),
@@ -290,6 +317,9 @@ ActivityWidget::ActivityWidget(QWidget *parent) :
 
     connect( _ui->_activityList, SIGNAL(activated(QModelIndex)), this,
              SLOT(slotOpenFile(QModelIndex)));
+
+    connect( this, SIGNAL(newNotificationList(ActivityList)), this,
+             SLOT(slotBuildNotificationDisplay(ActivityList)) );
 }
 
 ActivityWidget::~ActivityWidget()
@@ -300,6 +330,7 @@ ActivityWidget::~ActivityWidget()
 void ActivityWidget::slotRefresh(AccountState *ptr)
 {
     _model->slotRefreshActivity(ptr);
+    slotFetchNotifications(ptr);
 }
 
 void ActivityWidget::slotRemoveAccount( AccountState *ptr )
@@ -313,6 +344,8 @@ void ActivityWidget::showLabels()
     _ui->_headerLabel->setTextFormat(Qt::RichText);
     _ui->_headerLabel->setText(t);
 
+    _ui->_notifyLabel->setText(tr("Action Required: Notifications"));
+
     t.clear();
     QSetIterator<QString> i(_accountsWithoutActivities);
     while (i.hasNext() ) {
@@ -400,6 +433,137 @@ void ActivityWidget::slotOpenFile(QModelIndex indx)
     }
 }
 
+void ActivityWidget::slotFetchNotifications(AccountState *ptr)
+{
+    /* start the notification fetch job as well */
+    if( !ptr) {
+        return;
+    }
+
+    // if the previous notification job has finished, start next.
+    if( !_notificationJob ) {
+        _notificationJob = new JsonApiJob( ptr->account(), QLatin1String("ocs/v2.php/apps/notifications/api/v1/notifications"), this );
+        QObject::connect(_notificationJob.data(), SIGNAL(jsonReceived(QVariantMap, int)),
+                         this, SLOT(slotNotificationsReceived(QVariantMap, int)));
+        _notificationJob->setProperty("AccountStatePtr", QVariant::fromValue<AccountState*>(ptr));
+
+        qDebug() << "Start fetching notifications for " << ptr->account()->displayName();
+        _notificationJob->start();
+    } else {
+        qDebug() << "Notification Job still running, not starting a new one.";
+    }
+}
+
+
+void ActivityWidget::slotNotificationsReceived(const QVariantMap& json, int statusCode)
+{
+    if( statusCode != 200 ) {
+        qDebug() << "Failed for Notifications";
+        return;
+    }
+
+    auto notifies = json.value("ocs").toMap().value("data").toList();
+
+    AccountState* ai = qvariant_cast<AccountState*>(sender()->property("AccountStatePtr"));
+
+    qDebug() << "Notifications for " << ai->account()->displayName() << notifies;
+
+    ActivityList list;
+
+    foreach( auto element, notifies ) {
+        Activity a;
+        auto json   = element.toMap();
+        a._type     = Activity::NotificationType;
+        a._accName  = ai->account()->displayName();
+        a._id       = json.value("notification_id").toLongLong();
+        a._subject  = json.value("subject").toString();
+        a._message  = json.value("message").toString();
+        QString s   = json.value("link").toString();
+        if( !s.isEmpty() ) {
+            a._link     = QUrl(s);
+        }
+        a._dateTime = json.value("datetime").toDateTime();
+        a._dateTime.setTimeSpec(Qt::UTC);
+
+        auto actions = json.value("actions").toList();
+        foreach( auto action, actions) {
+            auto actionJson = action.toMap();
+            ActivityLink al;
+            al._label = QUrl::fromPercentEncoding(actionJson.value("label").toByteArray());
+            al._link  = actionJson.value("link").toString();
+            al._verb  = actionJson.value("type").toString();
+            al._isPrimary = actionJson.value("primary").toBool();
+
+            a._links.append(al);
+        }
+
+        list.append(a);
+    }
+    emit newNotificationList( list );
+}
+
+// GUI: Display the notifications
+void ActivityWidget::slotBuildNotificationDisplay(const ActivityList& list)
+{
+    foreach( auto activity, list ) {
+        NotificationWidget *widget = 0;
+
+        if( _widgetForNotifId.contains(activity._id) ) {
+            widget = _widgetForNotifId[activity._id];
+        } else {
+            widget = new NotificationWidget(this);
+            connect(widget, SIGNAL(sendNotificationRequest(QString, QString, QString)),
+                    this, SLOT(slotSendNotificationRequest(QString, QString, QString)));
+            _notificationsLayout->addWidget(widget);
+            // _ui->_notifyScroll->setMinimumHeight( widget->height());
+            _ui->_notifyScroll->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
+            _widgetForNotifId[activity._id] = widget;
+        }
+
+        widget->setAccountName( activity._accName );
+        widget->setActivity( activity );
+    }
+    _ui->_notifyLabel->setHidden( list.count() == 0 );
+    _ui->_notifyScroll->setHidden( list.count() == 0 );
+}
+
+void ActivityWidget::slotSendNotificationRequest(const QString& accountName, const QString& link, const QString& verb)
+{
+    qDebug() << "Server Notification Request " << verb << link << "on account" << accountName;
+
+    const QStringList validVerbs = QStringList() << "GET" << "PUT" << "POST" << "DELETE";
+
+    if( validVerbs.contains(verb)) {
+        AccountStatePtr acc = AccountManager::instance()->account(accountName);
+        if( acc ) {
+            NotificationConfirmJob *job = new NotificationConfirmJob(acc->account());
+            QString myLink(link);
+            QUrl l(myLink);
+            job->setLinkAndVerb(l, verb);
+            connect( job, SIGNAL( networkError(QNetworkReply*)),
+                                  this, SLOT(slotNotifyNetworkError(QNetworkReply*)));
+            connect( job, SIGNAL( jobFinished(QString, int)),
+                     this, SLOT(slotNotifyServerFinished(QString, int)) );
+            job->start();
+        }
+    } else {
+        qDebug() << "Invalid verb:" << verb;
+    }
+}
+
+
+void ActivityWidget::slotNotifyNetworkError( QNetworkReply* )
+{
+    qDebug() << "Server notify job failed.";
+}
+
+void ActivityWidget::slotNotifyServerFinished( const QString& reply, int replyCode )
+{
+    // FIXME: remove the  widget after a couple of seconds
+    qDebug() << "Server Notification reply code"<< replyCode << reply;
+
+}
+
 /* ==================================================================== */
 
 ActivitySettings::ActivitySettings(QWidget *parent)
diff --git a/src/gui/activitywidget.h b/src/gui/activitywidget.h
index c3ba5ca..c27724c 100644
--- a/src/gui/activitywidget.h
+++ b/src/gui/activitywidget.h
@@ -33,6 +33,8 @@ namespace OCC {
 class Account;
 class AccountStatusPtr;
 class ProtocolWidget;
+class JsonApiJob;
+class NotificationWidget;
 
 namespace Ui {
   class ActivityWidget;
@@ -40,6 +42,23 @@ namespace Ui {
 class Application;
 
 /**
+ * @brief The ActivityLink class describes actions of an activity
+ *
+ * These are part of notifications which are mapped into activities.
+ */
+
+class ActivityLink
+{
+public:
+    QHash <QString, QVariant> toVariantHash();
+
+    QString _label;
+    QString _link;
+    QString _verb;
+    bool _isPrimary;
+};
+
+/**
  * @brief Activity Structure
  * @ingroup gui
  *
@@ -49,6 +68,11 @@ class Application;
 class Activity
 {
 public:
+    enum Type {
+        ActivityType,
+        NotificationType
+    };
+    Type      _type;
     qlonglong _id;
     QString   _subject;
     QString   _message;
@@ -57,6 +81,7 @@ public:
     QDateTime _dateTime;
     QString   _accName;
 
+    QVector <ActivityLink> _links;
     /**
      * @brief Sort operator to sort the list youngest first.
      * @param val
@@ -146,12 +171,21 @@ public slots:
     void slotRefresh(AccountState* ptr);
     void slotRemoveAccount( AccountState *ptr );
     void slotAccountActivityStatus(AccountState *ast, int statusCode);
+    void slotFetchNotifications(AccountState *ptr);
 
 signals:
     void guiLog(const QString&, const QString&);
     void copyToClipboard();
     void rowsInserted();
     void hideAcitivityTab(bool);
+    void newNotificationList(const ActivityList& list);
+
+private slots:
+    void slotNotificationsReceived(const QVariantMap& json, int statusCode);
+    void slotBuildNotificationDisplay(const ActivityList& list);
+    void slotSendNotificationRequest(const QString &accountName, const QString& link, const QString& verb);
+    void slotNotifyNetworkError( QNetworkReply* );
+    void slotNotifyServerFinished( const QString& reply, int replyCode );
 
 private:
     void showLabels();
@@ -160,8 +194,10 @@ private:
     QPushButton *_copyBtn;
 
     QSet<QString> _accountsWithoutActivities;
-
+    QMap<int, NotificationWidget*> _widgetForNotifId;
+    QPointer<JsonApiJob> _notificationJob;
     ActivityListModel *_model;
+    QVBoxLayout *_notificationsLayout;
 };
 
 
diff --git a/src/gui/activitywidget.ui b/src/gui/activitywidget.ui
index eb48941..fefd7b3 100644
--- a/src/gui/activitywidget.ui
+++ b/src/gui/activitywidget.ui
@@ -15,23 +15,60 @@
   </property>
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
-    <widget class="QLabel" name="_headerLabel">
+    <widget class="QLabel" name="_notifyLabel">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item row="1" column="0">
-    <widget class="QListView" name="_activityList"/>
+    <widget class="QScrollArea" name="_notifyScroll">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="widgetResizable">
+      <bool>true</bool>
+     </property>
+     <widget class="QWidget" name="_scrollAreaWidgetContents">
+      <property name="geometry">
+       <rect>
+        <x>0</x>
+        <y>0</y>
+        <width>677</width>
+        <height>70</height>
+       </rect>
+      </property>
+     </widget>
+    </widget>
    </item>
    <item row="2" column="0">
-    <widget class="QLabel" name="_bottomLabel">
+    <widget class="QLabel" name="_headerLabel">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item row="3" column="0">
+    <widget class="QListView" name="_activityList">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="QLabel" name="_bottomLabel">
+     <property name="text">
+      <string>TextLabel</string>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="0">
     <widget class="QDialogButtonBox" name="_dialogButtonBox"/>
    </item>
   </layout>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud-client.git



More information about the Pkg-owncloud-commits mailing list