Add 'Reply' as activity link instead of changing the 'View chat' link.
authorCamila <hello@camila.codes>
Tue, 29 Mar 2022 11:33:06 +0000 (13:33 +0200)
committerCamila <hello@camila.codes>
Wed, 6 Apr 2022 08:38:00 +0000 (10:38 +0200)
- Align 'Reply' button.
- Do not display 'View chat' as a link: the 'View chat' action is active when
the user clickcs on the notification item in the tray window.
- Convert the QByteArray verb value to String.
- Handle logic to toggle the reply textfield in the QML code.

Signed-off-by: Camila <hello@camila.codes>
src/gui/tray/ActivityItem.qml
src/gui/tray/ActivityItemActions.qml
src/gui/tray/ActivityItemContent.qml
src/gui/tray/TalkReplyTextField.qml
src/gui/tray/activitydata.h
src/gui/tray/activitylistmodel.cpp
src/gui/tray/activitylistmodel.h
src/gui/tray/notificationhandler.cpp

index 46c353f945e7fb236762022769fcf275cf9d6294..3003ae667d7839cf0f6849eeb87d82d38e769920 100644 (file)
@@ -12,8 +12,9 @@ MouseArea {
 
     property bool isFileActivityList: false
 
-    property bool isChatActivity: model.objectType === "chat" || model.objectType === "room" || model.objectType === "call"
-    property bool isTalkReplyPossible: model.conversationToken !== ""
+    readonly property bool isChatActivity: model.objectType === "chat" || model.objectType === "room" || model.objectType === "call"
+    readonly property bool isTalkReplyPossible: model.conversationToken !== ""
+    property bool isTalkReplyOptionVisible: model.messageSent !== ""
 
     signal fileActivityButtonClicked(string absolutePath)
 
@@ -26,6 +27,10 @@ MouseArea {
     Accessible.name: (model.path !== "" && model.displayPath !== "") ? qsTr("Open %1 locally").arg(model.displayPath) : model.message
     Accessible.onPressAction: root.clicked()
 
+    function showReplyOptions(activityIndex) {
+        isTalkReplyOptionVisible = !isTalkReplyOptionVisible
+    }
+
     Rectangle {
         id: activityHover
         anchors.fill: parent
@@ -73,11 +78,11 @@ MouseArea {
         ActivityItemActions {
             id: activityActions
 
-            visible: !root.isFileActivityList && model.linksForActionButtons.length > 0 && !model.displayReplyOption
+            visible: !root.isFileActivityList && model.linksForActionButtons.length > 0 && !isTalkReplyOptionVisible
 
             Layout.preferredHeight: Style.trayWindowHeaderHeight * 0.85
             Layout.fillWidth: true
-            Layout.leftMargin: 40
+            Layout.leftMargin: 60
             Layout.bottomMargin: model.links.length > 1 ? 5 : 0
 
             displayActions: model.displayActions
index 3f14fbd4d42b0365adbc0a888c6f3ec91f7aa991..cdf7ff70f94a3a7320d01cdb8054761af9874ee3 100644 (file)
@@ -31,7 +31,12 @@ RowLayout {
         ActivityActionButton {
             id: activityActionButton
 
-            readonly property bool primary: model.index === 0 && model.modelData.verb !== "DELETE"
+            readonly property string verb: model.modelData.verb
+            readonly property bool primary: model.index === 0 && verb !== "DELETE"
+            readonly property bool isViewChatlink: verb === "WEB"
+            readonly property bool isTalkReplyButton: verb === "REPLY"
+
+            visible: !isViewChatlink
 
             Layout.minimumWidth: primary ? Style.activityItemActionPrimaryButtonMinWidth : Style.activityItemActionSecondaryButtonMinWidth
             Layout.preferredHeight: primary ? parent.height : parent.height * 0.3
@@ -48,7 +53,7 @@ RowLayout {
 
             bold: primary
 
-            onClicked: root.triggerAction(model.index)
+            onClicked: !isTalkReplyButton? root.triggerAction(model.index) : showReplyOptions(model.index)
         }
     }
 
index f18244e5615cce84f8ec11578566f02e8b227164..7b49e07bdce3c07f276e17c3001660ae1839f92a 100644 (file)
@@ -131,10 +131,22 @@ RowLayout {
             color: Style.ncSecondaryTextColor
         }
 
+        Label {
+            id: talkReplyMessageSent
+            text: root.activityData.messageSent
+            height: (text === "") ? 0 : implicitHeight
+            width: parent.width
+            elide: Text.ElideRight
+            wrapMode: Text.Wrap
+            maximumLineCount: 2
+            font.pixelSize: Style.topLinePixelSize
+            color: Style.ncSecondaryTextColor
+        }
+
         Loader {
             id: talkReplyTextFieldLoader
-            active: isChatActivity && isTalkReplyPossible && model.displayReplyOption
-            visible: model.displayReplyOption
+            active: isChatActivity && isTalkReplyPossible
+            visible: isTalkReplyOptionVisible
 
             anchors.top: activityTextDateTime.bottom
             anchors.topMargin: 10
index 610e28af1e5d45cc9656eea99a7435ddfd411fab..a53c88099a0c5ad59f9e3ff8942a3581dd5e4bd4 100644 (file)
@@ -13,25 +13,18 @@ Item {
         }
 
         UserModel.currentUser.sendReplyMessage(model.index, model.conversationToken, replyMessageTextField.text, model.messageId);
-    }
-
-    Text {
-        id: replyMessageSent
-        text: model.messageSent
-        font.pixelSize: Style.topLinePixelSize
-        color: Style.menuBorder
-        visible: model.messageSent !== ""
+        replyMessageTextField.visible = false
     }
 
     TextField {
         id: replyMessageTextField
+        visible: model.messageSent === ""
 
         // TODO use Layout to manage width/height. The Layout.minimunWidth does not apply to the width set.
         height: 38
         width: 250
 
         onAccepted: root.sendReplyMessage()
-        visible: replyMessageSent.text === ""
 
         topPadding: 4
 
index 166832f4f3e506c09994ba3c984c38f5a4312eef..9c035e2a32216f45c9f98d05c3b7237fe78474f6 100644 (file)
@@ -113,7 +113,6 @@ public:
         QString conversationToken;
         QString messageId;
         QString messageSent;
-        bool displayReplyOption = false;
     };
 
     Type _type;
index a34c2464b9f10a08ce9b82c5f2399e10fa3bce20..20badd5dcab1138f51303921c4c738bea9fee6b5 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -80,7 +80,6 @@ QHash<int, QByteArray> ActivityListModel::roleNames() const
     roles[TalkNotificationConversationTokenRole] = "conversationToken";
     roles[TalkNotificationMessageIdRole] = "messageId";
     roles[TalkNotificationMessageSentRole] = "messageSent";
-    roles[TalkNotificationDisplayReplyOptionRole] = "displayReplyOption";
 
     return roles;
 }
@@ -333,8 +332,6 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
         return a._talkNotificationData.messageId;
     case TalkNotificationMessageSentRole:
         return replyMessageSent(a);
-    case TalkNotificationDisplayReplyOptionRole:
-        return displayReplyOption(a);
     default:
         return QVariant();
     }
@@ -614,12 +611,6 @@ void ActivityListModel::slotTriggerAction(const int activityIndex, const int act
 
     const auto action = activity._links[actionIndex];
 
-    // TODO this will change with https://github.com/nextcloud/desktop/issues/4159
-    if (action._verb == "WEB" && action._label == tr("View chat")) {
-        setDisplayReplyOption(activityIndex);
-        return;
-    }
-
     if (action._verb == "WEB") {
         Utility::openBrowser(QUrl(action._link));
         return;
@@ -672,7 +663,7 @@ QVariantList ActivityListModel::convertLinksToActionButtons(const Activity &acti
     }
 
     if (static_cast<quint32>(activity._links.size()) > maxActionButtons()) {
-        customList << ActivityListModel::convertLinkToActionButton(activity, activity._links.first());
+        customList << ActivityListModel::convertLinkToActionButton(activity._links.first());
         return customList;
     }
 
@@ -680,20 +671,18 @@ QVariantList ActivityListModel::convertLinksToActionButtons(const Activity &acti
         if (activityLink._verb == QStringLiteral("DELETE")
             || (activity._objectType == QStringLiteral("chat") || activity._objectType == QStringLiteral("call")
                 || activity._objectType == QStringLiteral("room"))) {
-            customList << ActivityListModel::convertLinkToActionButton(activity, activityLink);
+            customList << ActivityListModel::convertLinkToActionButton(activityLink);
         }
     }
 
     return customList;
 }
 
-QVariant ActivityListModel::convertLinkToActionButton(const OCC::Activity &activity, const OCC::ActivityLink &activityLink)
+QVariant ActivityListModel::convertLinkToActionButton(const OCC::ActivityLink &activityLink)
 {
     auto activityLinkCopy = activityLink;
 
-    const auto isReplyIconApplicable = activityLink._verb == QStringLiteral("WEB")
-        && (activity._objectType == QStringLiteral("chat") || activity._objectType == QStringLiteral("call")
-            || activity._objectType == QStringLiteral("room"));
+    const auto isReplyIconApplicable = activityLink._verb == QStringLiteral("REPLY");
 
     const QString replyButtonPath = QStringLiteral("image://svgimage-custom-color/reply.svg");
 
@@ -704,14 +693,8 @@ QVariant ActivityListModel::convertLinkToActionButton(const OCC::Activity &activ
             QString(replyButtonPath + "/" + OCC::Theme::instance()->wizardHeaderTitleColor().name());
     }
 
-    const auto isReplyLabelApplicable = activityLink._verb == QStringLiteral("WEB")
-        && (activity._objectType == QStringLiteral("chat")
-        || (activity._objectType != QStringLiteral("room") && activity._objectType != QStringLiteral("call")));
-
     if (activityLink._verb == QStringLiteral("DELETE")) {
         activityLinkCopy._label = QObject::tr("Mark as read");
-    } else if (isReplyLabelApplicable) {
-        activityLinkCopy._label = QObject::tr("Reply");
     }
 
     return QVariant::fromValue(activityLinkCopy);
@@ -836,15 +819,4 @@ QString ActivityListModel::replyMessageSent(const Activity &activity) const
 {
     return activity._talkNotificationData.messageSent;
 }
-
-void ActivityListModel::setDisplayReplyOption(const int activityIndex)
-{
-    _finalList[activityIndex]._talkNotificationData.displayReplyOption = true;
-    emit dataChanged(index(activityIndex, 0), index(activityIndex, 0), {ActivityListModel::TalkNotificationDisplayReplyOptionRole});
-}
-
-bool ActivityListModel::displayReplyOption(const Activity &activity) const
-{
-    return activity._talkNotificationData.displayReplyOption;
-}
 }
index c0698a9e6ba78a43056fe5ad8d79ec9bec685c8c..1a421861e3c14ba5b5adaf0111d9debe71419234 100644 (file)
@@ -71,7 +71,6 @@ public:
         TalkNotificationConversationTokenRole,
         TalkNotificationMessageIdRole,
         TalkNotificationMessageSentRole,
-        TalkNotificationDisplayReplyOptionRole,
     };
     Q_ENUM(DataRole)
 
@@ -108,7 +107,6 @@ public:
 
     void setReplyMessageSent(const int activityIndex, const QString &message);
     QString replyMessageSent(const Activity &activity) const;
-    bool displayReplyOption(const Activity &activity) const;
 
 public slots:
     void slotRefreshActivity();
@@ -143,14 +141,12 @@ protected:
 private:
     static QVariantList convertLinksToMenuEntries(const Activity &activity);
     static QVariantList convertLinksToActionButtons(const Activity &activity);
-    static QVariant convertLinkToActionButton(const Activity &activity, const ActivityLink &activityLink);
+    static QVariant convertLinkToActionButton(const ActivityLink &activityLink);
     void combineActivityLists();
     bool canFetchActivities() const;
 
     void ingestActivities(const QJsonArray &activities);
 
-    void setDisplayReplyOption(const int activityIndex);
-
     ActivityList _activityLists;
     ActivityList _syncFileItemLists;
     ActivityList _notificationLists;
@@ -175,7 +171,7 @@ private:
     bool _doneFetching = false;
     bool _hideOldActivities = true;
 
-    static constexpr quint32 MaxActionButtons = 2;
+    static constexpr quint32 MaxActionButtons = 3;
 };
 }
 
index 0e79d13ad9aa0149565388baa57ca9a111cd4161..9246486e84a223ff869f3b6f5f29041370160d88 100644 (file)
@@ -98,9 +98,9 @@ void ServerNotificationHandler::slotNotificationsReceived(const QJsonDocument &j
         a._id = json.value("notification_id").toInt();
 
         // 2 cases to consider:
-        // - server == 24 & has Talk: notification type chat/call contains conversationToken/messageId in object_type
-        // - server < 24 & has Talk: notification type chat/call contains _only_ the conversationToken in object_type
-        if (a._objectType == "chat" || a._objectType == "call") {
+        // 1. server == 24 & has Talk: object_type is chat/call/room & object_id contains conversationToken/messageId
+        // 2. server < 24 & has Talk: object_type is chat/call/room & object_id contains _only_ conversationToken
+        if (a._objectType == "chat" || a._objectType == "call" || a._objectType == "room") {
             const auto objectId = json.value("object_id").toString();
             const auto objectIdData = objectId.split("/");
             a._talkNotificationData.conversationToken = objectIdData.first();
@@ -109,6 +109,14 @@ void ServerNotificationHandler::slotNotificationsReceived(const QJsonDocument &j
             } else {
                 qCInfo(lcServerNotification) << "Replying directly to Talk conversation" << a._talkNotificationData.conversationToken << "will not be possible because the notification doesn't contain the message ID.";
             }
+
+            ActivityLink al;
+            al._label = tr("Reply");
+            al._verb = "REPLY";
+            al._primary = true;
+            a._links.insert(0, al);
+
+            list.append(a);
         } 
 
         a._status = 0;