Gigantic ton of changes and deletions: ActivityListModel, tray GUI, Account logic.
authorDominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
Fri, 3 Jan 2020 12:09:29 +0000 (13:09 +0100)
committerDominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
Fri, 3 Jan 2020 12:09:29 +0000 (13:09 +0100)
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
32 files changed:
src/gui/CMakeLists.txt
src/gui/accountsettings.ui
src/gui/accountstate.cpp
src/gui/accountstate.h
src/gui/activitydata.cpp [deleted file]
src/gui/activitydata.h [deleted file]
src/gui/activityitemdelegate.cpp [deleted file]
src/gui/activityitemdelegate.h [deleted file]
src/gui/activitylistmodel.cpp [deleted file]
src/gui/activitylistmodel.h [deleted file]
src/gui/activitywidget.cpp [deleted file]
src/gui/activitywidget.h [deleted file]
src/gui/activitywidget.ui [deleted file]
src/gui/generalsettings.ui
src/gui/networksettings.ui
src/gui/owncloudgui.cpp
src/gui/servernotificationhandler.cpp [deleted file]
src/gui/servernotificationhandler.h [deleted file]
src/gui/settingsdialog.cpp
src/gui/settingsdialog.h
src/gui/settingsdialog.ui
src/gui/systray.cpp
src/gui/systray.h
src/gui/tray/ActivityData.cpp [new file with mode: 0644]
src/gui/tray/ActivityData.h [new file with mode: 0644]
src/gui/tray/ActivityListModel.cpp [new file with mode: 0644]
src/gui/tray/ActivityListModel.h [new file with mode: 0644]
src/gui/tray/UserLine.qml
src/gui/tray/UserModel.cpp
src/gui/tray/UserModel.h
src/gui/tray/window.qml
src/libsync/capabilities.cpp

