From 402515365ddd255217312b237e7e0cd4551b3097 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Thu, 15 Feb 2024 15:47:55 -0500
Subject: [PATCH] presence: follow daemon changes for presence indicator

Change-Id: Ie82a15da023ab97f133c8beadb8ddeb81b67666f
---
 daemon                                        |  2 +-
 .../commoncomponents/PresenceIndicator.qml    | 15 +++++
 src/app/contactadapter.cpp                    |  2 +-
 src/app/conversationlistmodelbase.cpp         |  5 +-
 .../components/ConversationAvatar.qml         |  1 +
 .../components/SmartListItemDelegate.qml      | 61 ++++++++-----------
 .../mainview/components/SwarmDetailsPanel.qml |  3 +-
 src/app/utilsadapter.cpp                      |  6 +-
 src/app/utilsadapter.h                        |  2 +-
 src/libclient/api/contact.h                   |  4 +-
 src/libclient/callbackshandler.cpp            |  3 +-
 src/libclient/callbackshandler.h              |  8 +--
 src/libclient/contactmodel.cpp                | 10 +--
 src/libclient/interfaces/pixmapmanipulatori.h |  6 +-
 src/libclient/pixmapmanipulatordefault.cpp    |  8 +--
 src/libclient/pixmapmanipulatordefault.h      |  4 +-
 .../qtwrapper/presencemanager_wrap.h          |  4 +-
 17 files changed, 73 insertions(+), 71 deletions(-)

diff --git a/daemon b/daemon
index 09ec8e6f4..842128f09 160000
--- a/daemon
+++ b/daemon
@@ -1 +1 @@
-Subproject commit 09ec8e6f43ea5c68742bffb5e40ece15fa687c46
+Subproject commit 842128f09bf0f1259602de70604285e8a2a427f1
diff --git a/src/app/commoncomponents/PresenceIndicator.qml b/src/app/commoncomponents/PresenceIndicator.qml
index 7d82f6232..b5663728e 100644
--- a/src/app/commoncomponents/PresenceIndicator.qml
+++ b/src/app/commoncomponents/PresenceIndicator.qml
@@ -29,6 +29,17 @@ Rectangle {
     property int status: Account.Status.REGISTERED
     property int size: 15
 
+    MaterialToolTip {
+        visible: text !== "" && hoverHandler.hovered
+        delay: Qt.styleHints.mousePressAndHoldInterval
+        text: status === 2 ? qsTr("Connected") : status === 1 ? qsTr("Available") : ""
+    }
+
+    HoverHandler {
+        id: hoverHandler
+        target: parent
+    }
+
     width: size
     height: size
     radius: size * 0.5
@@ -41,6 +52,10 @@ Rectangle {
             return JamiTheme.presenceGreen;
         else if (status === Account.Status.TRYING)
             return JamiTheme.unPresenceOrange;
+        else if (status === 2)
+            return JamiTheme.presenceGreen;
+        else if (status === 1)
+            return JamiTheme.unPresenceOrange;
         return JamiTheme.notificationRed;
     }
 }
diff --git a/src/app/contactadapter.cpp b/src/app/contactadapter.cpp
index b2e6f6b71..f9067e1d3 100644
--- a/src/app/contactadapter.cpp
+++ b/src/app/contactadapter.cpp
@@ -81,7 +81,7 @@ ContactAdapter::getContactSelectableModel(int type)
     }
     case SmartListModel::Type::CONFERENCE:
         selectableProxyModel_->setPredicate([](const QModelIndex& index, const QRegularExpression&) {
-            return index.data(Role::Presence).toBool();
+            return index.data(Role::Presence).toInt();
         });
         break;
     case SmartListModel::Type::TRANSFER:
