From 08236cf5e74eb3d1ec30a124a9c568c3bebc8938 Mon Sep 17 00:00:00 2001
From: ababi <albert.babi@savoirfairelinux.com>
Date: Thu, 17 Dec 2020 12:40:08 +0100
Subject: [PATCH] recording: show message when peer starts / stops recording
 the call

Gitlab: #160

Change-Id: Id8125c56145cc661941f445c2f52b73fd983c97d
---
 src/calladapter.cpp                           | 23 ++++++
 src/calladapter.h                             |  2 +
 src/constant/JamiStrings.qml                  |  5 ++
 src/mainview/components/CallOverlay.qml       | 74 ++++++++++++++-----
 .../components/CallOverlayButtonGroup.qml     |  2 +-
 .../components/CallViewContextMenu.qml        |  5 +-
 src/mainview/components/VideoCallPage.qml     |  4 +
 7 files changed, 94 insertions(+), 21 deletions(-)

diff --git a/src/calladapter.cpp b/src/calladapter.cpp
index c3b27152a..9acffcc29 100644
--- a/src/calladapter.cpp
+++ b/src/calladapter.cpp
@@ -469,6 +469,29 @@ CallAdapter::connectCallModel(const QString& accountId)
 
             emit LRCInstance::instance().updateSmartList();
         });
+
+    remoteRecordingChangedConnection_ = QObject::connect(
+        accInfo.callModel.get(),
+        &lrc::api::NewCallModel::remoteRecordingChanged,
+        [this](const QString& callId, const QSet<QString>& peerRec, bool state) {
+            const auto currentCallId =
+                    LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
+            if (callId == currentCallId) {
+                const auto& accInfo = LRCInstance::getCurrentAccountInfo();
+                QStringList peers {};
+                for (const auto& uri: peerRec) {
+                    auto bestName = accInfo.contactModel->bestNameForContact(uri);
+                    if (!bestName.isEmpty()) {
+                        peers.append(bestName);
+                    }
+                }
+                if (!peers.isEmpty()) {
+                    emit remoteRecordingChanged(peers, true);
+                } else if (!state) {
+                    emit remoteRecordingChanged(peers, false);
+                }
+            }
+    });
 }
 
 void
diff --git a/src/calladapter.h b/src/calladapter.h
index f8767b721..6d1616849 100644
--- a/src/calladapter.h
+++ b/src/calladapter.h
@@ -96,6 +96,7 @@ signals:
                        bool isSIP,
                        bool isConferenceCall,
                        const QString& bestName);