index 9b0455a6b5bdc2d5d8488a293415c22d2685c43f..af364ca4ed3d29a51711de6421026db6895be90d 100644 (file)
@@ -24,7 +24,6 @@ set(client_UI_SRCS
     ignorelisteditor.ui
     ignorelisttablewidget.ui
     networksettings.ui
-    activitywidget.ui
     synclogdialog.ui
     settingsdialog.ui
     sharedialog.ui
@@ -35,7 +34,7 @@ set(client_UI_SRCS
     addcertificatedialog.ui
     proxyauthdialog.ui
     mnemonicdialog.ui
-    tray/window.qml
+    tray/Window.qml
     tray/UserLine.qml
     wizard/flow2authwidget.ui
     wizard/owncloudadvancedsetuppage.ui
@@ -75,10 +74,6 @@ set(client_SRCS
     openfilemanager.cpp
     owncloudgui.cpp
     owncloudsetupwizard.cpp
-    activitydata.cpp
-    activitylistmodel.cpp
-    activitywidget.cpp
-    activityitemdelegate.cpp
     selectivesyncdialog.cpp
     settingsdialog.cpp
     sharedialog.cpp
@@ -101,12 +96,13 @@ set(client_SRCS
     synclogdialog.cpp
     tooltipupdater.cpp
     notificationconfirmjob.cpp
-    servernotificationhandler.cpp
     guiutility.cpp
     elidedlabel.cpp
     headerbanner.cpp
     iconjob.cpp
     remotewipe.cpp
+    tray/ActivityData.cpp
+    tray/ActivityListModel.cpp
     tray/UserModel.cpp
     creds/credentialsfactory.cpp
     creds/httpcredentialsgui.cpp
index f52adf4c73b29b8955725b78c53763b69bddace5..6249018bd19bfe2b06e6b2f47a1fa4d18522b3f4 100644 (file)
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>582</width>
+    <width>516</width>
     <height>557</height>
    </rect>
   </property>
index 7893a7a3b332bef767e692c48931a9bf563edb7f..9d2fa1830f57a69c83ec41b35b44d9960f265199 100644 (file)
@@ -74,6 +74,11 @@ AccountPtr AccountState::account() const
     return _account;
 }
 
+bool AccountState::hasTalk() const
+{
+    return _hasTalk;
+}
+
 AccountState::ConnectionStatus AccountState::connectionStatus() const
 {
     return _connectionStatus;
@@ -89,6 +94,23 @@ AccountState::State AccountState::state() const
     return _state;
 }
 
+void AccountState::setTalkCapability()
+{
+    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
+    connect(manager, &QNetworkAccessManager::finished,
+        this, [=](QNetworkReply *reply) {
+            if (reply->error()) {
+                return;
+            }
+            //TODO: This is **** dirty, but atm I don't see a capability-way to determine talk integration
+            _hasTalk = (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 303) ? true : false;
+        });
+    QNetworkRequest request;
+    QString url = this->account()->url().toString() + "/apps/spreed";
+    request.setUrl(QUrl(url));
+    manager->get(request);
+}
+
 void AccountState::setState(State state)
 {
     if (_state != state) {
@@ -267,7 +289,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
     // Come online gradually from 503 or maintenance mode
     if (status == ConnectionValidator::Connected
         && (_connectionStatus == ConnectionValidator::ServiceUnavailable
-               || _connectionStatus == ConnectionValidator::MaintenanceMode)) {
+            || _connectionStatus == ConnectionValidator::MaintenanceMode)) {
         if (!_timeSinceMaintenanceOver.isValid()) {
             qCInfo(lcAccountState) << "AccountState reconnection: delaying for"
                                    << _maintenanceToConnectedDelay << "ms";
@@ -293,6 +315,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
     case ConnectionValidator::Connected:
         if (_state != Connected) {
             setState(Connected);
+            setTalkCapability();
         }
         break;
     case ConnectionValidator::Undefined:
index 6ed9aa2656924d5d8384b128b707bc91cf34f585..7633bd78dfa2c0d5e734f56302c73e00850ba012 100644 (file)
@@ -101,6 +101,8 @@ public:
 
     bool isSignedOut() const;
 
+    bool hasTalk() const;
+
     /** A user-triggered sign out which disconnects, stops syncs
      * for the account and forgets the password. */
     void signOutByUi();
@@ -161,6 +163,7 @@ public slots:
 
 private:
     void setState(State state);
+    void setTalkCapability();
 
 signals:
     void stateChanged(int state);
@@ -182,6 +185,7 @@ private:
     ConnectionStatus _connectionStatus;
     QStringList _connectionErrors;
     bool _waitingForNewCredentials;
+    bool _hasTalk;
     QElapsedTimer _timeSinceLastETagCheck;
     QPointer<ConnectionValidator> _connectionValidator;
     QByteArray _notificationsEtagResponseHeader;
diff --git a/src/gui/activitydata.cpp b/src/gui/activitydata.cpp
deleted file mode 100644 (file)
index 866c979..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <QtCore>
-
-#include "activitydata.h"
-
-
-namespace OCC {
-
-bool operator<(const Activity &rhs, const Activity &lhs)
-{
-    return rhs._dateTime > lhs._dateTime;
-}
-
-bool operator==(const Activity &rhs, const Activity &lhs)
-{
-    return (rhs._type == lhs._type && rhs._id == lhs._id && rhs._accName == lhs._accName);
-}
-
-Activity::Identifier Activity::ident() const
-{
-    return Identifier(_id, _accName);
-}
-}
diff --git a/src/gui/activitydata.h b/src/gui/activitydata.h
deleted file mode 100644 (file)
index d2f3c86..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef ACTIVITYDATA_H
-#define ACTIVITYDATA_H
-
-#include <QtCore>
-#include <QIcon>
-
-namespace OCC {
-/**
- * @brief The ActivityLink class describes actions of an activity
- *
- * These are part of notifications which are mapped into activities.
- */
-
-class ActivityLink
-{
-public:
-    QString _label;
-    QString _link;
-    QByteArray _verb;
-    bool _isPrimary;
-};
-
-/* ==================================================================== */
-/**
- * @brief Activity Structure
- * @ingroup gui
- *
- * contains all the information describing a single activity.
- */
-
-class Activity
-{
-public:
-    typedef QPair<qlonglong, QString> Identifier;
-
-    enum Type {
-        ActivityType,
-        NotificationType,
-        SyncResultType,
-        SyncFileItemType
-    };
-
-    Type _type;
-    qlonglong _id;
-    QString _objectType;
-    QString _subject;
-    QString _message;
-    QString _folder;
-    QString _file;
-    QUrl _link;
-    QDateTime _dateTime;
-    QString _accName;
-
-    // Stores information about the error
-    int _status;
-
-    QVector<ActivityLink> _links;
-    /**
-     * @brief Sort operator to sort the list youngest first.
-     * @param val
-     * @return
-     */
-
-
-    Identifier ident() const;
-};
-
-bool operator==(const Activity &rhs, const Activity &lhs);
-bool operator<(const Activity &rhs, const Activity &lhs);
-
-/* ==================================================================== */
-/**
- * @brief The ActivityList
- * @ingroup gui
- *
- * A QList based list of Activities
- */
-
-typedef QList<Activity> ActivityList;
-}
-
-Q_DECLARE_METATYPE(OCC::Activity::Type)
-Q_DECLARE_METATYPE(OCC::ActivityLink)
-
-#endif // ACTIVITYDATA_H
diff --git a/src/gui/activityitemdelegate.cpp b/src/gui/activityitemdelegate.cpp
deleted file mode 100644 (file)
index 2b4231e..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- * Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "activityitemdelegate.h"
-#include "activitylistmodel.h"
-#include "folderstatusmodel.h"
-#include "folderman.h"
-#include "accountstate.h"
-#include "activitydata.h"
-#include <theme.h>
-#include <account.h>
-
-#include <QFileIconProvider>
-#include <QPainter>
-#include <QApplication>
-
-#define FIXME_USE_HIGH_DPI_RATIO
-#ifdef FIXME_USE_HIGH_DPI_RATIO
-    // FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
-    #include <QDesktopWidget>
-#endif
-
-#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
-
-namespace OCC {
-
-int ActivityItemDelegate::_iconHeight = 0;
-int ActivityItemDelegate::_margin = 0;
-int ActivityItemDelegate::_primaryButtonWidth = 0;
-int ActivityItemDelegate::_secondaryButtonWidth = 0;
-int ActivityItemDelegate::_spaceBetweenButtons = 0;
-int ActivityItemDelegate::_timeWidth = 0;
-int ActivityItemDelegate::_buttonHeight = 0;
-const QString ActivityItemDelegate::_remote_share("remote_share");
-const QString ActivityItemDelegate::_call("call");
-
-ActivityItemDelegate::ActivityItemDelegate()
-    : QStyledItemDelegate()
-{
-    customizeStyle();
-}
-
-int ActivityItemDelegate::iconHeight()
-{
-    if (_iconHeight == 0) {
-        QStyleOptionViewItem option;
-        QFont font = option.font;
-
-        QFontMetrics fm(font);
-
-        _iconHeight = qRound(fm.height() / 5.0 * 8.0);
-    }
-    return _iconHeight;
-}
-
-int ActivityItemDelegate::rowHeight()
-{
-    if (_margin == 0) {
-        QStyleOptionViewItem opt;
-
-        QFont f = opt.font;
-        QFontMetrics fm(f);
-
-        _margin = fm.height() / 2;
-
-#if defined(Q_OS_WIN)
-        _margin += 5;
-#endif
-    }
-    return iconHeight() + 5 * _margin;
-}
-
-QSize ActivityItemDelegate::sizeHint(const QStyleOptionViewItem &option,
-    const QModelIndex & /* index */) const
-{
-    QFont font = option.font;
-
-    return QSize(0, rowHeight());
-}
-
-void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
-    const QModelIndex &index) const
-{
-    QStyledItemDelegate::paint(painter, option, index);
-    QFont font = option.font;
-    QFontMetrics fm(font);
-    int margin = fm.height() / 2.5;
-    painter->save();
-    int iconSize = 16;
-    int iconOffset = qRound(fm.height() / 4.0 * 7.0);
-    int offset = 4;
-    const bool isSelected = (option.state & QStyle::State_Selected);
-#ifdef FIXME_USE_HIGH_DPI_RATIO
-    // FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
-    const int device_pixel_ration = QApplication::desktop()->devicePixelRatio();
-    int pixel_ratio = (device_pixel_ration > 1 ? device_pixel_ration : 1);
-#endif
-
-    // get the data
-    Activity::Type activityType = qvariant_cast<Activity::Type>(index.data(ActionRole));
-    QIcon actionIcon;
-    const ActivityListModel::ActionIcon icn = qvariant_cast<ActivityListModel::ActionIcon>(index.data(ActionIconRole));
-    switch(icn.iconType) {
-        case ActivityListModel::ActivityIconType::iconUseCached:        actionIcon = icn.cachedIcon;                                        break;
-        case ActivityListModel::ActivityIconType::iconActivity:         actionIcon = (isSelected ? _iconActivity_sel : _iconActivity);      break;
-        case ActivityListModel::ActivityIconType::iconBell:             actionIcon = (isSelected ? _iconBell_sel : _iconBell);              break;
-        case ActivityListModel::ActivityIconType::iconStateError:       actionIcon = _iconStateError;                                       break;
-        case ActivityListModel::ActivityIconType::iconStateWarning:     actionIcon = _iconStateWarning;                                     break;
-        case ActivityListModel::ActivityIconType::iconStateInfo:        actionIcon = _iconStateInfo;                                        break;
-        case ActivityListModel::ActivityIconType::iconStateSync:        actionIcon = _iconStateSync;                                        break;
-    }
-    QString objectType = qvariant_cast<QString>(index.data(ObjectTypeRole));
-    QString actionText = qvariant_cast<QString>(index.data(ActionTextRole));
-    QString messageText = qvariant_cast<QString>(index.data(MessageRole));
-    QList<QVariant> customList = index.data(ActionsLinksRole).toList();
-    QString timeText = qvariant_cast<QString>(index.data(PointInTimeRole));
-    bool accountOnline = qvariant_cast<bool>(index.data(AccountConnectedRole));
-
-    // activity/notification icons
-    QRect actionIconRect = option.rect;
-    actionIconRect.setLeft(option.rect.left() + iconOffset/3);
-    actionIconRect.setRight(option.rect.left() + iconOffset);
-    actionIconRect.setTop(option.rect.top() + qRound((option.rect.height() - 16)/3.0));
-
-    // subject text rect
-    QRect actionTextBox = actionIconRect;
-#if (HASQT5_11)
-    int actionTextBoxWidth = fm.horizontalAdvance(actionText);
-#else
-    int actionTextBoxWidth = fm.width(actionText);
-#endif
-    actionTextBox.setTop(option.rect.top() + margin + offset/2);
-    actionTextBox.setHeight(fm.height());
-    actionTextBox.setLeft(actionIconRect.right() + margin);
-#ifdef FIXME_USE_HIGH_DPI_RATIO
-    // FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
-    actionTextBoxWidth *= pixel_ratio;
-#endif
-    actionTextBox.setRight(actionTextBox.left() + actionTextBoxWidth + margin);
-
-    // message text rect
-    QRect messageTextBox = actionTextBox;
-#if (HASQT5_11)
-    int messageTextWidth = fm.horizontalAdvance(messageText);
-#else
-    int messageTextWidth = fm.width(messageText);
-#endif
-    int messageTextTop = option.rect.top() + fm.height() + margin;
-    if(actionText.isEmpty()) messageTextTop = option.rect.top() + margin + offset/2;
-    messageTextBox.setTop(messageTextTop);
-    messageTextBox.setHeight(fm.height());
-    messageTextBox.setBottom(messageTextBox.top() + fm.height());
-    messageTextBox.setRight(messageTextBox.left() + messageTextWidth + margin);
-    if(messageText.isEmpty()){
-        messageTextBox.setHeight(0);
-        messageTextBox.setBottom(messageTextBox.top());
-    }
-
-    // time box rect
-    QRect timeBox = messageTextBox;
-#if (HASQT5_11)
-    int timeTextWidth = fm.horizontalAdvance(timeText);
-#else
-    int timeTextWidth = fm.width(timeText);
-#endif
-    int timeTop = option.rect.top() + fm.height() + fm.height() + margin + offset/2;
-    if(messageText.isEmpty() || actionText.isEmpty())
-        timeTop = option.rect.top() + fm.height() + margin;
-    timeBox.setTop(timeTop);
-    timeBox.setHeight(fm.height());
-    timeBox.setBottom(timeBox.top() + fm.height());
-#ifdef FIXME_USE_HIGH_DPI_RATIO
-    // FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
-    timeTextWidth *= pixel_ratio;
-#endif
-    timeBox.setRight(timeBox.left() + timeTextWidth + margin);
-
-    // buttons - default values
-    int rightMargin = margin;
-    int leftMargin = margin * offset;
-    int top = option.rect.top() + margin;
-    int buttonSize = option.rect.height()/2;
-    int right = option.rect.right() - rightMargin;
-    int left = right - buttonSize;
-
-    QStyleOptionButton secondaryButton;
-    secondaryButton.rect = option.rect;
-    secondaryButton.features |= QStyleOptionButton::Flat;
-    secondaryButton.state |= QStyle::State_None;
-    secondaryButton.rect.setLeft(left);
-    secondaryButton.rect.setRight(right);
-    secondaryButton.rect.setTop(top + margin);
-    secondaryButton.rect.setHeight(iconSize);
-
-    QStyleOptionButton primaryButton;
-    primaryButton.rect = option.rect;
-    primaryButton.features |= QStyleOptionButton::DefaultButton;
-    primaryButton.state |= QStyle::State_Raised;
-    primaryButton.rect.setTop(top);
-    primaryButton.rect.setHeight(buttonSize);
-
-    right = secondaryButton.rect.left() - rightMargin;
-    left = secondaryButton.rect.left() - leftMargin;
-
-    primaryButton.rect.setRight(right);
-
-    if(activityType == Activity::Type::NotificationType){
-
-        // Secondary will be 'Dismiss' or '...' multiple options button
-        secondaryButton.icon = (isSelected ? _iconClose_sel : _iconClose);
-        if(customList.size() > 1)
-            secondaryButton.icon = (isSelected ? _iconMore_sel : _iconMore);
-        secondaryButton.iconSize = QSize(iconSize, iconSize);
-
-        // Primary button will be 'More Information' or 'Accept'
-        primaryButton.text = tr("More information");
-        if(objectType == _remote_share) primaryButton.text = tr("Accept");
-        if(objectType == _call) primaryButton.text = tr("Join");
-
-#if (HASQT5_11)
-        primaryButton.rect.setLeft(left - margin * 2 - fm.horizontalAdvance(primaryButton.text));
-#else
-        primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
-#endif
-
-        // save info to be able to filter mouse clicks
-        _buttonHeight = buttonSize;
-        _primaryButtonWidth = primaryButton.rect.size().width();
-        _secondaryButtonWidth = secondaryButton.rect.size().width();
-        _spaceBetweenButtons = secondaryButton.rect.left() - primaryButton.rect.right();
-
-    } else if(activityType == Activity::SyncResultType){
-
-        // Secondary will be 'open file manager' with the folder icon
-        secondaryButton.icon = _iconFolder;
-        secondaryButton.iconSize = QSize(iconSize, iconSize);
-
-        // Primary button will be 'open browser'
-        primaryButton.text = tr("Open Browser");
-
-#if (HASQT5_11)
-        primaryButton.rect.setLeft(left - margin * 2 - fm.horizontalAdvance(primaryButton.text));
-#else
-        primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
-#endif
-
-        // save info to be able to filter mouse clicks
-        _buttonHeight = buttonSize;
-        _primaryButtonWidth = primaryButton.rect.size().width();
-        _secondaryButtonWidth = secondaryButton.rect.size().width();
-        _spaceBetweenButtons = secondaryButton.rect.left() - primaryButton.rect.right();
-
-    } else if(activityType == Activity::SyncFileItemType){
-
-        // Secondary will be 'open file manager' with the folder icon
-        secondaryButton.icon = _iconFolder;
-        secondaryButton.iconSize = QSize(iconSize, iconSize);
-
-        // No primary button on this case
-        // Whatever error we have at this case it is local, there is no point on opening the browser
-        _primaryButtonWidth = 0;
-        _secondaryButtonWidth = secondaryButton.rect.size().width();
-        _spaceBetweenButtons = secondaryButton.rect.left() - primaryButton.rect.right();
-
-    } else {
-        _spaceBetweenButtons = leftMargin;
-        _primaryButtonWidth = 0;
-        _secondaryButtonWidth = 0;
-    }
-
-    // draw the icon
-    QPixmap pm = actionIcon.pixmap(iconSize, iconSize, QIcon::Normal);
-    painter->drawPixmap(QPoint(actionIconRect.left(), actionIconRect.top()), pm);
-
-    // change pen color if use is not online
-    QPalette p = option.palette;
-    if(!accountOnline)
-        p.setCurrentColorGroup(QPalette::Disabled);
-
-    // change pen color if the line is selected
-    if (isSelected)
-        painter->setPen(p.color(QPalette::HighlightedText));
-    else
-        painter->setPen(p.color(QPalette::Text));
-
-    // calculate space for text - use the max possible before using the elipses
-    int spaceLeftForText = option.rect.width() - (actionIconRect.width() + margin + rightMargin + leftMargin) -
-                             (_primaryButtonWidth + _secondaryButtonWidth + _spaceBetweenButtons);
-
-    // draw the subject
-    const QString elidedAction = fm.elidedText(actionText, Qt::ElideRight, spaceLeftForText);
-    painter->drawText(actionTextBox, elidedAction);
-
-    // draw the buttons
-    if(activityType == Activity::Type::NotificationType || activityType == Activity::Type::SyncResultType) {
-        primaryButton.palette = p;
-        if (isSelected)
-            primaryButton.palette.setColor(QPalette::ButtonText, p.color(QPalette::HighlightedText));
-        else
-            primaryButton.palette.setColor(QPalette::ButtonText, p.color(QPalette::Text));
-
-        QApplication::style()->drawControl(QStyle::CE_PushButton, &primaryButton, painter);
-    }
-
-    // Since they are errors on local syncing, there is nothing to do in the server
-    if(activityType != Activity::Type::ActivityType)
-        QApplication::style()->drawControl(QStyle::CE_PushButton, &secondaryButton, painter);
-
-    // draw the message
-    // change pen color for the message
-    if(!messageText.isEmpty()){
-        const QString elidedMessage = fm.elidedText(messageText, Qt::ElideRight, spaceLeftForText);
-        painter->drawText(messageTextBox, elidedMessage);
-    }
-
-    // change pen color for the time
-    if (isSelected)
-        painter->setPen(p.color(QPalette::Disabled, QPalette::HighlightedText));
-    else
-        painter->setPen(p.color(QPalette::Disabled, QPalette::Text));
-
-    // draw the time
-    const QString elidedTime = fm.elidedText(timeText, Qt::ElideRight, spaceLeftForText);
-    painter->drawText(timeBox, elidedTime);
-
-    painter->restore();
-}
-
-bool ActivityItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
-    const QStyleOptionViewItem &option, const QModelIndex &index)
-{
-    Activity::Type activityType = qvariant_cast<Activity::Type>(index.data(ActionRole));
-    if(activityType != Activity::Type::ActivityType){
-        if (event->type() == QEvent::MouseButtonRelease){
-            QMouseEvent *mouseEvent = (QMouseEvent*)event;
-            if(mouseEvent){
-                int mouseEventX = mouseEvent->x();
-                int mouseEventY = mouseEvent->y();
-                int buttonsWidth = _primaryButtonWidth + _spaceBetweenButtons + _secondaryButtonWidth;
-                int x = option.rect.left() + option.rect.width() - buttonsWidth - _timeWidth;
-                int y = option.rect.top();
-
-                // clickable area for ...
-                if (mouseEventX > x && mouseEventX < x + buttonsWidth){
-                    if(mouseEventY > y && mouseEventY < y + _buttonHeight){
-
-                        // ...primary button ('more information' or 'accept' on notifications or 'open browser' on errors)
-                        if (mouseEventX > x && mouseEventX < x + _primaryButtonWidth){
-                            emit primaryButtonClickedOnItemView(index);
-
-                        // ...secondary button ('dismiss' on notifications or 'open file manager' on errors)
-                        } else  {
-                            x += _primaryButtonWidth + _spaceBetweenButtons;
-                            if (mouseEventX > x && mouseEventX < x + _secondaryButtonWidth)
-                                emit secondaryButtonClickedOnItemView(index);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    return QStyledItemDelegate::editorEvent(event, model, option, index);
-}
-
-void ActivityItemDelegate::slotStyleChanged()
-{
-    customizeStyle();
-}
-
-void ActivityItemDelegate::customizeStyle()
-{
-    QPalette pal;
-    pal.setColor(QPalette::Base, QColor(0,0,0));    // use dark background colour to invert icons
-
-    _iconClose        = Theme::createColorAwareIcon(QLatin1String(":/client/resources/close.svg"));
-    _iconClose_sel    = Theme::createColorAwareIcon(QLatin1String(":/client/resources/close.svg"), pal);
-    _iconMore         = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"));
-    _iconMore_sel     = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"), pal);
-
-    _iconFolder       = QIcon(QLatin1String(":/client/resources/folder.svg"));
-
-    _iconActivity     = Theme::createColorAwareIcon(QLatin1String(":/client/resources/activity.png"));
-    _iconActivity_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/activity.png"), pal);
-    _iconBell         = Theme::createColorAwareIcon(QLatin1String(":/client/resources/bell.svg"));
-    _iconBell_sel     = Theme::createColorAwareIcon(QLatin1String(":/client/resources/bell.svg"), pal);
-
-    _iconStateError   = QIcon(QLatin1String(":/client/resources/state-error.svg"));
-    _iconStateWarning = QIcon(QLatin1String(":/client/resources/state-warning.svg"));
-    _iconStateInfo    = QIcon(QLatin1String(":/client/resources/state-info.svg"));
-    _iconStateSync    = QIcon(QLatin1String(":/client/resources/state-sync.svg"));
-}
-
-} // namespace OCC
diff --git a/src/gui/activityitemdelegate.h b/src/gui/activityitemdelegate.h
deleted file mode 100644 (file)
index 908889e..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@kde.org>
- * Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#pragma once
-#include <QStyledItemDelegate>
-#include <QMouseEvent>
-
-class QMouseEvent;
-
-namespace OCC {
-
-/**
- * @brief The ActivityItemDelegate class
- * @ingroup gui
- */
-class ActivityItemDelegate : public QStyledItemDelegate
-{
-    Q_OBJECT
-public:
-    enum datarole { ActionIconRole = Qt::UserRole + 1,
-        UserIconRole,
-        AccountRole,
-        ObjectTypeRole,
-        ActionsLinksRole,
-        ActionTextRole,
-        ActionRole,
-        MessageRole,
-        PathRole,
-        LinkRole,
-        PointInTimeRole,
-        AccountConnectedRole,
-        SyncFileStatusRole };
-
-    ActivityItemDelegate();
-
-    void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override;
-    QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override;
-    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
-        const QModelIndex &index) override;
-
-    static int rowHeight();
-    static int iconHeight();
-
-public slots:
-    void slotStyleChanged();
-
-signals:
-    void primaryButtonClickedOnItemView(const QModelIndex &index);
-    void secondaryButtonClickedOnItemView(const QModelIndex &index);
-
-private:
-    void customizeStyle();
-
-    static int _margin;
-    static int _iconHeight;
-    static int _primaryButtonWidth;
-    static int _secondaryButtonWidth;
-    static int _spaceBetweenButtons;
-    static int _timeWidth;
-    static int _buttonHeight;
-    static const QString _remote_share;
-    static const QString _call;
-
-    QIcon _iconClose;
-    QIcon _iconClose_sel;
-    QIcon _iconMore;
-    QIcon _iconMore_sel;
-
-    QIcon _iconFolder;
-
-    QIcon _iconActivity;
-    QIcon _iconActivity_sel;
-    QIcon _iconBell;
-    QIcon _iconBell_sel;
-
-    QIcon _iconStateError;
-    QIcon _iconStateWarning;
-    QIcon _iconStateInfo;
-    QIcon _iconStateSync;
-};
-
-} // namespace OCC
diff --git a/src/gui/activitylistmodel.cpp b/src/gui/activitylistmodel.cpp
deleted file mode 100644 (file)
index eeb0cc8..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <QtCore>
-#include <QAbstractListModel>
-#include <QWidget>
-#include <QIcon>
-#include <QJsonObject>
-#include <QJsonDocument>
-
-#include "account.h"
-#include "accountstate.h"
-#include "accountmanager.h"
-#include "folderman.h"
-#include "accessmanager.h"
-#include "activityitemdelegate.h"
-
-#include "activitydata.h"
-#include "activitylistmodel.h"
-
-#include "theme.h"
-
-#include "servernotificationhandler.h"
-
-namespace OCC {
-
-Q_LOGGING_CATEGORY(lcActivity, "nextcloud.gui.activity", QtInfoMsg)
-
-ActivityListModel::ActivityListModel(AccountState *accountState, QWidget *parent)
-    : QAbstractListModel(parent)
-    , _accountState(accountState)
-{
-}
-
-QVariant ActivityListModel::data(const QModelIndex &index, int role) const
-{
-    Activity a;
-
-    // filter the get action here
-    // send only the text of the get action
-    // if there is more than one send the icon? the ...
-
-    if (!index.isValid())
-        return QVariant();
-
-    a = _finalList.at(index.row());
-    AccountStatePtr ast = AccountManager::instance()->account(a._accName);
-    if (!ast && _accountState != ast.data())
-        return QVariant();
-    QStringList list;
-
-    switch (role) {
-    case ActivityItemDelegate::PathRole:
-        if(!a._file.isEmpty()){
-            auto folder = FolderMan::instance()->folder(a._folder);
-            QString relPath(a._file);
-            if(folder) relPath.prepend(folder->remotePath());
-            list = FolderMan::instance()->findFileInLocalFolders(relPath, ast->account());
-            if (list.count() > 0) {
-                return QVariant(list.at(0));
-            }
-            // File does not exist anymore? Let's try to open its path
-            if(QFileInfo(relPath).exists()) {
-                list = FolderMan::instance()->findFileInLocalFolders(QFileInfo(relPath).path(), ast->account());
-                if (list.count() > 0) {
-                    return QVariant(list.at(0));
-                }
-            }
-        }
-        return QVariant();
-     case ActivityItemDelegate::ActionsLinksRole:{
-        QList<QVariant> customList;
-        foreach (ActivityLink customItem, a._links) {
-            QVariant customVariant;
-            customVariant.setValue(customItem);
-            customList << customVariant;
-        }
-        return customList;
-    }
-    case ActivityItemDelegate::ActionIconRole:{
-        ActionIcon actionIcon;
-        if(a._type == Activity::NotificationType){
-           QIcon cachedIcon = ServerNotificationHandler::iconCache.value(a._id);
-            if(!cachedIcon.isNull()) {
-               actionIcon.iconType = ActivityIconType::iconUseCached;
-               actionIcon.cachedIcon = cachedIcon;
-            } else {
-                actionIcon.iconType = ActivityIconType::iconBell;
-            }
-        } else if(a._type == Activity::SyncResultType){
-            actionIcon.iconType = ActivityIconType::iconStateError;
-        } else if(a._type == Activity::SyncFileItemType){
-               if(a._status == SyncFileItem::NormalError
-                   || a._status == SyncFileItem::FatalError
-                   || a._status == SyncFileItem::DetailError
-                   || a._status == SyncFileItem::BlacklistedError) {
-                   actionIcon.iconType = ActivityIconType::iconStateError;
-               } else if(a._status == SyncFileItem::SoftError
-                         || a._status == SyncFileItem::Conflict
-                         || a._status == SyncFileItem::Restoration
-                         || a._status == SyncFileItem::FileLocked){
-                   actionIcon.iconType = ActivityIconType::iconStateWarning;
-               } else if(a._status == SyncFileItem::FileIgnored){
-                   actionIcon.iconType = ActivityIconType::iconStateInfo;
-               } else {
-                   actionIcon.iconType = ActivityIconType::iconStateSync;
-               }
-        } else {
-            actionIcon.iconType = ActivityIconType::iconActivity;
-        }
-        QVariant icn;
-        icn.setValue(actionIcon);
-        return icn;
-    }
-    case ActivityItemDelegate::ObjectTypeRole:
-        return a._objectType;
-    case ActivityItemDelegate::ActionRole:{
-        QVariant type;
-        type.setValue(a._type);
-        return type;
-    }
-    case ActivityItemDelegate::ActionTextRole:
-        return a._subject;
-    case ActivityItemDelegate::MessageRole:
-        return a._message;
-    case ActivityItemDelegate::LinkRole:
-        return a._link;
-    case ActivityItemDelegate::AccountRole:
-        return a._accName;
-    case ActivityItemDelegate::PointInTimeRole:
-        return QString("%1 (%2)").arg(a._dateTime.toLocalTime().toString(Qt::DefaultLocaleShortDate), Utility::timeAgoInWords(a._dateTime.toLocalTime()));
-    case ActivityItemDelegate::AccountConnectedRole:
-        return (ast && ast->isConnected());
-    default:
-        return QVariant();
-    }
-    return QVariant();
-}
-
-int ActivityListModel::rowCount(const QModelIndex &) const
-{
-    return _finalList.count();
-}
-
-bool ActivityListModel::canFetchMore(const QModelIndex &) const
-{
-    // We need to be connected to be able to fetch more
-    if (_accountState && _accountState->isConnected()) {
-        // If the fetching is reported to be done or we are currently fetching we can't fetch more
-        if (!_doneFetching && !_currentlyFetching) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-void ActivityListModel::startFetchJob()
-{
-    if (!_accountState->isConnected()) {
-        return;
-    }
-    JsonApiJob *job = new JsonApiJob(_accountState->account(), QLatin1String("ocs/v2.php/cloud/activity"), this);
-    QObject::connect(job, &JsonApiJob::jsonReceived,
-        this, &ActivityListModel::slotActivitiesReceived);
-
-    QUrlQuery params;
-    params.addQueryItem(QLatin1String("start"), QString::number(_currentItem));
-    params.addQueryItem(QLatin1String("count"), QString::number(100));
-    job->addQueryParams(params);
-
-    _currentlyFetching = true;
-    qCInfo(lcActivity) << "Start fetching activities for " << _accountState->account()->displayName();
-    job->start();
-}
-
-void ActivityListModel::slotActivitiesReceived(const QJsonDocument &json, int statusCode)
-{
-    auto activities = json.object().value("ocs").toObject().value("data").toArray();
-
-    ActivityList list;
-    auto ast = _accountState;
-    if (!ast) {
-        return;
-    }
-
-    if (activities.size() == 0) {
-        _doneFetching = true;
-    }
-
-    _currentlyFetching = false;
-    _currentItem += activities.size();
-
-    foreach (auto activ, activities) {
-        auto json = activ.toObject();
-
-        Activity a;
-        a._type = Activity::ActivityType;
-        a._accName = ast->account()->displayName();
-        a._id = json.value("id").toInt();
-        a._subject = json.value("subject").toString();
-        a._message = json.value("message").toString();
-        a._file = json.value("file").toString();
-        a._link = QUrl(json.value("link").toString());
-        a._dateTime = QDateTime::fromString(json.value("date").toString(), Qt::ISODate);
-        list.append(a);
-    }
-
-    _activityLists.append(list);
-
-    emit activityJobStatusCode(statusCode);
-
-    combineActivityLists();
-}
-
-void ActivityListModel::addErrorToActivityList(Activity activity) {
-    qCInfo(lcActivity) << "Error successfully added to the notification list: " << activity._subject;
-    _notificationErrorsLists.prepend(activity);
-    combineActivityLists();
-}
-
-void ActivityListModel::addIgnoredFileToList(Activity newActivity) {
-    qCInfo(lcActivity) << "First checking for duplicates then add file to the notification list of ignored files: " << newActivity._file;
-
-    bool duplicate = false;
-    if(_listOfIgnoredFiles.size() == 0){
-        _notificationIgnoredFiles = newActivity;
-        _notificationIgnoredFiles._subject = tr("Files from the ignore list as well as symbolic links are not synced. This includes:");
-        _listOfIgnoredFiles.append(newActivity);
-        return;
-    }
-
-    foreach(Activity activity, _listOfIgnoredFiles){
-        if(activity._file == newActivity._file){
-            duplicate = true;
-            break;
-        }
-    }
-
-    if(!duplicate){
-        _notificationIgnoredFiles._message.append(", " + newActivity._file);
-    }
-}
-
-void ActivityListModel::addNotificationToActivityList(Activity activity) {
-    qCInfo(lcActivity) << "Notification successfully added to the notification list: " << activity._subject;
-    _notificationLists.prepend(activity);
-    combineActivityLists();
-}
-
-void ActivityListModel::clearNotifications() {
-    qCInfo(lcActivity) << "Clear the notifications";
-    _notificationLists.clear();
-    combineActivityLists();
-}
-
-void ActivityListModel::removeActivityFromActivityList(int row) {
-    Activity activity = _finalList.at(row);
-    removeActivityFromActivityList(activity);
-    combineActivityLists();
-}
-
-void ActivityListModel::addSyncFileItemToActivityList(Activity activity) {
-    qCInfo(lcActivity) << "Successfully added to the activity list: " << activity._subject;
-    _syncFileItemLists.prepend(activity);
-    combineActivityLists();
-}
-
-void ActivityListModel::removeActivityFromActivityList(Activity activity) {
-    qCInfo(lcActivity) << "Activity/Notification/Error successfully dismissed: " << activity._subject;
-    qCInfo(lcActivity) << "Trying to remove Activity/Notification/Error from view... ";
-
-    int index = -1;
-    if(activity._type == Activity::ActivityType){
-        index = _activityLists.indexOf(activity);
-        if(index != -1) _activityLists.removeAt(index);
-    } else if(activity._type == Activity::NotificationType){
-        index = _notificationLists.indexOf(activity);
-        if(index != -1) _notificationLists.removeAt(index);
-    } else {
-        index = _notificationErrorsLists.indexOf(activity);
-        if(index != -1) _notificationErrorsLists.removeAt(index);
-    }
-
-    if(index != -1){
-        qCInfo(lcActivity) << "Activity/Notification/Error successfully removed from the list.";
-        qCInfo(lcActivity) << "Updating Activity/Notification/Error view.";
-        combineActivityLists();
-    }
-}
-
-void ActivityListModel::combineActivityLists()
-{
-    ActivityList resultList;
-
-    if(_notificationErrorsLists.count() > 0) {
-        std::sort(_notificationErrorsLists.begin(), _notificationErrorsLists.end());
-        resultList.append(_notificationErrorsLists);
-    }
-    if(_listOfIgnoredFiles.size() > 0)
-        resultList.append(_notificationIgnoredFiles);
-
-    if(_notificationLists.count() > 0) {
-        std::sort(_notificationLists.begin(), _notificationLists.end());
-        resultList.append(_notificationLists);
-    }
-
-    if(_syncFileItemLists.count() > 0) {
-        std::sort(_syncFileItemLists.begin(), _syncFileItemLists.end());
-        resultList.append(_syncFileItemLists);
-    }
-
-    if(_activityLists.count() > 0) {
-        std::sort(_activityLists.begin(), _activityLists.end());
-        resultList.append(_activityLists);
-    }
-
-    beginResetModel();
-    _finalList.clear();
-    endResetModel();
-
-    beginInsertRows(QModelIndex(), 0, resultList.count());
-    _finalList = resultList;
-    endInsertRows();
-}
-
-bool ActivityListModel::canFetchActivities() const {
-    return _accountState->isConnected() && _accountState->account()->capabilities().hasActivities();
-}
-
-void ActivityListModel::fetchMore(const QModelIndex &)
-{
-    if (canFetchActivities()) {
-        startFetchJob();
-    } else {
-        _doneFetching = true;
-        combineActivityLists();
-    }
-}
-
-void ActivityListModel::slotRefreshActivity()
-{
-    _activityLists.clear();
-    _doneFetching = false;
-    _currentItem = 0;
-
-    if (canFetchActivities()) {
-        startFetchJob();
-    } else {
-        _doneFetching = true;
-        combineActivityLists();
-    }
-}
-
-void ActivityListModel::slotRemoveAccount()
-{
-    _finalList.clear();
-    _activityLists.clear();
-    _currentlyFetching = false;
-    _doneFetching = false;
-    _currentItem = 0;
-}
-}
diff --git a/src/gui/activitylistmodel.h b/src/gui/activitylistmodel.h
deleted file mode 100644 (file)
index 1ff352b..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef ACTIVITYLISTMODEL_H
-#define ACTIVITYLISTMODEL_H
-
-#include <QtCore>
-
-#include "activitydata.h"
-
-class QJsonDocument;
-
-namespace OCC {
-
-Q_DECLARE_LOGGING_CATEGORY(lcActivity)
-
-class AccountState;
-
-/**
- * @brief The ActivityListModel
- * @ingroup gui
- *
- * Simple list model to provide the list view with data.
- */
-
-class ActivityListModel : public QAbstractListModel
-{
-    Q_OBJECT
-public:
-    enum ActivityIconType {
-        iconUseCached = 0,
-        iconActivity,
-        iconBell,
-        iconStateError,
-        iconStateWarning,
-        iconStateInfo,
-        iconStateSync
-    };
-    struct ActionIcon {
-        ActivityIconType iconType;
-        QIcon cachedIcon;
-    };
-
-    explicit ActivityListModel(AccountState *accountState, QWidget *parent = nullptr);
-
-    QVariant data(const QModelIndex &index, int role) const override;
-    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-
-    bool canFetchMore(const QModelIndex &) const override;
-    void fetchMore(const QModelIndex &) override;
-
-    ActivityList activityList() { return _finalList; }
-    ActivityList errorsList() { return _notificationErrorsLists; }
-    void addNotificationToActivityList(Activity activity);
-    void clearNotifications();
-    void addErrorToActivityList(Activity activity);
-    void addIgnoredFileToList(Activity newActivity);
-    void addSyncFileItemToActivityList(Activity activity);
-    void removeActivityFromActivityList(int row);
-    void removeActivityFromActivityList(Activity activity);
-
-public slots:
-    void slotRefreshActivity();
-    void slotRemoveAccount();
-
-private slots:
-    void slotActivitiesReceived(const QJsonDocument &json, int statusCode);
-
-signals:
-    void activityJobStatusCode(int statusCode);
-
-private:
-    void startFetchJob();
-    void combineActivityLists();
-    bool canFetchActivities() const;
-
-    ActivityList _activityLists;
-    ActivityList _syncFileItemLists;
-    ActivityList _notificationLists;
-    ActivityList _listOfIgnoredFiles;
-    Activity _notificationIgnoredFiles;
-    ActivityList _notificationErrorsLists;
-    ActivityList _finalList;
-    AccountState *_accountState;
-    bool _currentlyFetching = false;
-    bool _doneFetching = false;
-    int _currentItem = 0;
-};
-}
-
-Q_DECLARE_METATYPE(OCC::ActivityListModel::ActionIcon)
-
-#endif // ACTIVITYLISTMODEL_H
diff --git a/src/gui/activitywidget.cpp b/src/gui/activitywidget.cpp
deleted file mode 100644 (file)
index 469b0d1..0000000
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <QtGui>
-#include <QtWidgets>
-
-#include "activitylistmodel.h"
-#include "activitywidget.h"
-#include "syncresult.h"
-#include "logger.h"
-#include "theme.h"
-#include "folderman.h"
-#include "syncfileitem.h"
-#include "folder.h"
-#include "openfilemanager.h"
-#include "owncloudpropagator.h"
-#include "account.h"
-#include "accountstate.h"
-#include "accountmanager.h"
-#include "activityitemdelegate.h"
-#include "QProgressIndicator.h"
-#include "notificationconfirmjob.h"
-#include "servernotificationhandler.h"
-#include "theme.h"
-#include "ocsjob.h"
-#include "configfile.h"
-#include "guiutility.h"
-#include "socketapi.h"
-#include "ui_activitywidget.h"
-#include "syncengine.h"
-
-#include <climits>
-
-// time span in milliseconds which has to be between two
-// refreshes of the notifications
-#define NOTIFICATION_REQUEST_FREE_PERIOD 15000
-
-namespace OCC {
-
-ActivityWidget::ActivityWidget(AccountState *accountState, QWidget *parent)
-    : QWidget(parent)
-    , _ui(new Ui::ActivityWidget)
-    , _notificationRequestsRunning(0)
-    , _accountState(accountState)
-    , _accept(tr("Accept"))
-    , _remote_share("remote_share")
-{
-    _ui->setupUi(this);
-
-// Adjust copyToClipboard() when making changes here!
-#if defined(Q_OS_MAC)
-    _ui->_activityList->setMinimumWidth(400);
-#endif
-
-    _model = new ActivityListModel(accountState, this);
-    ActivityItemDelegate *delegate = new ActivityItemDelegate;
-    delegate->setParent(this);
-    _ui->_activityList->setItemDelegate(delegate);
-    _ui->_activityList->setAlternatingRowColors(true);
-    _ui->_activityList->setModel(_model);
-
-    showLabels();
-
-    connect(_model, &ActivityListModel::activityJobStatusCode,
-        this, &ActivityWidget::slotAccountActivityStatus);
-
-    connect(_model, &QAbstractItemModel::rowsInserted, this, &ActivityWidget::rowsInserted);
-
-    connect(delegate, &ActivityItemDelegate::primaryButtonClickedOnItemView, this, &ActivityWidget::slotPrimaryButtonClickedOnListView);
-    connect(delegate, &ActivityItemDelegate::secondaryButtonClickedOnItemView, this, &ActivityWidget::slotSecondaryButtonClickedOnListView);
-    connect(_ui->_activityList, &QListView::activated, this, &ActivityWidget::slotOpenFile);
-
-    connect(ProgressDispatcher::instance(), &ProgressDispatcher::progressInfo,
-        this, &ActivityWidget::slotProgressInfo);
-    connect(ProgressDispatcher::instance(), &ProgressDispatcher::itemCompleted,
-        this, &ActivityWidget::slotItemCompleted);
-    connect(ProgressDispatcher::instance(), &ProgressDispatcher::syncError,
-        this, &ActivityWidget::addError);
-
-    _removeTimer.setInterval(1000);
-
-    // Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
-    connect(this, &ActivityWidget::styleChanged, delegate, &ActivityItemDelegate::slotStyleChanged);
-}
-
-ActivityWidget::~ActivityWidget()
-{
-    delete _ui;
-}
-
-void ActivityWidget::slotProgressInfo(const QString &folder, const ProgressInfo &progress)
-{
-    if (progress.status() == ProgressInfo::Reconcile) {
-        // Wipe all non-persistent entries - as well as the persistent ones
-        // in cases where a local discovery was done.
-        auto f = FolderMan::instance()->folder(folder);
-        if (!f)
-            return;
-        const auto &engine = f->syncEngine();
-        const auto style = engine.lastLocalDiscoveryStyle();
-        foreach (Activity activity, _model->errorsList()) {
-            if (activity._folder != folder){
-                continue;
-            }
-
-            if (style == LocalDiscoveryStyle::FilesystemOnly){
-                _model->removeActivityFromActivityList(activity);
-                continue;
-            }
-
-            if(activity._status == SyncFileItem::Conflict && !QFileInfo(f->path() + activity._file).exists()){
-                _model->removeActivityFromActivityList(activity);
-                continue;
-            }
-
-            if(activity._status == SyncFileItem::FileLocked && !QFileInfo(f->path() + activity._file).exists()){
-                _model->removeActivityFromActivityList(activity);
-                continue;
-            }
-
-
-            if(activity._status == SyncFileItem::FileIgnored && !QFileInfo(f->path() + activity._file).exists()) {
-                _model->removeActivityFromActivityList(activity);
-                continue;
-            }
-
-
-            if(!QFileInfo(f->path() + activity._file).exists()){
-                _model->removeActivityFromActivityList(activity);
-                continue;
-            }
-
-            auto path = QFileInfo(activity._file).dir().path().toUtf8();
-            if (path == ".")
-                path.clear();
-
-            if(engine.shouldDiscoverLocally(path))
-                _model->removeActivityFromActivityList(activity);
-        }
-
-    }
-
-    if (progress.status() == ProgressInfo::Done) {
-        // We keep track very well of pending conflicts.
-        // Inform other components about them.
-        QStringList conflicts;
-        foreach (Activity activity, _model->errorsList()) {
-            if (activity._folder == folder
-                && activity._status == SyncFileItem::Conflict) {
-                conflicts.append(activity._file);
-            }
-        }
-
-        emit ProgressDispatcher::instance()->folderConflicts(folder, conflicts);
-    }
-}
-
-void ActivityWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item){
-    auto folderInstance = FolderMan::instance()->folder(folder);
-
-    if (!folderInstance)
-        return;
-
-    // check if we are adding it to the right account and if it is useful information (protocol errors)
-    if(folderInstance->accountState() == _accountState){
-        qCWarning(lcActivity) << "Item " << item->_file << " retrieved resulted in " << item->_errorString;
-
-        Activity activity;
-        activity._type = Activity::SyncFileItemType; //client activity
-        activity._status = item->_status;
-        activity._dateTime = QDateTime::currentDateTime();
-        activity._message = item->_originalFile;
-        activity._link = folderInstance->accountState()->account()->url();
-        activity._accName = folderInstance->accountState()->account()->displayName();
-        activity._file = item->_file;
-        activity._folder = folder;
-
-        if(item->_status == SyncFileItem::NoStatus || item->_status == SyncFileItem::Success){
-            qCWarning(lcActivity) << "Item " << item->_file << " retrieved successfully.";
-            activity._message.prepend(" ");
-            activity._message.prepend(tr("Synced"));
-            _model->addSyncFileItemToActivityList(activity);
-        } else {
-            qCWarning(lcActivity) << "Item " << item->_file << " retrieved resulted in error " << item->_errorString;
-            activity._subject = item->_errorString;
-
-            if(item->_status == SyncFileItem::Status::FileIgnored) {
-                _model->addIgnoredFileToList(activity);
-            } else {
-                // add 'protocol error' to activity list
-                _model->addErrorToActivityList(activity);
-            }
-        }
-    }
-}
-
-void ActivityWidget::addError(const QString &folderAlias, const QString &message,
-    ErrorCategory category)
-{
-    auto folderInstance = FolderMan::instance()->folder(folderAlias);
-    if (!folderInstance)
-        return;
-
-    if(folderInstance->accountState() == _accountState){
-        qCWarning(lcActivity) << "Item " << folderInstance->shortGuiLocalPath() << " retrieved resulted in " << message;
-
-        Activity activity;
-        activity._type = Activity::SyncResultType;
-        activity._status = SyncResult::Error;
-        activity._dateTime = QDateTime::fromString(QDateTime::currentDateTime().toString(), Qt::ISODate);
-        activity._subject = message;
-        activity._message = folderInstance->shortGuiLocalPath();
-        activity._link = folderInstance->shortGuiLocalPath();
-        activity._accName = folderInstance->accountState()->account()->displayName();
-        activity._folder = folderAlias;
-
-
-        if (category == ErrorCategory::InsufficientRemoteStorage) {
-            ActivityLink link;
-            link._label = tr("Retry all uploads");
-            link._link = folderInstance->path();
-            link._verb = "";
-            link._isPrimary = true;
-            activity._links.append(link);
-        }
-
-        // add 'other errors' to activity list
-        _model->addErrorToActivityList(activity);
-    }
-}
-
-
-void ActivityWidget::slotPrimaryButtonClickedOnListView(const QModelIndex &index){
-    QUrl link = qvariant_cast<QString>(index.data(ActivityItemDelegate::LinkRole));
-    QString objectType = index.data(ActivityItemDelegate::ObjectTypeRole).toString();
-    if(!link.isEmpty()){
-        qCWarning(lcActivity) << "Opening" << link.toString() <<  "in browser for Notification/Activity" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
-        Utility::openBrowser(link, this);
-    } else if(objectType == _remote_share){
-        QVariant customItem = index.data(ActivityItemDelegate::ActionsLinksRole).toList().first();
-        ActivityLink actionLink = qvariant_cast<ActivityLink>(customItem);
-        if(actionLink._label == _accept){
-            qCWarning(lcActivity) << objectType <<  "action" << actionLink._label << "for" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
-            const QString accountName = index.data(ActivityItemDelegate::AccountRole).toString();
-            slotSendNotificationRequest(accountName, actionLink._link, actionLink._verb, index.row());
-        } else {
-            qCWarning(lcActivity) << "Failed: " << objectType <<  "action" << actionLink._label << "for" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
-        }
-    }
-}
-
-void ActivityWidget::slotSecondaryButtonClickedOnListView(const QModelIndex &index){
-    QList<QVariant> customList = index.data(ActivityItemDelegate::ActionsLinksRole).toList();
-    QString objectType = index.data(ActivityItemDelegate::ObjectTypeRole).toString();
-
-    QList<ActivityLink> actionLinks;
-    foreach(QVariant customItem, customList){
-        actionLinks << qvariant_cast<ActivityLink>(customItem);
-    }
-
-    if(objectType == _remote_share && actionLinks.first()._label == _accept)
-        actionLinks.removeFirst();
-
-    if(qvariant_cast<Activity::Type>(index.data(ActivityItemDelegate::ActionRole)) == Activity::Type::NotificationType){
-        const QString accountName = index.data(ActivityItemDelegate::AccountRole).toString();
-        if(actionLinks.size() == 1){
-            if(actionLinks.at(0)._verb == "DELETE"){
-                qCWarning(lcActivity) << "Dismissing Notification/Activity" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
-                slotSendNotificationRequest(index.data(ActivityItemDelegate::AccountRole).toString(), actionLinks.at(0)._link, actionLinks.at(0)._verb, index.row());
-            }
-        } else if(actionLinks.size() > 1){
-            QMenu menu;
-            qCWarning(lcActivity) << "Displaying menu for Notification/Activity" << qvariant_cast<QString>(index.data(ActivityItemDelegate::ActionTextRole));
-            foreach (ActivityLink actionLink, actionLinks) {
-                QAction *menuAction = new QAction(actionLink._label, &menu);
-                connect(menuAction, &QAction::triggered, this, [this, index, accountName, actionLink] {
-                    this->slotSendNotificationRequest(accountName, actionLink._link, actionLink._verb, index.row());
-                });
-                menu.addAction(menuAction);
-            }
-            menu.exec(QCursor::pos());
-        }
-    }
-
-    Activity::Type activityType = qvariant_cast<Activity::Type>(index.data(ActivityItemDelegate::ActionRole));
-    if(activityType == Activity::Type::SyncFileItemType || activityType == Activity::Type::SyncResultType)
-        slotOpenFile(index);
-}
-
-void ActivityWidget::slotNotificationRequestFinished(int statusCode)
-{
-    int row = sender()->property("activityRow").toInt();
-
-    // the ocs API returns stat code 100 or 200 inside the xml if it succeeded.
-    if (statusCode != OCS_SUCCESS_STATUS_CODE && statusCode != OCS_SUCCESS_STATUS_CODE_V2) {
-        qCWarning(lcActivity) << "Notification Request to Server failed, leave notification visible.";
-    } else {
-       // to do use the model to rebuild the list or remove the item
-        qCWarning(lcActivity) << "Notification Request to Server successed, rebuilding list.";
-       _model->removeActivityFromActivityList(row);
-    }
-}
-
-void ActivityWidget::slotRefreshActivities()
-{
-    _model->slotRefreshActivity();
-}
-
-void ActivityWidget::slotRefreshNotifications()
-{
-    // start a server notification handler if no notification requests
-    // are running
-    if (_notificationRequestsRunning == 0) {
-        ServerNotificationHandler *snh = new ServerNotificationHandler(_accountState);
-        connect(snh, &ServerNotificationHandler::newNotificationList,
-            this, &ActivityWidget::slotBuildNotificationDisplay);
-
-        snh->slotFetchNotifications();
-    } else {
-        qCWarning(lcActivity) << "Notification request counter not zero.";
-    }
-}
-
-void ActivityWidget::slotRemoveAccount()
-{
-    _model->slotRemoveAccount();
-}
-
-void ActivityWidget::showLabels()
-{
-    _ui->_bottomLabel->hide(); // hide whatever was there before
-    QString t("");
-    QSetIterator<QString> i(_accountsWithoutActivities);
-    while (i.hasNext()) {
-        t.append(tr("<br/>Account %1 does not have activities enabled.").arg(i.next()));
-    }
-    if(!t.isEmpty()){
-        _ui->_bottomLabel->setTextFormat(Qt::RichText);
-        _ui->_bottomLabel->setText(t);
-        _ui->_bottomLabel->show();
-    }
-}
-
-void ActivityWidget::slotAccountActivityStatus(int statusCode)
-{
-    if (!(_accountState && _accountState->account())) {
-        return;
-    }
-    if (statusCode == 999) {
-        _accountsWithoutActivities.insert(_accountState->account()->displayName());
-    } else {
-        _accountsWithoutActivities.remove(_accountState->account()->displayName());
-    }
-
-    checkActivityWidgetVisibility();
-    showLabels();
-}
-
-// FIXME: Reused from protocol widget. Move over to utilities.
-QString ActivityWidget::timeString(QDateTime dt, QLocale::FormatType format) const
-{
-    const QLocale loc = QLocale::system();
-    QString dtFormat = loc.dateTimeFormat(format);
-    static const QRegExp re("(HH|H|hh|h):mm(?!:s)");
-    dtFormat.replace(re, "\\1:mm:ss");
-    return loc.toString(dt, dtFormat);
-}
-
-void ActivityWidget::storeActivityList(QTextStream &ts)
-{
-    ActivityList activities = _model->activityList();
-
-    foreach (Activity activity, activities) {
-        ts << right
-           // account name
-           << qSetFieldWidth(activity._accName.length())
-           << activity._accName
-           // separator
-           << qSetFieldWidth(2) << " - "
-
-           // date and time
-           << qSetFieldWidth(activity._dateTime.toString().length())
-           << activity._dateTime.toString()
-           // separator
-           << qSetFieldWidth(2) << " - "
-
-           // fileq
-           << qSetFieldWidth(activity._file.length())
-           << activity._file
-           // separator
-           << qSetFieldWidth(2) << " - "
-
-           // subject
-           << qSetFieldWidth(activity._subject.length())
-           << activity._subject
-           // separator
-           << qSetFieldWidth(2) << " - "
-
-          // message
-          << qSetFieldWidth(activity._message.length())
-          << activity._message
-          << endl;
-    }
-}
-
-void ActivityWidget::checkActivityWidgetVisibility()
-{
-    int accountCount = AccountManager::instance()->accounts().count();
-    bool hasAccountsWithActivity =
-        _accountsWithoutActivities.count() != accountCount;
-
-    _ui->_activityList->setVisible(hasAccountsWithActivity);
-
-    emit hideActivityTab(!hasAccountsWithActivity);
-}
-
-void ActivityWidget::slotOpenFile(QModelIndex indx)
-{
-    qCDebug(lcActivity) << indx.isValid() << indx.data(ActivityItemDelegate::PathRole).toString() << QFile::exists(indx.data(ActivityItemDelegate::PathRole).toString());
-    if (indx.isValid()) {
-        QString fullPath = indx.data(ActivityItemDelegate::PathRole).toString();
-        if(!fullPath.isEmpty()){
-            if (QFile::exists(fullPath)) {
-                showInFileManager(fullPath);
-            }
-        }
-    }
-}
-
-// GUI: Display the notifications.
-// All notifications in list are coming from the same account
-// but in the _widgetForNotifId hash widgets for all accounts are
-// collected.
-void ActivityWidget::slotBuildNotificationDisplay(const ActivityList &list)
-{
-    // Whether a new notification was added to the list
-    bool newNotificationShown = false;
-
-    _model->clearNotifications();
-
-    foreach (auto activity, list) {
-        if (_blacklistedNotifications.contains(activity)) {
-            qCInfo(lcActivity) << "Activity in blacklist, skip";
-            continue;
-        }
-
-        // handle gui logs. In order to NOT annoy the user with every fetching of the
-        // notifications the notification id is stored in a Set. Only if an id
-        // is not in the set, it qualifies for guiLog.
-        // Important: The _guiLoggedNotifications set must be wiped regularly which
-        // will repeat the gui log.
-
-        // after one hour, clear the gui log notification store
-        if (_guiLogTimer.elapsed() > 60 * 60 * 1000) {
-            _guiLoggedNotifications.clear();
-        }
-
-        if (!_guiLoggedNotifications.contains(activity._id)) {
-            newNotificationShown = true;
-            _guiLoggedNotifications.insert(activity._id);
-
-            // Assemble a tray notification for the NEW notification
-            ConfigFile cfg;
-            if(cfg.optionalServerNotifications()){
-                if(AccountManager::instance()->accounts().count() == 1){
-                    emit guiLog(activity._subject, "");
-                } else {
-                    emit guiLog(activity._subject, activity._accName);
-                }
-            }
-        }
-
-        _model->addNotificationToActivityList(activity);
-    }
-
-    // restart the gui log timer now that we show a new notification
-    if(newNotificationShown) {
-        _guiLogTimer.start();
-    }
-}
-
-void ActivityWidget::slotSendNotificationRequest(const QString &accountName, const QString &link, const QByteArray &verb, int row)
-{
-    qCInfo(lcActivity) << "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());
-            QUrl l(link);
-            job->setLinkAndVerb(l, verb);
-            job->setProperty("activityRow", QVariant::fromValue(row));
-            connect(job, &AbstractNetworkJob::networkError,
-                this, &ActivityWidget::slotNotifyNetworkError);
-            connect(job, &NotificationConfirmJob::jobFinished,
-                this, &ActivityWidget::slotNotifyServerFinished);
-            job->start();
-
-            // count the number of running notification requests. If this member var
-            // is larger than zero, no new fetching of notifications is started
-            _notificationRequestsRunning++;
-        }
-    } else {
-        qCWarning(lcActivity) << "Notification Links: Invalid verb:" << verb;
-    }
-}
-
-void ActivityWidget::endNotificationRequest(int replyCode)
-{
-    _notificationRequestsRunning--;
-    slotNotificationRequestFinished(replyCode);
-}
-
-void ActivityWidget::slotNotifyNetworkError(QNetworkReply *reply)
-{
-    NotificationConfirmJob *job = qobject_cast<NotificationConfirmJob *>(sender());
-    if (!job) {
-        return;
-    }
-
-    int resultCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
-
-    endNotificationRequest(resultCode);
-    qCWarning(lcActivity) << "Server notify job failed with code " << resultCode;
-}
-
-void ActivityWidget::slotNotifyServerFinished(const QString &reply, int replyCode)
-{
-    NotificationConfirmJob *job = qobject_cast<NotificationConfirmJob *>(sender());
-    if (!job) {
-        return;
-    }
-
-    endNotificationRequest(replyCode);
-    qCInfo(lcActivity) << "Server Notification reply code" << replyCode << reply;
-}
-
-void ActivityWidget::slotStyleChanged()
-{
-    // Notify the other widgets (Dark-/Light-Mode switching)
-    emit styleChanged();
-}
-
-/* ==================================================================== */
-
-ActivitySettings::ActivitySettings(AccountState *accountState, QWidget *parent)
-    : QWidget(parent)
-    , _accountState(accountState)
-{
-    _vbox = new QVBoxLayout(this);
-    setLayout(_vbox);
-
-    _activityWidget = new ActivityWidget(_accountState, this);
-
-    _vbox->insertWidget(1, _activityWidget);
-    connect(_activityWidget, &ActivityWidget::guiLog, this, &ActivitySettings::guiLog);
-    connect(&_notificationCheckTimer, &QTimer::timeout,
-        this, &ActivitySettings::slotRegularNotificationCheck);
-
-    // Add a progress indicator to spin if the acitivity list is updated.
-    _progressIndicator = new QProgressIndicator(this);
-
-    // connect a model signal to stop the animation
-    connect(_activityWidget, &ActivityWidget::rowsInserted, _progressIndicator, &QProgressIndicator::stopAnimation);
-    connect(_activityWidget, &ActivityWidget::rowsInserted, this, &ActivitySettings::slotDisplayActivities);
-
-    // Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
-    connect(this, &ActivitySettings::styleChanged, _activityWidget, &ActivityWidget::slotStyleChanged);
-}
-
-void ActivitySettings::slotDisplayActivities(){
-   _vbox->removeWidget(_progressIndicator);
-}
-
-void ActivitySettings::setNotificationRefreshInterval(std::chrono::milliseconds interval)
-{
-    qCDebug(lcActivity) << "Starting Notification refresh timer with " << interval.count() / 1000 << " sec interval";
-    _notificationCheckTimer.start(interval.count());
-}
-
-void ActivitySettings::slotRemoveAccount()
-{
-    _activityWidget->slotRemoveAccount();
-}
-
-void ActivitySettings::slotRefresh()
-{
-    // QElapsedTimer isn't actually constructed as invalid.
-    if (!_timeSinceLastCheck.contains(_accountState)) {
-        _timeSinceLastCheck[_accountState].invalidate();
-    }
-    QElapsedTimer &timer = _timeSinceLastCheck[_accountState];
-
-    // Fetch Activities only if visible and if last check is longer than 15 secs ago
-    if (timer.isValid() && timer.elapsed() < NOTIFICATION_REQUEST_FREE_PERIOD) {
-        qCDebug(lcActivity) << "Do not check as last check is only secs ago: " << timer.elapsed() / 1000;
-        return;
-    }
-    if (_accountState && _accountState->isConnected()) {
-        if (isVisible() || !timer.isValid()) {
-            _vbox->insertWidget(0, _progressIndicator);
-            _vbox->setAlignment(_progressIndicator, Qt::AlignHCenter);
-            _progressIndicator->startAnimation();
-            _activityWidget->slotRefreshActivities();
-        }
-        _activityWidget->slotRefreshNotifications();
-        timer.start();
-    }
-}
-
-void ActivitySettings::slotRegularNotificationCheck()
-{
-    slotRefresh();
-}
-
-bool ActivitySettings::event(QEvent *e)
-{
-    if (e->type() == QEvent::Show) {
-        slotRefresh();
-    }
-    return QWidget::event(e);
-}
-
-ActivitySettings::~ActivitySettings()
-{
-}
-
-void ActivitySettings::slotStyleChanged()
-{
-    if(_progressIndicator)
-        _progressIndicator->setColor(QGuiApplication::palette().color(QPalette::Text));
-
-    // Notify the other widgets (Dark-/Light-Mode switching)
-    emit styleChanged();
-}
-
-}
diff --git a/src/gui/activitywidget.h b/src/gui/activitywidget.h
deleted file mode 100644 (file)
index ee271c6..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef ACTIVITYWIDGET_H
-#define ACTIVITYWIDGET_H
-
-#include <QDialog>
-#include <QDateTime>
-#include <QLocale>
-#include <QAbstractListModel>
-#include <chrono>
-
-#include "progressdispatcher.h"
-#include "owncloudgui.h"
-#include "account.h"
-#include "activitydata.h"
-#include "accountmanager.h"
-
-#include "ui_activitywidget.h"
-
-class QPushButton;
-class QProgressIndicator;
-
-namespace OCC {
-
-class Account;
-class AccountStatusPtr;
-class JsonApiJob;
-class ActivityListModel;
-
-namespace Ui {
-    class ActivityWidget;
-}
-class Application;
-
-/**
- * @brief The ActivityWidget class
- * @ingroup gui
- *
- * The list widget to display the activities, contained in the
- * subsequent ActivitySettings widget.
- */
-
-class ActivityWidget : public QWidget
-{
-    Q_OBJECT
-public:
-    explicit ActivityWidget(AccountState *accountState, QWidget *parent = nullptr);
-    ~ActivityWidget();
-    QSize sizeHint() const override { return ownCloudGui::settingsDialogSize(); }
-    void storeActivityList(QTextStream &ts);
-
-    /**
-     * Adjusts the activity tab's and some widgets' visibility
-     *
-     * Based on whether activities are enabled and whether notifications are
-     * available.
-     */
-    void checkActivityWidgetVisibility();
-
-public slots:
-    void slotOpenFile(QModelIndex indx);
-    void slotRefreshActivities();
-    void slotRefreshNotifications();
-    void slotRemoveAccount();
-    void slotAccountActivityStatus(int statusCode);
-    void addError(const QString &folderAlias, const QString &message, ErrorCategory category);
-    void slotProgressInfo(const QString &folder, const ProgressInfo &progress);
-    void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
-    void slotStyleChanged();
-
-signals:
-    void guiLog(const QString &, const QString &);
-    void rowsInserted();
-    void hideActivityTab(bool);
-    void sendNotificationRequest(const QString &accountName, const QString &link, const QByteArray &verb, int row);
-    void styleChanged();
-
-private slots:
-    void slotBuildNotificationDisplay(const ActivityList &list);
-    void slotSendNotificationRequest(const QString &accountName, const QString &link, const QByteArray &verb, int row);
-    void slotNotifyNetworkError(QNetworkReply *);
-    void slotNotifyServerFinished(const QString &reply, int replyCode);
-    void endNotificationRequest(int replyCode);
-    void slotNotificationRequestFinished(int statusCode);
-    void slotPrimaryButtonClickedOnListView(const QModelIndex &index);
-    void slotSecondaryButtonClickedOnListView(const QModelIndex &index);
-
-private:
-    void customizeStyle();
-    void showLabels();
-    QString timeString(QDateTime dt, QLocale::FormatType format) const;
-    Ui::ActivityWidget *_ui;
-    QSet<QString> _accountsWithoutActivities;
-    QElapsedTimer _guiLogTimer;
-    QSet<int> _guiLoggedNotifications;
-    ActivityList _blacklistedNotifications;
-
-    QTimer _removeTimer;
-
-    // number of currently running notification requests. If non zero,
-    // no query for notifications is started.
-    int _notificationRequestsRunning;
-
-    ActivityListModel *_model;
-    AccountState *_accountState;
-    const QString _accept;
-    const QString _remote_share;
-};
-
-
-/**
- * @brief The ActivitySettings class
- * @ingroup gui
- *
- * Implements a tab for the settings dialog, displaying the three activity
- * lists.
- */
-class ActivitySettings : public QWidget
-{
-    Q_OBJECT
-public:
-    explicit ActivitySettings(AccountState *accountState, QWidget *parent = nullptr);
-
-    ~ActivitySettings();
-    QSize sizeHint() const override { return ownCloudGui::settingsDialogSize(); }
-
-public slots:
-    void slotRefresh();
-    void slotRemoveAccount();
-    void setNotificationRefreshInterval(std::chrono::milliseconds interval);
-    void slotStyleChanged();
-
-private slots:
-    void slotRegularNotificationCheck();
-    void slotDisplayActivities();
-
-signals:
-    void guiLog(const QString &, const QString &);
-    void styleChanged();
-
-private:
-    bool event(QEvent *e) override;
-
-    ActivityWidget *_activityWidget;
-    QProgressIndicator *_progressIndicator;
-    QVBoxLayout *_vbox;
-    QTimer _notificationCheckTimer;
-    QHash<AccountState *, QElapsedTimer> _timeSinceLastCheck;
-
-    AccountState *_accountState;
-};
-}
-#endif // ActivityWIDGET_H
diff --git a/src/gui/activitywidget.ui b/src/gui/activitywidget.ui
deleted file mode 100644 (file)
index 7e5e9f7..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>OCC::ActivityWidget</class>
- <widget class="QWidget" name="OCC::ActivityWidget">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>652</width>
-    <height>556</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string notr="true">Form</string>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <property name="sizeConstraint">
-    <enum>QLayout::SetDefaultConstraint</enum>
-   </property>
-   <property name="leftMargin">
-    <number>0</number>
-   </property>
-   <property name="topMargin">
-    <number>0</number>
-   </property>
-   <property name="rightMargin">
-    <number>0</number>
-   </property>
-   <property name="bottomMargin">
-    <number>0</number>
-   </property>
-   <item>
-    <widget class="QListView" name="_activityList">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="frameShape">
-      <enum>QFrame::StyledPanel</enum>
-     </property>
-     <property name="frameShadow">
-      <enum>QFrame::Sunken</enum>
-     </property>
-     <property name="lineWidth">
-      <number>1</number>
-     </property>
-     <property name="sizeAdjustPolicy">
-      <enum>QAbstractScrollArea::AdjustToContents</enum>
-     </property>
-     <property name="editTriggers">
-      <set>QAbstractItemView::NoEditTriggers</set>
-     </property>
-     <property name="showDropIndicator" stdset="0">
-      <bool>false</bool>
-     </property>
-     <property name="defaultDropAction">
-      <enum>Qt::IgnoreAction</enum>
-     </property>
-     <property name="resizeMode">
-      <enum>QListView::Adjust</enum>
-     </property>
-     <property name="viewMode">
-      <enum>QListView::ListMode</enum>
-     </property>
-     <property name="modelColumn">
-      <number>0</number>
-     </property>
-     <property name="wordWrap">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QLabel" name="_bottomLabel">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="text">
-      <string notr="true">TextLabel</string>
-     </property>
-     <property name="textFormat">
-      <enum>Qt::RichText</enum>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <tabstops>
-  <tabstop>_activityList</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
index fcdfc073c9be5eab109dfcdbd832277b3b44f73a..1c7c250158933d302434b40a75fb6b478f7ba787 100644 (file)
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>785</width>
+    <width>516</width>
     <height>523</height>
    </rect>
   </property>
index 5d7dc94e8781830804203be6487f9d821f11d114..b9391cf7e59d15ce2291980dd211b2d96701e8e0 100644 (file)
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>563</width>
+    <width>516</width>
     <height>444</height>
    </rect>
   </property>
index 27662f715ad012e12e5b24fbe45e0b0428da4830..8916c28468b51d62f44601e70013e3afe6f019c5 100644 (file)
@@ -207,10 +207,6 @@ void ownCloudGui::slotSyncStateChange(Folder *folder)
         || result.status() == SyncResult::Error) {
         Logger::instance()->enterNextLogFile();
     }
-
-    if (result.status() == SyncResult::NotYetStarted) {
-        _settingsDialog->slotRefreshActivity(folder->accountState());
-    }
 }
 
 void ownCloudGui::slotFoldersChanged()
@@ -792,10 +788,7 @@ void ownCloudGui::setupActions()
     _navLinksMenu->setEnabled(false);
     _actionSettings = new QAction(tr("Settings â€¦"), this);
     _actionNewAccountWizard = new QAction(tr("New account â€¦"), this);
-    _actionRecent = new QAction(tr("View more activity â€¦"), this);
-    _actionRecent->setEnabled(true);
 
-    QObject::connect(_actionRecent, &QAction::triggered, this, &ownCloudGui::slotShowSyncProtocol);
     QObject::connect(_actionSettings, &QAction::triggered, this, &ownCloudGui::slotShowSettings);
     QObject::connect(_actionNewAccountWizard, &QAction::triggered, this, &ownCloudGui::slotNewAccountWizard);
     _actionHelp = new QAction(tr("Help"), this);
@@ -909,8 +902,6 @@ void ownCloudGui::slotRebuildRecentMenus()
     } else {
         _recentActionsMenu->addAction(tr("No items synced recently"))->setEnabled(false);
     }
-    // add a more... entry.
-    _recentActionsMenu->addAction(_actionRecent);
 }
 
 /// Returns true if the completion of a given item should show up in the
@@ -970,8 +961,6 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
         _actionStatus->setText(msg);
     }
 
-    _actionRecent->setIcon(QIcon()); // Fixme: Set a "in-progress"-item eventually.
-
     if (!progress._lastCompletedItem.isEmpty()
         && shouldShowInRecentsMenu(progress._lastCompletedItem)) {
         if (Progress::isWarningKind(progress._lastCompletedItem._status)) {
diff --git a/src/gui/servernotificationhandler.cpp b/src/gui/servernotificationhandler.cpp
deleted file mode 100644 (file)
index bcf3860..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "servernotificationhandler.h"
-#include "accountstate.h"
-#include "capabilities.h"
-#include "networkjobs.h"
-
-#include "iconjob.h"
-
-#include <QJsonDocument>
-#include <QJsonObject>
-
-namespace OCC {
-
-Q_LOGGING_CATEGORY(lcServerNotification, "nextcloud.gui.servernotification", QtInfoMsg)
-
-const QString notificationsPath = QLatin1String("ocs/v2.php/apps/notifications/api/v2/notifications");
-const char propertyAccountStateC[] = "oc_account_state";
-const int successStatusCode = 200;
-const int notModifiedStatusCode = 304;
-QMap<int, QIcon> ServerNotificationHandler::iconCache;
-
-ServerNotificationHandler::ServerNotificationHandler(AccountState *accountState, QObject *parent)
-    : QObject(parent)
-    , _accountState(accountState)
-{
-}
-
-void ServerNotificationHandler::slotFetchNotifications()
-{
-    // check connectivity and credentials
-    if (!(_accountState && _accountState->isConnected() &&
-          _accountState->account() && _accountState->account()->credentials() &&
-          _accountState->account()->credentials()->ready())) {
-        deleteLater();
-        return;
-    }
-    // check if the account has notifications enabled. If the capabilities are
-    // not yet valid, its assumed that notifications are available.
-    if (_accountState->account()->capabilities().isValid()) {
-        if (!_accountState->account()->capabilities().notificationsAvailable()) {
-            qCInfo(lcServerNotification) << "Account" << _accountState->account()->displayName() << "does not have notifications enabled.";
-            deleteLater();
-            return;
-        }
-    }
-
-    // if the previous notification job has finished, start next.
-    _notificationJob = new JsonApiJob(_accountState->account(), notificationsPath, this);
-    QObject::connect(_notificationJob.data(), &JsonApiJob::jsonReceived,
-        this, &ServerNotificationHandler::slotNotificationsReceived);
-    QObject::connect(_notificationJob.data(), &JsonApiJob::etagResponseHeaderReceived,
-        this, &ServerNotificationHandler::slotEtagResponseHeaderReceived);
-    _notificationJob->setProperty(propertyAccountStateC, QVariant::fromValue<AccountState *>(_accountState));
-    _notificationJob->addRawHeader("If-None-Match", _accountState->notificationsEtagResponseHeader());
-    _notificationJob->start();
-}
-
-void ServerNotificationHandler::slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode){
-    if(statusCode == successStatusCode){
-        qCWarning(lcServerNotification) << "New Notification ETag Response Header received " << value;
-        AccountState *account = qvariant_cast<AccountState *>(sender()->property(propertyAccountStateC));
-        account->setNotificationsEtagResponseHeader(value);
-    }
-}
-
-void ServerNotificationHandler::slotIconDownloaded(QByteArray iconData){
-    QPixmap pixmap;
-    pixmap.loadFromData(iconData);
-    iconCache.insert(sender()->property("activityId").toInt(), QIcon(pixmap));
-}
-
-void ServerNotificationHandler::slotNotificationsReceived(const QJsonDocument &json, int statusCode)
-{
-    if (statusCode != successStatusCode && statusCode != notModifiedStatusCode) {
-        qCWarning(lcServerNotification) << "Notifications failed with status code " << statusCode;
-        deleteLater();
-        return;
-    }
-
-    if (statusCode == notModifiedStatusCode) {
-        qCWarning(lcServerNotification) << "Status code " << statusCode << " Not Modified - No new notifications.";
-        deleteLater();
-        return;
-    }
-
-    auto notifies = json.object().value("ocs").toObject().value("data").toArray();
-
-    AccountState *ai = qvariant_cast<AccountState *>(sender()->property(propertyAccountStateC));
-
-    ActivityList list;
-
-    foreach (auto element, notifies) {
-        Activity a;
-        auto json = element.toObject();
-        a._type = Activity::NotificationType;
-        a._accName = ai->account()->displayName();
-        a._id = json.value("notification_id").toInt();
-
-        //need to know, specially for remote_share
-        a._objectType = json.value("object_type").toString();
-        a._status = 0;
-
-        a._subject = json.value("subject").toString();
-        a._message = json.value("message").toString();
-
-        if(!json.value("icon").toString().isEmpty()){
-            IconJob *iconJob = new IconJob(QUrl(json.value("icon").toString()));
-            iconJob->setProperty("activityId", a._id);
-            connect(iconJob, &IconJob::jobFinished, this, &ServerNotificationHandler::slotIconDownloaded);
-        }
-
-        QUrl link(json.value("link").toString());
-        if (!link.isEmpty()) {
-            if(link.host().isEmpty()){
-                link.setScheme(ai->account()->url().scheme());
-                link.setHost(ai->account()->url().host());
-            }
-            if (link.port() == -1) {
-                link.setPort(ai->account()->url().port());
-            }
-        }
-        a._link = link;
-        a._dateTime = QDateTime::fromString(json.value("datetime").toString(), Qt::ISODate);
-
-        auto actions = json.value("actions").toArray();
-        foreach (auto action, actions) {
-            auto actionJson = action.toObject();
-            ActivityLink al;
-            al._label = QUrl::fromPercentEncoding(actionJson.value("label").toString().toUtf8());
-            al._link = actionJson.value("link").toString();
-            al._verb = actionJson.value("type").toString().toUtf8();
-            al._isPrimary = actionJson.value("primary").toBool();
-
-            a._links.append(al);
-        }
-
-        // Add another action to dismiss notification on server
-        // https://github.com/owncloud/notifications/blob/master/docs/ocs-endpoint-v1.md#deleting-a-notification-for-a-user
-        ActivityLink al;
-        al._label = tr("Dismiss");
-        al._link  = Utility::concatUrlPath(ai->account()->url(), notificationsPath + "/" + QString::number(a._id)).toString();
-        al._verb  = "DELETE";
-        al._isPrimary = false;
-        a._links.append(al);
-
-        list.append(a);
-    }
-    emit newNotificationList(list);
-
-    deleteLater();
-}
-}
diff --git a/src/gui/servernotificationhandler.h b/src/gui/servernotificationhandler.h
deleted file mode 100644 (file)
index f0276da..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef SERVERNOTIFICATIONHANDLER_H
-#define SERVERNOTIFICATIONHANDLER_H
-
-#include <QtCore>
-
-#include "activitywidget.h"
-
-class QJsonDocument;
-
-namespace OCC {
-
-class ServerNotificationHandler : public QObject
-{
-    Q_OBJECT
-public:
-    explicit ServerNotificationHandler(AccountState *accountState, QObject *parent = nullptr);
-    static QMap<int, QIcon> iconCache;
-
-signals:
-    void newNotificationList(ActivityList);
-
-public slots:
-    void slotFetchNotifications();
-
-private slots:
-    void slotNotificationsReceived(const QJsonDocument &json, int statusCode);
-    void slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode);
-    void slotIconDownloaded(QByteArray iconData);
-
-private:
-    QPointer<JsonApiJob> _notificationJob;
-    AccountState *_accountState;
-};
-}
-
-#endif // SERVERNOTIFICATIONHANDLER_H
index a80de4da5aa2b7ef4f20ce71606276b094345e2d..6fa7bfa470591a91eb8600446f78e81a9fb79a2c 100644 (file)
@@ -23,7 +23,6 @@
 #include "configfile.h"
 #include "progressdispatcher.h"
 #include "owncloudgui.h"
-#include "activitywidget.h"
 #include "accountmanager.h"
 
 #include <QLabel>
@@ -189,39 +188,13 @@ void SettingsDialog::showFirstPage()
     }
 }
 
-void SettingsDialog::showActivityPage()
-{
-    if (auto account = qvariant_cast<AccountState*>(sender()->property("account"))) {
-        _activitySettings[account]->show();
-        _ui->stack->setCurrentWidget(_activitySettings[account]);
-    }
-}
-
 void SettingsDialog::showIssuesList(AccountState *account) {
-    for (auto it = _actionGroupWidgets.begin(); it != _actionGroupWidgets.end(); ++it) {
+    /*for (auto it = _actionGroupWidgets.begin(); it != _actionGroupWidgets.end(); ++it) {
         if (it.value() == _activitySettings[account]) {
             it.key()->activate(QAction::ActionEvent::Trigger);
             break;
         }
-    }
-}
-
-void SettingsDialog::activityAdded(AccountState *s){
-    _ui->stack->addWidget(_activitySettings[s]);
-    connect(_activitySettings[s], &ActivitySettings::guiLog, _gui,
-        &ownCloudGui::slotShowOptionalTrayMessage);
-
-    ConfigFile cfg;
-    _activitySettings[s]->setNotificationRefreshInterval(cfg.notificationRefreshInterval());
-
-    // Note: all the actions have a '\n' because the account name is in two lines and
-    // all buttons must have the same size in order to keep a good layout
-    QAction *action = createColorAwareAction(QLatin1String(":/client/resources/activity.png"), tr("Activity"));
-    action->setProperty("account", QVariant::fromValue(s));
-    _toolBar->insertAction(_actionBefore, action);
-    _actionGroup->addAction(action);
-    _actionGroupWidgets.insert(action, _activitySettings[s]);
-    connect(action, &QAction::triggered, this, &SettingsDialog::showActivityPage);
+    }*/
 }
 
 void SettingsDialog::accountAdded(AccountState *s)
@@ -229,16 +202,6 @@ void SettingsDialog::accountAdded(AccountState *s)
     auto height = _toolBar->sizeHint().height();
     bool brandingSingleAccount = !Theme::instance()->multiAccount();
 
-    _activitySettings[s] = new ActivitySettings(s, this);
-
-
-
-    // if this is not the first account, then before we continue to add more accounts we add a separator
-    if(AccountManager::instance()->accounts().first().data() != s &&
-        AccountManager::instance()->accounts().size() >= 1){
-        _actionGroupWidgets.insert(_toolBar->insertSeparator(_actionBefore), _activitySettings[s]);
-    }
-
     QAction *accountAction;
     QImage avatar = s->account()->avatar();
     const QString actionText = brandingSingleAccount ? tr("Account") : s->account()->displayName();
@@ -270,15 +233,8 @@ void SettingsDialog::accountAdded(AccountState *s)
     connect(s->account().data(), &Account::accountChangedAvatar, this, &SettingsDialog::slotAccountAvatarChanged);
     connect(s->account().data(), &Account::accountChangedDisplayName, this, &SettingsDialog::slotAccountDisplayNameChanged);
 
-    // Refresh immediatly when getting online
-    connect(s, &AccountState::isConnectedChanged, this, &SettingsDialog::slotRefreshActivityAccountStateSender);
-
     // Connect styleChanged event, to adapt (Dark-/Light-Mode switching)
     connect(this, &SettingsDialog::styleChanged, accountSettings, &AccountSettings::slotStyleChanged);
-    connect(this, &SettingsDialog::styleChanged, _activitySettings[s], &ActivitySettings::slotStyleChanged);
-
-    activityAdded(s);
-    slotRefreshActivity(s);
 }
 
 void SettingsDialog::slotAccountAvatarChanged()
@@ -334,19 +290,6 @@ void SettingsDialog::accountRemoved(AccountState *s)
         _actionForAccount.remove(s->account().data());
     }
 