diff --git a/src/app/conversationlistmodelbase.cpp b/src/app/conversationlistmodelbase.cpp
index 3ebbc0da7..03f93a4fb 100644
--- a/src/app/conversationlistmodelbase.cpp
+++ b/src/app/conversationlistmodelbase.cpp
@@ -176,10 +176,9 @@ ConversationListModelBase::dataForItem(item_t item, int role) const
             try {
                 auto& accInfo = lrcInstance_->getAccountInfo(accountId_);
                 if (peerUri == accInfo.profileInfo.uri)
-                    return true; // Self account
+                    return 2; // Self account
                 auto contact = accInfo.contactModel->getContact(peerUri);
-                if (contact.isPresent)
-                    return true;
+                return contact.presence;
             } catch (const std::exception&) {
             }
         return false;
diff --git a/src/app/mainview/components/ConversationAvatar.qml b/src/app/mainview/components/ConversationAvatar.qml
index d5f75b489..a07a7fe8c 100644
--- a/src/app/mainview/components/ConversationAvatar.qml
+++ b/src/app/mainview/components/ConversationAvatar.qml
@@ -24,6 +24,7 @@ Item {
     id: root
 
     property alias imageId: avatar.imageId
+    property alias presenceStatus: avatar.presenceStatus
     property alias showPresenceIndicator: avatar.showPresenceIndicator
     property alias animationMode: animation.mode
 
diff --git a/src/app/mainview/components/SmartListItemDelegate.qml b/src/app/mainview/components/SmartListItemDelegate.qml
index 1c98b14b8..a3d801942 100644
--- a/src/app/mainview/components/SmartListItemDelegate.qml
+++ b/src/app/mainview/components/SmartListItemDelegate.qml
@@ -21,12 +21,10 @@ import QtQuick
 import QtQuick.Controls
 import QtQuick.Layouts
 import Qt5Compat.GraphicalEffects
-
 import net.jami.Adapters 1.1
 import net.jami.Constants 1.1
 import net.jami.Enums 1.1
 import net.jami.Models 1.1
-
 import "../../commoncomponents"
 
 ItemDelegate {
@@ -40,9 +38,7 @@ ItemDelegate {
 
     highlighted: ListView.isCurrentItem
     property bool interactive: true
-    property string lastInteractionDate: LastInteractionTimeStamp === undefined
-                                         ? ""
-                                         : LastInteractionTimeStamp
+    property string lastInteractionDate: LastInteractionTimeStamp === undefined ? "" : LastInteractionTimeStamp
 
     property string lastInteractionFormattedDate: MessagesAdapter.getBestFormattedDate(lastInteractionDate)
 
@@ -51,25 +47,25 @@ ItemDelegate {
 
     Connections {
         target: PositionManager
-        function onPositionShareConvIdsCountChanged () {
-            root.showSharePositionIndicator = PositionManager.isPositionSharedToConv(accountId, UID)
+        function onPositionShareConvIdsCountChanged() {
+            root.showSharePositionIndicator = PositionManager.isPositionSharedToConv(accountId, UID);
         }
-        function onSharingUrisCountChanged () {
-            root.showSharedPositionIndicator = PositionManager.isConvSharingPosition(accountId, UID)
+        function onSharingUrisCountChanged() {
+            root.showSharedPositionIndicator = PositionManager.isConvSharingPosition(accountId, UID);
         }
     }
 
     Connections {
         target: MessagesAdapter
         function onTimestampUpdated() {
-            lastInteractionFormattedDate = MessagesAdapter.getBestFormattedDate(lastInteractionDate)
+            lastInteractionFormattedDate = MessagesAdapter.getBestFormattedDate(lastInteractionDate);
         }
     }
 
     Component.onCompleted: {
         // Store to avoid undefined at the end
-        root.accountId = Qt.binding(() => CurrentAccount.id)
-        root.convId = UID
+        root.accountId = Qt.binding(() => CurrentAccount.id);
+        root.convId = UID;
     }
 
     RowLayout {
@@ -82,6 +78,7 @@ ItemDelegate {
             id: avatar
 
             imageId: UID
+            presenceStatus: Presence
             showPresenceIndicator: Presence !== undefined ? Presence : false
 
             Layout.preferredWidth: JamiTheme.smartListAvatarSize
@@ -111,7 +108,6 @@ ItemDelegate {
                     source: JamiResources.check_black_24dp_svg
                 }
             }
-
         }
 
         ColumnLayout {
@@ -133,10 +129,7 @@ ItemDelegate {
                 color: JamiTheme.textColor
             }
             RowLayout {
-                visible: ContactType !== Profile.Type.TEMPORARY
-                         && !IsBanned
-                         && lastInteractionFormattedDate !== undefined
-                         && interactive
+                visible: ContactType !== Profile.Type.TEMPORARY && !IsBanned && lastInteractionFormattedDate !== undefined && interactive
                 Layout.fillWidth: true
                 Layout.minimumHeight: 20
                 Layout.alignment: Qt.AlignTop
@@ -157,9 +150,7 @@ ItemDelegate {
                     Layout.fillWidth: true
                     Layout.alignment: Qt.AlignVCenter
                     horizontalAlignment: Text.AlignLeft
-                    text: Draft ?
-                              Draft :
-                              (LastInteraction === undefined ? "" : LastInteraction)
+                    text: Draft ? Draft : (LastInteraction === undefined ? "" : LastInteraction)
                     textFormat: TextEdit.PlainText
                     font.pointSize: JamiTheme.smallFontSize
                     font.weight: UnreadMessagesCount ? Font.Normal : Font.Light
@@ -222,7 +213,7 @@ ItemDelegate {
             Text {
                 id: callStatusText
 
-                visible : text
+                visible: text
                 Layout.minimumHeight: 20
                 Layout.alignment: Qt.AlignRight
                 text: InCall ? UtilsAdapter.getCallStatusStr(CallState) : ""
@@ -247,51 +238,47 @@ ItemDelegate {
             }
         }
 
-
-
-
-
         Accessible.role: Accessible.Button
-        Accessible.name: Title === undefined? "" : Title
-        Accessible.description: LastInteraction === undefined? "" : LastInteraction
+        Accessible.name: Title === undefined ? "" : Title
+        Accessible.description: LastInteraction === undefined ? "" : LastInteraction
     }
 
     background: Rectangle {
         color: {
             if (root.pressed || root.highlighted)
-                return JamiTheme.smartListSelectedColor
+                return JamiTheme.smartListSelectedColor;
             else if (root.hovered)
-                return JamiTheme.smartListHoveredColor
+                return JamiTheme.smartListHoveredColor;
             else
-                return "transparent"
+                return "transparent";
         }
     }
 
     onClicked: {
         if (!interactive) {
-            highlighted = !highlighted
+            highlighted = !highlighted;
             return;
         }
-        ListView.view.model.select(index)
+        ListView.view.model.select(index);
     }
     onDoubleClicked: {
         if (!interactive)
             return;
-        ListView.view.model.select(index)
+        ListView.view.model.select(index);
         if (CurrentConversation.isSwarm && !CurrentConversation.isCoreDialog && !UtilsAdapter.getAppValue(Settings.EnableExperimentalSwarm))
             return; // For now disable calls for swarm with multiple participants
         if (LRCInstance.currentAccountType === Profile.Type.SIP || !CurrentAccount.videoEnabled_Video)
-            CallAdapter.placeAudioOnlyCall()
+            CallAdapter.placeAudioOnlyCall();
         else {
             if (!CurrentConversation.readOnly) {
-                CallAdapter.placeCall()
+                CallAdapter.placeCall();
             }
         }
     }
     onPressAndHold: {
         if (!interactive)
             return;
-        ListView.view.openContextMenuAt(pressX, pressY, root)
+        ListView.view.openContextMenuAt(pressX, pressY, root);
     }
 
     MouseArea {
@@ -299,7 +286,7 @@ ItemDelegate {
         enabled: interactive
         acceptedButtons: Qt.RightButton
         onClicked: function (mouse) {
-            root.ListView.view.openContextMenuAt(mouse.x, mouse.y, root)
+            root.ListView.view.openContextMenuAt(mouse.x, mouse.y, root);
         }
     }
 }
diff --git a/src/app/mainview/components/SwarmDetailsPanel.qml b/src/app/mainview/components/SwarmDetailsPanel.qml
index ef439fe16..7c2521db6 100644
--- a/src/app/mainview/components/SwarmDetailsPanel.qml
+++ b/src/app/mainview/components/SwarmDetailsPanel.qml
@@ -624,7 +624,8 @@ Rectangle {
                             opacity: (MemberRole === Member.Role.INVITED || MemberRole === Member.Role.BANNED) ? 0.5 : 1
 
                             imageId: CurrentAccount.uri === MemberUri ? CurrentAccount.id : MemberUri
-                            showPresenceIndicator: UtilsAdapter.getContactPresence(CurrentAccount.id, MemberUri)
+                            presenceStatus: UtilsAdapter.getContactPresence(CurrentAccount.id, MemberUri)
+                            showPresenceIndicator: presenceStatus > 0
                             mode: CurrentAccount.uri === MemberUri ? Avatar.Mode.Account : Avatar.Mode.Contact
                         }
 
diff --git a/src/app/utilsadapter.cpp b/src/app/utilsadapter.cpp
index 70f559fa8..882474ecc 100644
--- a/src/app/utilsadapter.cpp
+++ b/src/app/utilsadapter.cpp
@@ -610,17 +610,17 @@ UtilsAdapter::setTempCreationImageFromImage(const QImage& image, const QString&
     }
 }
 
-bool
+int
 UtilsAdapter::getContactPresence(const QString& accountId, const QString& uri)
 {
     try {
         if (lrcInstance_->getAccountInfo(accountId).profileInfo.uri == uri)
             return true; // It's the same account
         auto info = lrcInstance_->getAccountInfo(accountId).contactModel->getContact(uri);
-        return info.isPresent;
+        return info.presence;
     } catch (...) {
     }
-    return false;
+    return 0;
 }
 
 QString
diff --git a/src/app/utilsadapter.h b/src/app/utilsadapter.h
index d4e1aa920..8616d847f 100644
--- a/src/app/utilsadapter.h
+++ b/src/app/utilsadapter.h
@@ -150,7 +150,7 @@ public:
                                                    const QString& imageId = "temp");
 
     // For Swarm details page
-    Q_INVOKABLE bool getContactPresence(const QString& accountId, const QString& uri);
+    Q_INVOKABLE int getContactPresence(const QString& accountId, const QString& uri);
     Q_INVOKABLE QString getContactBestName(const QString& accountId, const QString& uri);
     Q_INVOKABLE lrc::api::member::Role getParticipantRole(const QString& accountId,
                                                           const QString& convId,
diff --git a/src/libclient/api/contact.h b/src/libclient/api/contact.h
index bbb1935e5..008e3c4fd 100644
--- a/src/libclient/api/contact.h
+++ b/src/libclient/api/contact.h
@@ -32,7 +32,7 @@ namespace contact {
  * @var profileInfo
  * @var registeredName
  * @var isTrusted
- * @var isPresent
+ * @var presence
  * @var isBanned
  */
 struct Info
@@ -40,7 +40,7 @@ struct Info
     profile::Info profileInfo;
     QString registeredName;
     bool isTrusted = false;
-    bool isPresent = false;
+    int presence = 0;
     bool isBanned = false;
     QString conversationId {};
 };
diff --git a/src/libclient/callbackshandler.cpp b/src/libclient/callbackshandler.cpp
index 685dae9bb..06c7df295 100644
--- a/src/libclient/callbackshandler.cpp
+++ b/src/libclient/callbackshandler.cpp
@@ -408,10 +408,9 @@ CallbacksHandler::slotNewAccountMessage(const QString& accountId,
 void
 CallbacksHandler::slotNewBuddySubscription(const QString& accountId,
                                            const QString& uri,
-                                           bool status,
+                                           int status,
                                            const QString& message)
 {
-    Q_UNUSED(status)
     Q_UNUSED(message)
     Q_EMIT newBuddySubscription(accountId, uri, status);
 }
diff --git a/src/libclient/callbackshandler.h b/src/libclient/callbackshandler.h
index d92c70dce..78c73a639 100644
--- a/src/libclient/callbackshandler.h
+++ b/src/libclient/callbackshandler.h
@@ -66,9 +66,9 @@ Q_SIGNALS:
      * Connect this signal to get information when a peer is online.
      * @param accountId  related account.
      * @param contactUri the peer.
-     * @param present if the peer is online.
+     * @param presence if the peer is online.
      */
-    void newBuddySubscription(const QString& accountId, const QString& contactUri, bool present);
+    void newBuddySubscription(const QString& accountId, const QString& contactUri, int presence);
     /**
      * Connect this signal to get information when peer discovery changes.
      * @param contactUri the peer.
@@ -407,12 +407,12 @@ private Q_SLOTS:
      * Emit newBuddySubscription
      * @param accountId
      * @param contactUri
-     * @param status if the contact is present
+     * @param status if the contact is present (1=dht presence, 0=offline, 2=connected)
      * @param message unused for now
      */
     void slotNewBuddySubscription(const QString& accountId,
                                   const QString& contactUri,
-                                  bool status,
+                                  int status,
                                   const QString& message);
     /**
      * Emit contactAdded
diff --git a/src/libclient/contactmodel.cpp b/src/libclient/contactmodel.cpp
index 9771b2dd0..0d210492e 100644
--- a/src/libclient/contactmodel.cpp
+++ b/src/libclient/contactmodel.cpp
@@ -130,7 +130,7 @@ public Q_SLOTS:
      * @param contactUri
      * @param status
      */
-    void slotNewBuddySubscription(const QString& accountId, const QString& uri, bool status);
+    void slotNewBuddySubscription(const QString& accountId, const QString& uri, int status);
 
     /**
      * Listen CallbacksHandler when a contact is added
@@ -778,7 +778,7 @@ ContactModelPimpl::fillWithJamiContacts()
                     std::lock_guard<std::mutex> lk(contactsMtx_);
                     auto it = contacts.find(uri);
                     if (it != contacts.end()) {
-                        it->isPresent = key == "Online";
+                        it->presence = key == "Online" ? 1 : 0;
                         linked.modelUpdated(uri);
                     }
                 }
@@ -792,7 +792,7 @@ ContactModelPimpl::fillWithJamiContacts()
 void
 ContactModelPimpl::slotNewBuddySubscription(const QString& accountId,
                                             const QString& contactUri,
-                                            bool status)
+                                            int state)
 {
     if (accountId != linked.owner.id)
         return;
@@ -800,7 +800,7 @@ ContactModelPimpl::slotNewBuddySubscription(const QString& accountId,
         std::lock_guard<std::mutex> lk(contactsMtx_);
         auto it = contacts.find(contactUri);
         if (it != contacts.end()) {
-            it->isPresent = status;
+            it->presence = state;
         } else
             return;
     }
@@ -966,7 +966,7 @@ ContactModelPimpl::addToContacts(const QString& contactUri,
     if (iter != contacts.end()) {
         auto info = iter.value();
         contactInfo.registeredName = info.registeredName;
-        contactInfo.isPresent = info.isPresent;
+        contactInfo.presence = info.presence;
         iter.value() = contactInfo;
     } else
         contacts.insert(iter, contactInfo.profileInfo.uri, contactInfo);
diff --git a/src/libclient/interfaces/pixmapmanipulatori.h b/src/libclient/interfaces/pixmapmanipulatori.h
index f9f3101cc..a6d7ab100 100644
--- a/src/libclient/interfaces/pixmapmanipulatori.h
+++ b/src/libclient/interfaces/pixmapmanipulatori.h
@@ -72,18 +72,18 @@ public:
     virtual QVariant conversationPhoto(const lrc::api::conversation::Info& conversation,
                                        const lrc::api::account::Info& accountInfo,
                                        const QSize& size,
-                                       bool displayPresence = true)
+                                       int presence = 0)
     {
         Q_UNUSED(conversation);
         Q_UNUSED(accountInfo);
         Q_UNUSED(size);
-        Q_UNUSED(displayPresence);
+        Q_UNUSED(presence);
         return {};
     }
     virtual QVariant numberCategoryIcon(const QVariant& p,
                                         const QSize& size,
                                         bool displayPresence = false,
-                                        bool isPresent = false)
+                                        int presence = 0)
         = 0;
     virtual QByteArray toByteArray(const QVariant& pxm) = 0;
     virtual QVariant personPhoto(const QByteArray& data, const QString& type = "PNG") = 0;
diff --git a/src/libclient/pixmapmanipulatordefault.cpp b/src/libclient/pixmapmanipulatordefault.cpp
index 43f13f3ae..2df328c72 100644
--- a/src/libclient/pixmapmanipulatordefault.cpp
+++ b/src/libclient/pixmapmanipulatordefault.cpp
@@ -32,12 +32,12 @@ QVariant
 PixmapManipulatorDefault::numberCategoryIcon(const QVariant& p,
                                              const QSize& size,
                                              bool displayPresence,
-                                             bool isPresent)
+                                             int presence)
 {
     Q_UNUSED(p)
     Q_UNUSED(size)
     Q_UNUSED(displayPresence)
-    Q_UNUSED(isPresent)
+    Q_UNUSED(presence)
     return QVariant();
 }
 
@@ -45,12 +45,12 @@ QVariant
 PixmapManipulatorDefault::conversationPhoto(const lrc::api::conversation::Info& conversation,
                                             const lrc::api::account::Info& accountInfo,
                                             const QSize& size,
-                                            bool displayPresence)
+                                            int presence)
 {
     Q_UNUSED(conversation)
     Q_UNUSED(accountInfo)
     Q_UNUSED(size)
-    Q_UNUSED(displayPresence)
+    Q_UNUSED(presence)
     return QVariant();
 }
 
diff --git a/src/libclient/pixmapmanipulatordefault.h b/src/libclient/pixmapmanipulatordefault.h
index 5a93b204d..3e6e8fef3 100644
--- a/src/libclient/pixmapmanipulatordefault.h
+++ b/src/libclient/pixmapmanipulatordefault.h
@@ -29,11 +29,11 @@ public:
     QVariant conversationPhoto(const lrc::api::conversation::Info& conversation,
                                const lrc::api::account::Info& accountInfo,
                                const QSize& size,
-                               bool displayPresence = true) override;
+                               int presence = 0) override;
     QVariant numberCategoryIcon(const QVariant& p,
                                 const QSize& size,
                                 bool displayPresence = false,
-                                bool isPresent = false) override;
+                                int presence = 0) override;
     QByteArray toByteArray(const QVariant& pxm) override;
     QVariant personPhoto(const QByteArray& data, const QString& type = "PNG") override;
     QVariant decorationRole(const QModelIndex& index) override;
diff --git a/src/libclient/qtwrapper/presencemanager_wrap.h b/src/libclient/qtwrapper/presencemanager_wrap.h
index 9acb379c3..253cecc07 100644
--- a/src/libclient/qtwrapper/presencemanager_wrap.h
+++ b/src/libclient/qtwrapper/presencemanager_wrap.h
@@ -60,7 +60,7 @@ public:
                exportable_callback<PresenceSignal::NewBuddyNotification>(
                    [this](const std::string& accountID,
                           const std::string& buddyUri,
-                          bool status,
+                          int status,
                           const std::string& lineStatus) {
                        Q_EMIT this->newBuddyNotification(QString(accountID.c_str()),
                                                          QString(buddyUri.c_str()),
@@ -126,7 +126,7 @@ Q_SIGNALS: // SIGNALS
     void serverError(const QString& accountID, const QString& error, const QString& msg);
     void newBuddyNotification(const QString& accountID,
                               const QString& buddyUri,
-                              bool status,
+                              int status,
                               const QString& lineStatus);
     void subscriptionStateChanged(const QString& accountID, const QString& buddyUri, bool state);
 };
-- 
GitLab