+    void remoteRecordingChanged(const QStringList& peers, bool state);
 
 public slots:
     void slotShowIncomingCallView(const QString& accountId,
@@ -117,6 +118,7 @@ private:
     QMetaObject::Connection onParticipantsChangedConnection_;
     QMetaObject::Connection closeIncomingCallPageConnection_;
     QMetaObject::Connection appStateChangedConnection_;
+    QMetaObject::Connection remoteRecordingChangedConnection_;
 
     /*
      * For Call Overlay
diff --git a/src/constant/JamiStrings.qml b/src/constant/JamiStrings.qml
index af29f73b6..dbb213c0d 100644
--- a/src/constant/JamiStrings.qml
+++ b/src/constant/JamiStrings.qml
@@ -174,6 +174,11 @@ Item {
     property string name: qsTr("name")
     property string identifier: qsTr("Identifier")
 
+    // CallOverlay
+    property string isRecording: qsTr("is recording")
+    property string areRecording: qsTr("are recording")
+    property string peerStoppedRecording: qsTr("Peer stopped recording")
+
     // CallOverlayButtonGroup
     property string mute: qsTr("Mute")
     property string unmute: qsTr("Unmute")
diff --git a/src/mainview/components/CallOverlay.qml b/src/mainview/components/CallOverlay.qml
index c2956a4d0..84dc5bd9f 100644
--- a/src/mainview/components/CallOverlay.qml
+++ b/src/mainview/components/CallOverlay.qml
@@ -36,15 +36,17 @@ Rectangle {
     id: callOverlayRect
 
     property string timeText: "00:00"
-
-    signal overlayChatButtonClicked
+    property string remoteRecordingLabel: ""
 
     property var participantOverlays: []
     property var participantComponent: Qt.createComponent("ParticipantOverlay.qml")
 
-    function setRecording(isRecording) {
-        callViewContextMenu.isRecording = isRecording
-        recordingRect.visible = isRecording
+    signal overlayChatButtonClicked
+
+    function setRecording(localIsRecording) {
+        callViewContextMenu.localIsRecording = localIsRecording
+        recordingRect.visible = localIsRecording
+                || callViewContextMenu.peerIsRecording
     }
 
     function updateButtonStatus(isPaused, isAudioOnly, isAudioMuted, isVideoMuted,
@@ -52,12 +54,11 @@ Rectangle {
         callViewContextMenu.isSIP = isSIP
         callViewContextMenu.isPaused = isPaused
         callViewContextMenu.isAudioOnly = isAudioOnly
-        callViewContextMenu.isRecording = isRecording
+        callViewContextMenu.localIsRecording = isRecording
         recordingRect.visible = isRecording
         callOverlayButtonGroup.setButtonStatus(isPaused, isAudioOnly,
                                                isAudioMuted, isVideoMuted,
-                                               isRecording, isSIP,
-                                               isConferenceCall)
+                                               isSIP, isConferenceCall)
     }
 
     function updateMenu() {
@@ -91,7 +92,6 @@ Rectangle {
                 && pW >= distantRenderer.width - distantRenderer.getXOffset() * 2 - 1)
     }
 
-
     function handleParticipantsInfo(infos) {
         // TODO: in the future the conference layout should be entirely managed by the client
         videoCallOverlay.updateMenu()
@@ -185,7 +185,6 @@ Rectangle {
                 }
             }
         }
-
     }
 
     // x, y position does not need to be translated
@@ -196,6 +195,27 @@ Rectangle {
         callViewContextMenu.openMenu()
     }
 
+    function showRemoteRecording(peers, state) {
+        var label = ""
+        var i = 0
+        if (state) {
+            for (var p in peers) {
+                label += peers[p]
+                if (i !== (peers.length - 1))
+                    label += ", "
+                i += 1
+            }
+            label += " " + ((peers.length > 1)? JamiStrings.areRecording
+                                              : JamiStrings.isRecording)
+        }
+
+        remoteRecordingLabel = state? label : JamiStrings.peerStoppedRecording
+        callViewContextMenu.peerIsRecording = state
+        recordingRect.visible = callViewContextMenu.localIsRecording
+                || callViewContextMenu.peerIsRecording
+        callOverlayRectMouseArea.entered()
+    }
+
     anchors.fill: parent
 
     SipInputPanel {
@@ -212,13 +232,26 @@ Rectangle {
         onTriggered: {
             if (overlayUpperPartRect.state !== 'freezed') {
                 overlayUpperPartRect.state = 'freezed'
+                resetRecordingLabelTimer.restart()
             }
             if (callOverlayButtonGroup.state !== 'freezed') {
                 callOverlayButtonGroup.state = 'freezed'
+                resetRecordingLabelTimer.restart()
             }
         }
     }
 
+    // Timer to reset recording label text
+    Timer {
+        id: resetRecordingLabelTimer
+        interval: 1000
+        onTriggered: {
+            if (callOverlayButtonGroup.state === 'freezed'
+                    && !callViewContextMenu.peerIsRecording)
+                remoteRecordingLabel = ""
+        }
+    }
+
     Rectangle {
         id: overlayUpperPartRect
 
@@ -287,8 +320,13 @@ Rectangle {
                     id: textMetricsjamiBestNameText
                     font: jamiBestNameText.font
                     text: {
-                        if (videoCallPageRect)
-                            return videoCallPageRect.bestName
+                        if (videoCallPageRect) {
+                            if (remoteRecordingLabel === "") {
+                                return videoCallPageRect.bestName
+                            } else {
+                                return remoteRecordingLabel
+                            }
+                        }
                         return ""
                     }
                     elideWidth: overlayUpperPartRect.width / 3
@@ -299,8 +337,11 @@ Rectangle {
             Text {
                 id: callTimerText
                 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
-                Layout.preferredWidth: overlayUpperPartRect.width / 3
+                Layout.preferredWidth: 64
+                Layout.minimumWidth: 64
                 Layout.preferredHeight: 48
+                Layout.rightMargin: recordingRect.visible?
+                                        0 : JamiTheme.preferredMarginSize
                 font.pointSize: JamiTheme.textFontSize
                 horizontalAlignment: Text.AlignRight
                 verticalAlignment: Text.AlignVCenter
@@ -310,7 +351,7 @@ Rectangle {
                     id: textMetricscallTimerText
                     font: callTimerText.font
                     text: timeText
-                    elideWidth: overlayUpperPartRect.width / 3
+                    elideWidth: overlayUpperPartRect.width / 4
                     elide: Qt.ElideRight
                 }
             }
@@ -318,6 +359,7 @@ Rectangle {
             Rectangle {
                 id: recordingRect
                 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
+                Layout.rightMargin: JamiTheme.preferredMarginSize
                 height: 16
                 width: 16
                 radius: height / 2
@@ -330,10 +372,6 @@ Rectangle {
                     ColorAnimation { from: "transparent"; to: "red"; duration: 500 }
                 }
             }
-
-            Item {
-                width: 8
-            }
         }
 
         color: "transparent"
diff --git a/src/mainview/components/CallOverlayButtonGroup.qml b/src/mainview/components/CallOverlayButtonGroup.qml
index 6d66301b4..b7fce991c 100644
--- a/src/mainview/components/CallOverlayButtonGroup.qml
+++ b/src/mainview/components/CallOverlayButtonGroup.qml
@@ -45,7 +45,7 @@ Rectangle {
     }
 
     function setButtonStatus(isPaused, isAudioOnly, isAudioMuted, isVideoMuted,
-                             isRecording, isSIP, isConferenceCall) {
+                             isSIP, isConferenceCall) {
         root.isModerator = CallAdapter.isCurrentModerator()
         root.isSip = isSIP
         noVideoButton.visible = !isAudioOnly
diff --git a/src/mainview/components/CallViewContextMenu.qml b/src/mainview/components/CallViewContextMenu.qml
index 9667aaf12..75919c5cd 100644
--- a/src/mainview/components/CallViewContextMenu.qml
+++ b/src/mainview/components/CallViewContextMenu.qml
@@ -37,7 +37,8 @@ Item {
     property bool isSIP: false
     property bool isPaused: false
     property bool isAudioOnly: false
-    property bool isRecording: false
+    property bool localIsRecording: false
+    property bool peerIsRecording: false
 
     signal pluginItemClicked
     signal transferCallButtonClicked
@@ -67,7 +68,7 @@ Item {
             ContextMenuGenerator.addMenuSeparator()
         }
 
-        ContextMenuGenerator.addMenuItem(isRecording ? JamiStrings.stopRec :
+        ContextMenuGenerator.addMenuItem(localIsRecording ? JamiStrings.stopRec :
                                                        JamiStrings.startRec,
                                          "qrc:/images/icons/av_icons/fiber_manual_record-24px.svg",
                                          function (){
diff --git a/src/mainview/components/VideoCallPage.qml b/src/mainview/components/VideoCallPage.qml
index a7897d3f0..52e879d5b 100644
--- a/src/mainview/components/VideoCallPage.qml
+++ b/src/mainview/components/VideoCallPage.qml
@@ -197,6 +197,10 @@ Rectangle {
                         function onShowOnHoldLabel(isPaused) {
                             videoCallOverlay.showOnHoldImage(isPaused)
                         }
+
+                        function onRemoteRecordingChanged(label, state) {
+                            videoCallOverlay.showRemoteRecording(label, state)
+                        }
                     }
 
                     onOverlayChatButtonClicked: {
-- 
GitLab