-    if(_activitySettings.contains(s)){
-        _activitySettings[s]->slotRemoveAccount();
-        _activitySettings[s]->hide();
-
-        // get the settings widget and the separator
-        foreach(QAction *action, _actionGroupWidgets.keys(_activitySettings[s])){
-            _actionGroupWidgets.remove(action);
-            _toolBar->removeAction(action);
-        }
-        _toolBar->widgetForAction(_actionBefore)->hide();
-        _activitySettings.remove(s);
-    }
-
     // Hide when the last account is deleted. We want to enter the same
     // state we'd be in the client was started up without an account
     // configured.
@@ -416,15 +359,4 @@ QAction *SettingsDialog::createColorAwareAction(const QString &iconPath, const Q
     return createActionWithIcon(coloredIcon, text, iconPath);
 }
 
-void SettingsDialog::slotRefreshActivityAccountStateSender()
-{
-    slotRefreshActivity(qobject_cast<AccountState*>(sender()));
-}
-
-void SettingsDialog::slotRefreshActivity(AccountState *accountState)
-{
-    if (accountState->isConnected())
-        _activitySettings[accountState]->slotRefresh();
-}
-
 } // namespace OCC
index f5ec654d967f1c39db72db8d6704da5529ee5cbe..8242522c29b716592b837afbe837f582fd05c714 100644 (file)
@@ -37,7 +37,6 @@ class AccountSettings;
 class Application;
 class FolderMan;
 class ownCloudGui;
-class ActivitySettings;
 
 /**
  * @brief The SettingsDialog class
@@ -55,11 +54,8 @@ public:
 
 public slots:
     void showFirstPage();
-    void showActivityPage();
     void showIssuesList(AccountState *account);
     void slotSwitchPage(QAction *action);
-    void slotRefreshActivity(AccountState *accountState);
-    void slotRefreshActivityAccountStateSender();
     void slotAccountAvatarChanged();
     void slotAccountDisplayNameChanged();
 
@@ -78,7 +74,6 @@ private slots:
 
 private:
     void customizeStyle();
-    void activityAdded(AccountState *);
 
     QAction *createColorAwareAction(const QString &iconName, const QString &fileName);
     QAction *createActionWithIcon(const QIcon &icon, const QString &text, const QString &iconPath = QString());
@@ -95,7 +90,6 @@ private:
     QHash<Account *, QAction *> _actionForAccount;
 
     QToolBar *_toolBar;
-    QMap<AccountState *, ActivitySettings *> _activitySettings;
 
     ownCloudGui *_gui;
 };
index 3f886ed222bc08d747b3a76e7323de2b3ad4353f..18632134f605935fad413f93ec3796c35f26151b 100644 (file)
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>693</width>
+    <width>516</width>
     <height>457</height>
    </rect>
   </property>
index 97d6a1a03444bd68c729f0afd14600363f7f2388..c377c69bb2a4c5a6782d59720ad10add0be9d397 100644 (file)
@@ -42,14 +42,12 @@ Systray::Systray() // TODO: make singleton, provide ::instance()
 {
     // Create QML tray engine, build component, set C++ backend context used in window.qml
     // Use pointer instead of engine() helper function until Qt 5.12 is minimum standard
-    QQmlEngine *engine = new QQmlEngine;
-    _trayComponent = new QQmlComponent(engine, QUrl(QStringLiteral("qrc:/qml/src/gui/tray/window.qml")));
-    _trayContext = engine->contextForObject(_trayComponent->create());
-
-    engine->addImageProvider("avatars", new ImageProvider);
-    engine->rootContext()->setContextProperty("userModelBackend", UserModel::instance());
-    engine->rootContext()->setContextProperty("activityModel", ActivityModel::instance());
-    engine->rootContext()->setContextProperty("systrayBackend", this);
+    _trayEngine = new QQmlEngine;
+    _trayEngine->addImageProvider("avatars", new ImageProvider);
+    _trayEngine->rootContext()->setContextProperty("userModelBackend", UserModel::instance());
+    _trayEngine->rootContext()->setContextProperty("systrayBackend", this);
+    _trayComponent = new QQmlComponent(_trayEngine, QUrl(QStringLiteral("qrc:/qml/src/gui/tray/window.qml")));
+    _trayContext = _trayEngine->contextForObject(_trayComponent->create());
 
     // TODO: hack to pass the icon to QML
     //ctxt->setContextProperty("theme", QLatin1String("colored"));
@@ -59,8 +57,6 @@ Systray::Systray() // TODO: make singleton, provide ::instance()
         slotChangeActivityModel(AccountManager::instance()->accounts().first());
     }
 
-    //connect(AccountManager::instance(), &AccountManager::accountAdded,
-    //    this, &Systray::slotChangeActivityModel);
     hideWindow();
 }
 
@@ -72,6 +68,7 @@ void Systray::slotChangeActivityModel(const AccountStatePtr account)
 {
     _currentAccount = account;
     emit currentUserChanged();
+    _trayEngine->rootContext()->setContextProperty("activityModel", UserModel::instance()->currentActivityModel());
 }
 
 void Systray::showMessage(const QString &title, const QString &message, MessageIcon icon, int millisecondsTimeoutHint)
index f99f024e673eeba50526d4148f1fae106b51a844..50c277186bc49a07c00dfbb4135a3fc167537790 100644 (file)
@@ -62,6 +62,7 @@ private slots:
 
 private:
     AccountStatePtr _currentAccount;
+    QQmlEngine *_trayEngine;
     QQmlComponent *_trayComponent;
     QQmlContext *_trayContext;
 };
diff --git a/src/gui/tray/ActivityData.cpp b/src/gui/tray/ActivityData.cpp
new file mode 100644 (file)
index 0000000..866c979
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <QtCore>
+
+#include "activitydata.h"
+
+
+namespace OCC {
+
+bool operator<(const Activity &rhs, const Activity &lhs)
+{
+    return rhs._dateTime > lhs._dateTime;
+}
+
+bool operator==(const Activity &rhs, const Activity &lhs)
+{
+    return (rhs._type == lhs._type && rhs._id == lhs._id && rhs._accName == lhs._accName);
+}
+
+Activity::Identifier Activity::ident() const
+{
+    return Identifier(_id, _accName);
+}
+}
diff --git a/src/gui/tray/ActivityData.h b/src/gui/tray/ActivityData.h
new file mode 100644 (file)
index 0000000..d2f3c86
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef ACTIVITYDATA_H
+#define ACTIVITYDATA_H
+
+#include <QtCore>
+#include <QIcon>
+
+namespace OCC {
+/**
+ * @brief The ActivityLink class describes actions of an activity
+ *
+ * These are part of notifications which are mapped into activities.
+ */
+
+class ActivityLink
+{
+public:
+    QString _label;
+    QString _link;
+    QByteArray _verb;
+    bool _isPrimary;
+};
+
+/* ==================================================================== */
+/**
+ * @brief Activity Structure
+ * @ingroup gui
+ *
+ * contains all the information describing a single activity.
+ */
+
+class Activity
+{
+public:
+    typedef QPair<qlonglong, QString> Identifier;
+
+    enum Type {
+        ActivityType,
+        NotificationType,
+        SyncResultType,
+        SyncFileItemType
+    };
+
+    Type _type;
+    qlonglong _id;
+    QString _objectType;
+    QString _subject;
+    QString _message;
+    QString _folder;
+    QString _file;
+    QUrl _link;
+    QDateTime _dateTime;
+    QString _accName;
+
+    // Stores information about the error
+    int _status;
+
+    QVector<ActivityLink> _links;
+    /**
+     * @brief Sort operator to sort the list youngest first.
+     * @param val
+     * @return
+     */
+
+
+    Identifier ident() const;
+};
+
+bool operator==(const Activity &rhs, const Activity &lhs);
+bool operator<(const Activity &rhs, const Activity &lhs);
+
+/* ==================================================================== */
+/**
+ * @brief The ActivityList
+ * @ingroup gui
+ *
+ * A QList based list of Activities
+ */
+
+typedef QList<Activity> ActivityList;
+}
+
+Q_DECLARE_METATYPE(OCC::Activity::Type)
+Q_DECLARE_METATYPE(OCC::ActivityLink)
+
+#endif // ACTIVITYDATA_H
diff --git a/src/gui/tray/ActivityListModel.cpp b/src/gui/tray/ActivityListModel.cpp
new file mode 100644 (file)
index 0000000..4a875d2
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <QtCore>
+#include <QAbstractListModel>
+#include <QWidget>
+#include <QIcon>
+#include <QJsonObject>
+#include <QJsonDocument>
+
+#include "account.h"
+#include "accountstate.h"
+#include "accountmanager.h"
+#include "folderman.h"
+#include "accessmanager.h"
+
+#include "ActivityData.h"
+#include "ActivityListModel.h"
+
+#include "theme.h"
+
+namespace OCC {
+
+Q_LOGGING_CATEGORY(lcActivity, "nextcloud.gui.activity", QtInfoMsg)
+
+ActivityListModel::ActivityListModel(AccountState *accountState, QObject* parent)
+    : QAbstractListModel()
+    , _accountState(accountState)
+{
+}
+
+QVariant ActivityListModel::data(const QModelIndex &index, int role) const
+{
+    Activity a;
+
+    // filter the get action here
+    // send only the text of the get action
+    // if there is more than one send the icon? the ...
+
+    if (!index.isValid())
+        return QVariant();
+
+    a = _finalList.at(index.row());
+    AccountStatePtr ast = AccountManager::instance()->account(a._accName);
+    if (!ast && _accountState != ast.data())
+        return QVariant();
+    QStringList list;
+
+    switch (role) {
+    case PathRole:
+        if(!a._file.isEmpty()){
+            auto folder = FolderMan::instance()->folder(a._folder);
+            QString relPath(a._file);
+            if(folder) relPath.prepend(folder->remotePath());
+            list = FolderMan::instance()->findFileInLocalFolders(relPath, ast->account());
+            if (list.count() > 0) {
+                return QVariant(list.at(0));
+            }
+            // File does not exist anymore? Let's try to open its path
+            if(QFileInfo(relPath).exists()) {
+                list = FolderMan::instance()->findFileInLocalFolders(QFileInfo(relPath).path(), ast->account());
+                if (list.count() > 0) {
+                    return QVariant(list.at(0));
+                }
+            }
+        }
+        return QVariant();
+     case ActionsLinksRole:{
+        QList<QVariant> customList;
+        foreach (ActivityLink customItem, a._links) {
+            QVariant customVariant;
+            customVariant.setValue(customItem);
+            customList << customVariant;
+        }
+        return customList;
+    }
+    case ActionIconRole:{
+        ActionIcon actionIcon;
+        if(a._type == Activity::NotificationType){
+           /*QIcon cachedIcon = ServerNotificationHandler::iconCache.value(a._id);
+            if(!cachedIcon.isNull()) {
+               actionIcon.iconType = ActivityIconType::iconUseCached;
+               actionIcon.cachedIcon = cachedIcon;
+            } else {
+                actionIcon.iconType = ActivityIconType::iconBell;
+            }*/
+        } else if(a._type == Activity::SyncResultType){
+            actionIcon.iconType = ActivityIconType::iconStateError;
+        } else if(a._type == Activity::SyncFileItemType){
+               if(a._status == SyncFileItem::NormalError
+                   || a._status == SyncFileItem::FatalError
+                   || a._status == SyncFileItem::DetailError
+                   || a._status == SyncFileItem::BlacklistedError) {
+                   actionIcon.iconType = ActivityIconType::iconStateError;
+               } else if(a._status == SyncFileItem::SoftError
+                         || a._status == SyncFileItem::Conflict
+                         || a._status == SyncFileItem::Restoration
+                         || a._status == SyncFileItem::FileLocked){
+                   actionIcon.iconType = ActivityIconType::iconStateWarning;
+               } else if(a._status == SyncFileItem::FileIgnored){
+                   actionIcon.iconType = ActivityIconType::iconStateInfo;
+               } else {
+                   actionIcon.iconType = ActivityIconType::iconStateSync;
+               }
+        } else {
+            actionIcon.iconType = ActivityIconType::iconActivity;
+        }
+        QVariant icn;
+        icn.setValue(actionIcon);
+        return icn;
+    }
+    case ObjectTypeRole:
+        return a._objectType;
+    case ActionRole:{
+        QVariant type;
+        type.setValue(a._type);
+        return type;
+    }
+    case ActionTextRole:
+        return a._subject;
+    case MessageRole:
+        return a._message;
+    case LinkRole:
+        return a._link;
+    case AccountRole:
+        return a._accName;
+    case PointInTimeRole:
+        return QString("%1 (%2)").arg(a._dateTime.toLocalTime().toString(Qt::DefaultLocaleShortDate), Utility::timeAgoInWords(a._dateTime.toLocalTime()));
+    case AccountConnectedRole:
+        return (ast && ast->isConnected());
+    default:
+        return QVariant();
+    }
+    return QVariant();
+}
+
+int ActivityListModel::rowCount(const QModelIndex &) const
+{
+    return _finalList.count();
+}
+
+bool ActivityListModel::canFetchMore(const QModelIndex &) const
+{
+    // We need to be connected to be able to fetch more
+    if (_accountState && _accountState->isConnected()) {
+        // If the fetching is reported to be done or we are currently fetching we can't fetch more
+        if (!_doneFetching && !_currentlyFetching) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void ActivityListModel::startFetchJob()
+{
+    if (!_accountState->isConnected()) {
+        return;
+    }
+    JsonApiJob *job = new JsonApiJob(_accountState->account(), QLatin1String("ocs/v2.php/cloud/activity"), this);
+    QObject::connect(job, &JsonApiJob::jsonReceived,
+        this, &ActivityListModel::slotActivitiesReceived);
+
+    QUrlQuery params;
+    params.addQueryItem(QLatin1String("start"), QString::number(_currentItem));
+    params.addQueryItem(QLatin1String("count"), QString::number(100));
+    job->addQueryParams(params);
+
+    _currentlyFetching = true;
+    qCInfo(lcActivity) << "Start fetching activities for " << _accountState->account()->displayName();
+    job->start();
+}
+
+void ActivityListModel::slotActivitiesReceived(const QJsonDocument &json, int statusCode)
+{
+    auto activities = json.object().value("ocs").toObject().value("data").toArray();
+
+    ActivityList list;
+    auto ast = _accountState;
+    if (!ast) {
+        return;
+    }
+
+    if (activities.size() == 0) {
+        _doneFetching = true;
+    }
+
+    _currentlyFetching = false;
+    _currentItem += activities.size();
+
+    foreach (auto activ, activities) {
+        auto json = activ.toObject();
+
+        Activity a;
+        a._type = Activity::ActivityType;
+        a._accName = ast->account()->displayName();
+        a._id = json.value("id").toInt();
+        a._subject = json.value("subject").toString();
+        a._message = json.value("message").toString();
+        a._file = json.value("file").toString();
+        a._link = QUrl(json.value("link").toString());
+        a._dateTime = QDateTime::fromString(json.value("date").toString(), Qt::ISODate);
+        list.append(a);
+    }
+
+    _activityLists.append(list);
+
+    emit activityJobStatusCode(statusCode);
+
+    combineActivityLists();
+}
+
+void ActivityListModel::addErrorToActivityList(Activity activity) {
+    qCInfo(lcActivity) << "Error successfully added to the notification list: " << activity._subject;
+    _notificationErrorsLists.prepend(activity);
+    combineActivityLists();
+}
+
+void ActivityListModel::addIgnoredFileToList(Activity newActivity) {
+    qCInfo(lcActivity) << "First checking for duplicates then add file to the notification list of ignored files: " << newActivity._file;
+
+    bool duplicate = false;
+    if(_listOfIgnoredFiles.size() == 0){
+        _notificationIgnoredFiles = newActivity;
+        _notificationIgnoredFiles._subject = tr("Files from the ignore list as well as symbolic links are not synced. This includes:");
+        _listOfIgnoredFiles.append(newActivity);
+        return;
+    }
+
+    foreach(Activity activity, _listOfIgnoredFiles){
+        if(activity._file == newActivity._file){
+            duplicate = true;
+            break;
+        }
+    }
+
+    if(!duplicate){
+        _notificationIgnoredFiles._message.append(", " + newActivity._file);
+    }
+}
+
+void ActivityListModel::addNotificationToActivityList(Activity activity) {
+    qCInfo(lcActivity) << "Notification successfully added to the notification list: " << activity._subject;
+    _notificationLists.prepend(activity);
+    combineActivityLists();
+}
+
+void ActivityListModel::clearNotifications() {
+    qCInfo(lcActivity) << "Clear the notifications";
+    _notificationLists.clear();
+    combineActivityLists();
+}
+
+void ActivityListModel::removeActivityFromActivityList(int row) {
+    Activity activity = _finalList.at(row);
+    removeActivityFromActivityList(activity);
+    combineActivityLists();
+}
+
+void ActivityListModel::addSyncFileItemToActivityList(Activity activity) {
+    qCInfo(lcActivity) << "Successfully added to the activity list: " << activity._subject;
+    _syncFileItemLists.prepend(activity);
+    combineActivityLists();
+}
+
+void ActivityListModel::removeActivityFromActivityList(Activity activity) {
+    qCInfo(lcActivity) << "Activity/Notification/Error successfully dismissed: " << activity._subject;
+    qCInfo(lcActivity) << "Trying to remove Activity/Notification/Error from view... ";
+
+    int index = -1;
+    if(activity._type == Activity::ActivityType){
+        index = _activityLists.indexOf(activity);
+        if(index != -1) _activityLists.removeAt(index);
+    } else if(activity._type == Activity::NotificationType){
+        index = _notificationLists.indexOf(activity);
+        if(index != -1) _notificationLists.removeAt(index);
+    } else {
+        index = _notificationErrorsLists.indexOf(activity);
+        if(index != -1) _notificationErrorsLists.removeAt(index);
+    }
+
+    if(index != -1){
+        qCInfo(lcActivity) << "Activity/Notification/Error successfully removed from the list.";
+        qCInfo(lcActivity) << "Updating Activity/Notification/Error view.";
+        combineActivityLists();
+    }
+}
+
+void ActivityListModel::combineActivityLists()
+{
+    ActivityList resultList;
+
+    if(_notificationErrorsLists.count() > 0) {
+        std::sort(_notificationErrorsLists.begin(), _notificationErrorsLists.end());
+        resultList.append(_notificationErrorsLists);
+    }
+    if(_listOfIgnoredFiles.size() > 0)
+        resultList.append(_notificationIgnoredFiles);
+
+    if(_notificationLists.count() > 0) {
+        std::sort(_notificationLists.begin(), _notificationLists.end());
+        resultList.append(_notificationLists);
+    }
+
+    if(_syncFileItemLists.count() > 0) {
+        std::sort(_syncFileItemLists.begin(), _syncFileItemLists.end());
+        resultList.append(_syncFileItemLists);
+    }
+
+    if(_activityLists.count() > 0) {
+        std::sort(_activityLists.begin(), _activityLists.end());
+        resultList.append(_activityLists);
+    }
+
+    beginResetModel();
+    _finalList.clear();
+    endResetModel();
+
+    beginInsertRows(QModelIndex(), 0, resultList.count());
+    _finalList = resultList;
+    endInsertRows();
+}
+
+bool ActivityListModel::canFetchActivities() const {
+    return _accountState->isConnected() && _accountState->account()->capabilities().hasActivities();
+}
+
+void ActivityListModel::fetchMore(const QModelIndex &)
+{
+    if (canFetchActivities()) {
+        startFetchJob();
+    } else {
+        _doneFetching = true;
+        combineActivityLists();
+    }
+}
+
+void ActivityListModel::slotRefreshActivity()
+{
+    _activityLists.clear();
+    _doneFetching = false;
+    _currentItem = 0;
+
+    if (canFetchActivities()) {
+        startFetchJob();
+    } else {
+        _doneFetching = true;
+        combineActivityLists();
+    }
+}
+
+void ActivityListModel::slotRemoveAccount()
+{
+    _finalList.clear();
+    _activityLists.clear();
+    _currentlyFetching = false;
+    _doneFetching = false;
+    _currentItem = 0;
+}
+}
diff --git a/src/gui/tray/ActivityListModel.h b/src/gui/tray/ActivityListModel.h
new file mode 100644 (file)
index 0000000..1353015
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef ACTIVITYLISTMODEL_H
+#define ACTIVITYLISTMODEL_H
+
+#include <QtCore>
+
+#include "activitydata.h"
+
+class QJsonDocument;
+
+namespace OCC {
+
+Q_DECLARE_LOGGING_CATEGORY(lcActivity)
+
+class AccountState;
+
+/**
+ * @brief The ActivityListModel
+ * @ingroup gui
+ *
+ * Simple list model to provide the list view with data.
+ */
+
+class ActivityListModel : public QAbstractListModel
+{
+    Q_OBJECT
+public:
+    enum ActivityIconType {
+        iconUseCached = 0,
+        iconActivity,
+        iconBell,
+        iconStateError,
+        iconStateWarning,
+        iconStateInfo,
+        iconStateSync
+    };
+
+    enum datarole { ActionIconRole = Qt::UserRole + 1,
+        UserIconRole,
+    AccountRole,
+    ObjectTypeRole,
+    ActionsLinksRole,
+    ActionTextRole,
+    ActionRole,
+    MessageRole,
+    PathRole,
+    LinkRole,
+    PointInTimeRole,
+    AccountConnectedRole,
+    SyncFileStatusRole };
+
+    struct ActionIcon {
+        ActivityIconType iconType;
+        QIcon cachedIcon;
+    };
+
+    explicit ActivityListModel(AccountState *accountState, QObject* parent = 0);
+
+    QVariant data(const QModelIndex &index, int role) const override;
+    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+    bool canFetchMore(const QModelIndex &) const override;
+    void fetchMore(const QModelIndex &) override;
+
+    ActivityList activityList() { return _finalList; }
+    ActivityList errorsList() { return _notificationErrorsLists; }
+    void addNotificationToActivityList(Activity activity);
+    void clearNotifications();
+    void addErrorToActivityList(Activity activity);
+    void addIgnoredFileToList(Activity newActivity);
+    void addSyncFileItemToActivityList(Activity activity);
+    void removeActivityFromActivityList(int row);
+    void removeActivityFromActivityList(Activity activity);
+
+public slots:
+    void slotRefreshActivity();
+    void slotRemoveAccount();
+
+private slots:
+    void slotActivitiesReceived(const QJsonDocument &json, int statusCode);
+
+signals:
+    void activityJobStatusCode(int statusCode);
+
+private:
+    void startFetchJob();
+    void combineActivityLists();
+    bool canFetchActivities() const;
+
+    ActivityList _activityLists;
+    ActivityList _syncFileItemLists;
+    ActivityList _notificationLists;
+    ActivityList _listOfIgnoredFiles;
+    Activity _notificationIgnoredFiles;
+    ActivityList _notificationErrorsLists;
+    ActivityList _finalList;
+    AccountState *_accountState;
+    bool _currentlyFetching = false;
+    bool _doneFetching = false;
+    int _currentItem = 0;
+};
+}
+
+Q_DECLARE_METATYPE(OCC::ActivityListModel::ActionIcon)
+
+#endif // ACTIVITYLISTMODEL_H
index 7dd648fda9dd1d50741b64fb0dfec9ad90ed8658..8aaa58398d63abc048f6b0fbbf0188e4c15d1bfc 100644 (file)
@@ -6,7 +6,7 @@ import QtQuick.Layouts 1.2
 MenuItem {\r
 \r
     Connections {\r
-        target: systrayBackend\r
+        target: userModelBackend\r
         onRefreshUserMenu: {\r
             userLine.visible = isCurrentUser ? false : true\r
             userLine.height = isCurrentUser ? 0 : 60\r
@@ -17,7 +17,6 @@ MenuItem {
     visible: isCurrentUser ? false : true\r
     width: 216\r
     height: isCurrentUser ? 0 : 60\r
-    //color: "transparent"\r
 \r
     Rectangle {\r
         id: userLineBackground\r
@@ -43,7 +42,7 @@ MenuItem {
                 }\r
 \r
                 onClicked: {\r
-                    systrayBackend.switchCurrentUser(index)\r
+                    userModelBackend.switchCurrentUser(index)\r
                 }\r
 \r
                 RowLayout {\r
@@ -55,7 +54,7 @@ MenuItem {
                         id: accountAvatar\r
                         Layout.leftMargin: 4\r
                         verticalAlignment: Qt.AlignCenter\r
-                        source: avatar\r
+                        source: ("image://avatars/" + index)\r
                         Layout.preferredHeight: (userLineBackground.height -16)\r
                         Layout.preferredWidth: (userLineBackground.height -16)\r
                     }\r
index 95591226f1e68ad49eb580cb54eaf5cd1b8f39a7..9ee8ae42a7fe8fd95f4942ae453f805ecbfdf8b4 100644 (file)
@@ -10,6 +10,7 @@ namespace OCC {
 User::User(AccountStatePtr &account, const bool &isCurrent)
     : _account(account)
     , _isCurrentUser(isCurrent)
+    , _activityModel(new ActivityListModel(_account.data()))
 {
 }
 
@@ -32,6 +33,11 @@ Folder *User::getFolder()
     }
 }
 
+ActivityListModel *User::getActivityModel()
+{
+    return _activityModel;
+}
+
 void User::openLocalFolder()
 {
     QDesktopServices::openUrl(this->getFolder()->path());
@@ -67,11 +73,17 @@ QImage User::avatar() const
 {
     QImage img = AvatarJob::makeCircularAvatar(_account->account()->avatar());
     if (img.isNull()) {
-        img = QImage(":/client/resources/account.svg");
+        img = AvatarJob::makeCircularAvatar(QImage(":/client/resources/account.png"));
     }
     return img;
 }
 
+bool User::serverHasTalk() const
+{
+    auto test = _account->hasTalk();
+    return _account->hasTalk();
+}
+
 bool User::isCurrentUser() const
 {
     return _isCurrentUser;
@@ -79,6 +91,7 @@ bool User::isCurrentUser() const
 
 bool User::isConnected() const
 {
+    bool test = (_account->connectionStatus() == AccountState::ConnectionStatus::Connected);
     return (_account->connectionStatus() == AccountState::ConnectionStatus::Connected);
 }
 
@@ -143,17 +156,26 @@ Q_INVOKABLE QString UserModel::currentUserServer()
     return _users[_currentUserId].server();
 }
 
+Q_INVOKABLE bool UserModel::currentServerHasTalk()
+{
+    return _users[_currentUserId].serverHasTalk();
+}
+
 void UserModel::addUser(AccountStatePtr &user, const bool &isCurrent)
 {
-    auto newUser = User(user, isCurrent);
     beginInsertRows(QModelIndex(), rowCount(), rowCount());
-    _users << newUser;
+    _users << User(user, isCurrent);
     if (isCurrent) {
-        _currentUserId = _users.indexOf(newUser);
+        _currentUserId = _users.indexOf(_users.last());
     }
     endInsertRows();
 }
 
+int UserModel::currentUserIndex()
+{
+    return _currentUserId;
+}
+
 Q_INVOKABLE void UserModel::openCurrentAccountLocalFolder()
 {
     _users[_currentUserId].openLocalFolder();
@@ -204,74 +226,9 @@ QHash<int, QByteArray> UserModel::roleNames() const
     return roles;
 }
 
-/*-------------------------------------------------------------------------------------*/
-
-QString UserActivity::type() const
-{
-    return "Test";
-}
-QString UserActivity::fileName() const
-{
-    return "Test";
-}
-
-QString UserActivity::info() const
-{
-    return "Test";
-}
-
-
-ActivityModel *ActivityModel::_instance = nullptr;
-
-ActivityModel *ActivityModel::instance()
-{
-    if (_instance == nullptr) {
-        _instance = new ActivityModel();
-    }
-    return _instance;
-}
-
-ActivityModel::ActivityModel(QObject *parent)
-    : QAbstractListModel()
-{
-}
-
-QHash<int, QByteArray> ActivityModel::roleNames() const
-{
-    QHash<int, QByteArray> roles;
-    roles[TypeRole] = "type";
-    roles[FileNameRole] = "filename";
-    roles[InfoRole] = "info";
-    return roles;
-}
-
-int ActivityModel::rowCount(const QModelIndex &parent) const
+ActivityListModel *UserModel::currentActivityModel()
 {
-    Q_UNUSED(parent);
-    return _activities.count();
-}
-
-QVariant ActivityModel::data(const QModelIndex &index, int role) const
-{
-    if (index.row() < 0 || index.row() >= _activities.count()) {
-        return QVariant();
-    }
-
-    const UserActivity &activity = _activities[index.row()];
-    if (role == TypeRole)
-        return activity.type();
-    else if (role == FileNameRole)
-        return activity.fileName();
-    else if (role == InfoRole)
-        return activity.info();
-    return QVariant();
-}
-
-void ActivityModel::addActivity(const UserActivity &activity)
-{
-    beginInsertRows(QModelIndex(), rowCount(), rowCount());
-    _activities << activity;
-    endInsertRows();
+    return _users[currentUserIndex()].getActivityModel();
 }
 
 /*-------------------------------------------------------------------------------------*/
index 35eb3f9c2d4f1a07b05cdb55fbf724ce74676ebd..f93d33d8de0a8b0123724aa9c87006bff58e6e43 100644 (file)
@@ -6,6 +6,7 @@
 #include <QStringList>
 #include <QQuickImageProvider>
 
+#include "ActivityListModel.h"
 #include "accountmanager.h"
 #include "folderman.h"
 
@@ -22,15 +23,18 @@ public:
     bool isCurrentUser() const;
     void setCurrentUser(const bool &isCurrent);
     Folder *getFolder();
+    ActivityListModel *getActivityModel();
     void openLocalFolder();
     QString name() const;
     QString server() const;
+    bool serverHasTalk() const;
     QImage avatar() const;
     QString id() const;
 
 private:
     AccountStatePtr _account;
     bool _isCurrentUser;
+    ActivityListModel *_activityModel;
 };
 
 class UserModel : public QAbstractListModel
@@ -41,6 +45,7 @@ public:
     virtual ~UserModel() {};
 
     void addUser(AccountStatePtr &user, const bool &isCurrent = false);
+    int currentUserIndex();
 
     int rowCount(const QModelIndex &parent = QModelIndex()) const;
 
@@ -54,8 +59,11 @@ public:
     Q_INVOKABLE bool isCurrentUserConnected();
     Q_INVOKABLE QString currentUserName();
     Q_INVOKABLE QString currentUserServer();
+    Q_INVOKABLE bool currentServerHasTalk();
     Q_INVOKABLE void switchCurrentUser(const int &id);
 
+    ActivityListModel *currentActivityModel();
+
     enum UserRoles {
         NameRole = Qt::UserRole + 1,
         ServerRole,
@@ -85,40 +93,6 @@ private:
     void initUserList();
 };
 
-class UserActivity
-{
-public:
-    QString type() const;
-    QString fileName() const;
-    QString info() const;
-};
-
-class ActivityModel : public QAbstractListModel
-{
-    Q_OBJECT
-public:
-    static ActivityModel *instance();
-    virtual ~ActivityModel() {};
-
-    int rowCount(const QModelIndex &parent = QModelIndex()) const;
-    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-    void addActivity(const UserActivity &activity);
-
-    enum ActivityRoles {
-        TypeRole = Qt::UserRole + 1,
-        FileNameRole,
-        InfoRole
-    };
-
-protected:
-    QHash<int, QByteArray> roleNames() const;
-
-private:
-    static ActivityModel *_instance;
-    ActivityModel(QObject *parent = 0);
-    QList<UserActivity> _activities;
-};
-
 class ImageProvider : public QQuickImageProvider
 {
 public:
index 28e61f466518a6a0e14cdfa5da12e7df008d6a28..337302960676e61b8cf6bbe4dfd0130b48594fb5 100644 (file)
@@ -20,15 +20,25 @@ Window {
         }\r
     }\r
 \r
+    onVisibleChanged: {\r
+        currentAccountAvatar.source = ""\r
+        currentAccountAvatar.source = "image://avatars/currentUser"\r
+        currentAccountUser.text = userModelBackend.currentUserName();\r
+        currentAccountServer.text = userModelBackend.currentUserServer();\r
+        trayWindowTalkButton.visible = userModelBackend.currentServerHasTalk() ? true : false;\r
+    }\r
+\r
     Connections {\r
         target: userModelBackend\r
         onRefreshCurrentUserGui: {\r
-            currentAccountAvatar.source = userModelBackend.currentUserAvatar()\r
-            currentAccountUser.text = userModelBackend.currentUserName()\r
-            currentAccountServer.text = userModelBackend.currentUserServer()\r
+            currentAccountAvatar.source = ""\r
+            currentAccountAvatar.source = "image://avatars/currentUser"\r
+            currentAccountUser.text = userModelBackend.currentUserName();\r
+            currentAccountServer.text = userModelBackend.currentUserServer();\r
         }\r
         onNewUserSelected: {\r
-            accountMenu.close()\r
+            accountMenu.close();\r
+            trayWindowTalkButton.visible = userModelBackend.currentServerHasTalk() ? true : false;\r
         }\r
     }\r
 \r
@@ -85,6 +95,7 @@ Window {
                         hoverEnabled: true\r
                         onClicked:\r
                         {\r
+                            accMenuLoginButton.text = (userModelBackend.isCurrentUserConnected() ? "Logout" : "Login")\r
                             accountMenu.open()\r
                         }\r
 \r
@@ -109,7 +120,7 @@ Window {
                             MenuSeparator { id: accountMenuSeparator }\r
 \r
                             MenuItem {\r
-                                text: (userModelBackend.isCurrentUserConnected() ? "Logout" : "Login")\r
+                                id: accMenuLoginButton\r
                                 onClicked: (userModelBackend.isCurrentUserConnected()\r
                                             ? userModelBackend.logout()\r
                                             : userModelBackend.login() )\r
@@ -188,7 +199,8 @@ Window {
                             id: currentAccountAvatar\r
                             Layout.leftMargin: 8\r
                             verticalAlignment: Qt.AlignCenter\r
-                            source: userModelBackend.currentUserAvatar()\r
+                            cache: false\r
+                            source: "image://avatars/currentUser"\r
                             Layout.preferredHeight: (trayWindowHeaderBackground.height -16)\r
                             Layout.preferredWidth: (trayWindowHeaderBackground.height -16)\r
                         }\r
@@ -262,6 +274,7 @@ Window {
                     Layout.preferredWidth: (trayWindowHeaderBackground.height)\r
                     Layout.preferredHeight: (trayWindowHeaderBackground.height)\r
                     flat: true\r
+                    visible: userModelBackend.currentServerHasTalk() ? true : false\r
 \r
                     icon.source: "qrc:///client/theme/white/talk-app.svg"\r
                     icon.color: "transparent"\r
@@ -289,6 +302,7 @@ Window {
                     Layout.preferredWidth: (trayWindowHeaderBackground.height)\r
                     Layout.preferredHeight: (trayWindowHeaderBackground.height)\r
                     flat: true\r
+                    visible: false\r
 \r
                     icon.source: "qrc:///client/theme/white/more-apps.svg"\r
                     icon.color: "transparent"\r
index 39df7d1677f87091c321add3945e6b33ba5a2bf9..d0c5f727f7dbbf3e1dbdc84229b5efa61ae90ab3 100644 (file)
@@ -103,7 +103,8 @@ bool Capabilities::isValid() const
     return !_capabilities.isEmpty();
 }
 
-bool Capabilities::hasActivities() const {
+bool Capabilities::hasActivities() const
+{
     return _capabilities.contains("activity");
 }