Skip to content
Snippets Groups Projects
Commit 6607e0e9 authored by Sébastien Blin's avatar Sébastien Blin
Browse files

videocallpage: handle conference infos

Change-Id: I4cfc7c9c525c66f4e483089864bec059c388a1bd
parent 8940f3c4
No related branches found
No related tags found
No related merge requests found
[gerrit]
host=gerrit-ring.savoirfairelinux.com
port=29420
project=ring-client-window.git
project=jami-client-qt.git
defaultremote=origin
defaultbranch=master
<svg fill="#ffffff" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08c-.18-.17-.29-.42-.29-.7 0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28-.79-.74-1.69-1.36-2.67-1.85-.33-.16-.56-.5-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z"/>
</svg>
......@@ -67,6 +67,7 @@
<file>src/mainview/components/ContactSearchBar.qml</file>
<file>src/mainview/components/VideoCallPage.qml</file>
<file>src/mainview/components/CallAdvancedOptions.qml</file>
<file>src/mainview/components/ParticipantOverlay.qml</file>
<file>src/mainview/components/ChangeLogScrollView.qml</file>
<file>src/mainview/components/ProjectCreditsScrollView.qml</file>
<file>src/mainview/components/AccountComboBoxPopup.qml</file>
......@@ -77,6 +78,7 @@
<file>src/commoncomponents/GeneralMenuItem.qml</file>
<file>src/mainview/components/ConversationSmartListContextMenu.qml</file>
<file>src/mainview/components/CallViewContextMenu.qml</file>
<file>src/mainview/components/ParticipantContextMenu.qml</file>
<file>src/commoncomponents/GeneralMenuSeparator.qml</file>
<file>src/mainview/components/UserProfile.qml</file>
<file>src/mainview/js/videodevicecontextmenuitemcreation.js</file>
......
......@@ -37,7 +37,7 @@ CallAdapter::~CallAdapter() {}
void
CallAdapter::initQmlObject()
{
connectCallStatusChanged(LRCInstance::getCurrAccId());
connectCallModel(LRCInstance::getCurrAccId());
connect(&LRCInstance::behaviorController(),
&BehaviorController::showIncomingCallView,
......@@ -233,12 +233,91 @@ CallAdapter::shouldShowPreview(bool force)
return shouldShowPreview;
}
QVariantList
CallAdapter::getConferencesInfos()
{
QVariantList map;
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
if (convInfo.uid.isEmpty())
return map;
auto callId = convInfo.confId.isEmpty()? convInfo.callId : convInfo.confId;
if (!callId.isEmpty()) {
try {
auto call = LRCInstance::getCurrentCallModel()->getCall(callId);
for (const auto& participant: call.participantsInfos) {
QJsonObject data;
data["x"] = participant["x"].toInt();
data["y"] = participant["y"].toInt();
data["w"] = participant["w"].toInt();
data["h"] = participant["h"].toInt();
data["active"] = participant["active"] == "true";
auto bestName = participant["uri"];
auto &accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
data["isLocal"] = false;
if (bestName == accInfo.profileInfo.uri) {
bestName = tr("me");
data["isLocal"] = true;
} else {
try {
auto &contact = LRCInstance::getCurrentAccountInfo().contactModel->getContact(participant["uri"]);
bestName = Utils::bestNameForContact(contact);
} catch (...) {}
}
data["bestName"] = bestName;
map.push_back(QVariant(data));
}
return map;
} catch (...) {}
}
return map;
}
void
CallAdapter::connectCallStatusChanged(const QString &accountId)
CallAdapter::connectCallModel(const QString &accountId)
{
auto &accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
QObject::disconnect(callStatusChangedConnection_);
QObject::disconnect(onParticipantsChangedConnection_);
onParticipantsChangedConnection_ = QObject::connect(
accInfo.callModel.get(),
&lrc::api::NewCallModel::onParticipantsChanged,
[this, accountId](const QString &confId) {
auto &accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
auto &callModel = accInfo.callModel;
auto call = callModel->getCall(confId);
auto convInfo = LRCInstance::getConversationFromCallId(confId);
if (!convInfo.uid.isEmpty()) {
// Convert to QML
QVariantList map;
for (const auto& participant: call.participantsInfos) {
QJsonObject data;
data["x"] = participant["x"].toInt();
data["y"] = participant["y"].toInt();
data["w"] = participant["w"].toInt();
data["h"] = participant["h"].toInt();
data["uri"] = participant["uri"];
data["active"] = participant["active"] == "true";
auto bestName = participant["uri"];
data["isLocal"] = false;
auto &accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
if (bestName == accInfo.profileInfo.uri) {
bestName = tr("me");
data["isLocal"] = true;
} else {
try {
auto &contact = LRCInstance::getCurrentAccountInfo().contactModel->getContact(participant["uri"]);
bestName = Utils::bestNameForContact(contact);
} catch (...) {}
}
data["bestName"] = bestName;
map.push_back(QVariant(data));
}
emit updateParticipantsInfos(map, accountId, confId);
}
});
callStatusChangedConnection_ = QObject::connect(
accInfo.callModel.get(),
......@@ -345,7 +424,7 @@ CallAdapter::updateCallOverlay(const lrc::api::conversation::Info &convInfo)
bool isAudioOnly = call->isAudioOnly && !isPaused;
bool isAudioMuted = call->audioMuted && (call->status != lrc::api::call::Status::PAUSED);
bool isVideoMuted = call->videoMuted && !isPaused && !call->isAudioOnly;
bool isRecording = accInfo.callModel->isRecording(convInfo.callId);
bool isRecording = isRecordingThisCall();
emit updateOverlay(isPaused,
isAudioOnly,
......@@ -359,16 +438,16 @@ CallAdapter::updateCallOverlay(const lrc::api::conversation::Info &convInfo)
}
void
CallAdapter::hangUpThisCall()
CallAdapter::hangupCall(const QString& uri)
{
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
auto convInfo = LRCInstance::getConversationFromPeerUri(uri, accountId_);
if (!convInfo.uid.isEmpty()) {
auto callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
if (callModel->hasCall(convInfo.callId)) {
/*
* Store the last remaining participant of the conference,
* so we can switch the smartlist index after termination.
*/
* Store the last remaining participant of the conference,
* so we can switch the smartlist index after termination.
*/
if (!convInfo.confId.isEmpty()) {
auto callList = LRCInstance::getAPI().getConferenceSubcalls(convInfo.confId);
if (callList.size() == 2) {
......@@ -379,6 +458,73 @@ CallAdapter::hangUpThisCall()
}
}
}
callModel->hangUp(convInfo.callId);
}
}
}
void
CallAdapter::maximizeParticipant(const QString& uri, bool isActive)
{
auto callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
auto confId = LRCInstance::getCurrentConversation().confId;
QString callId;
if (LRCInstance::getCurrentAccountInfo().profileInfo.uri != uri) {
auto convInfo = LRCInstance::getConversationFromPeerUri(uri, accountId_);
if (!convInfo.uid.isEmpty()) {
callId = convInfo.callId;
}
}
try {
auto call = callModel->getCall(confId);
switch (call.layout) {
case lrc::api::call::Layout::GRID:
callModel->setActiveParticipant(confId, callId);
callModel->setConferenceLayout(confId, lrc::api::call::Layout::ONE_WITH_SMALL);
break;
case lrc::api::call::Layout::ONE_WITH_SMALL:
callModel->setActiveParticipant(confId, callId);
callModel->setConferenceLayout(confId,
isActive? lrc::api::call::Layout::ONE : lrc::api::call::Layout::ONE_WITH_SMALL);
break;
case lrc::api::call::Layout::ONE:
callModel->setActiveParticipant(confId, callId);
callModel->setConferenceLayout(confId, lrc::api::call::Layout::GRID);
break;
};
} catch (...) {}
}
void
CallAdapter::minimizeParticipant()
{
auto callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
auto confId = LRCInstance::getCurrentConversation().confId;
try {
auto call = callModel->getCall(confId);
switch (call.layout) {
case lrc::api::call::Layout::GRID:
break;
case lrc::api::call::Layout::ONE_WITH_SMALL:
callModel->setConferenceLayout(confId, lrc::api::call::Layout::GRID);
break;
case lrc::api::call::Layout::ONE:
callModel->setConferenceLayout(confId, lrc::api::call::Layout::ONE_WITH_SMALL);
break;
};
} catch (...) {}
}
void
CallAdapter::hangUpThisCall()
{
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
if (!convInfo.uid.isEmpty()) {
auto callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
if (!convInfo.confId.isEmpty() && callModel->hasCall(convInfo.confId)) {
callModel->hangUp(convInfo.confId);
} else if (callModel->hasCall(convInfo.callId)) {
callModel->hangUp(convInfo.callId);
}
}
......@@ -393,6 +539,38 @@ CallAdapter::isRecordingThisCall()
|| accInfo.callModel->isRecording(convInfo.callId);
}
bool
CallAdapter::isCurrentMaster() const
{
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
if (!convInfo.uid.isEmpty()) {
auto callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
try {
if (!convInfo.confId.isEmpty() && callModel->hasCall(convInfo.confId)) {
return true;
} else {
auto call = callModel->getCall(convInfo.callId);
return call.participantsInfos.size() == 0;
}
} catch (...) {}
}
return true;
}
int
CallAdapter::getCurrentLayoutType() const
{
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
if (!convInfo.uid.isEmpty()) {
auto callModel = LRCInstance::getAccountInfo(accountId_).callModel.get();
try {
auto call = callModel->getCall(convInfo.confId);
return Utils::toUnderlyingValue(call.layout);
} catch (...) {}
}
return -1;
}
void
CallAdapter::holdThisCallToggle()
{
......
......@@ -24,6 +24,7 @@
#include <QObject>
#include <QString>
#include <QVariant>
class CallAdapter : public QmlAdapterBase
{
......@@ -44,17 +45,23 @@ public:
Q_INVOKABLE void refuseACall(const QString &accountId, const QString &convUid);
Q_INVOKABLE void acceptACall(const QString &accountId, const QString &convUid);
Q_INVOKABLE void connectCallStatusChanged(const QString &accountId);
Q_INVOKABLE void connectCallModel(const QString &accountId);
/*
* For Call Overlay
*/
Q_INVOKABLE void hangupCall(const QString& uri);
Q_INVOKABLE void maximizeParticipant(const QString& uri, bool isActive);
Q_INVOKABLE void minimizeParticipant();
Q_INVOKABLE void hangUpThisCall();
Q_INVOKABLE bool isCurrentMaster() const;
Q_INVOKABLE int getCurrentLayoutType() const;
Q_INVOKABLE void holdThisCallToggle();
Q_INVOKABLE void muteThisCallToggle();
Q_INVOKABLE void recordThisCallToggle();
Q_INVOKABLE void videoPauseThisCallToggle();
Q_INVOKABLE bool isRecordingThisCall();
Q_INVOKABLE QVariantList getConferencesInfos();
signals:
void showOutgoingCallPage(const QString &accountId, const QString &convUid);
......@@ -66,6 +73,7 @@ signals:
void closePotentialIncomingCallPageWindow(const QString &accountId, const QString &convUid);
void callStatusChanged(const QString &status, const QString &accountId, const QString &convUid);
void updateConversationSmartList();
void updateParticipantsInfos(const QVariantList& infos, const QString &accountId, const QString &callId);
void incomingCallNeedToSetupMainView(const QString &accountId, const QString &convUid);
void previewVisibilityNeedToChange(bool visible);
......@@ -103,6 +111,7 @@ private:
QString convUid_;
QMetaObject::Connection callStatusChangedConnection_;
QMetaObject::Connection onParticipantsChangedConnection_;
QMetaObject::Connection closeIncomingCallPageConnection_;
/*
......
......@@ -51,15 +51,48 @@ DistantRenderer::setRendererId(const QString &id)
update(QRect(0, 0, width(), height()));
}
int
DistantRenderer::getXOffset() const
{
return xOffset_;
}
int
DistantRenderer::getYOffset() const
{
return yOffset_;
}
double
DistantRenderer::getScaledWidth() const
{
return scaledWidth_;
}
double
DistantRenderer::getScaledHeight() const
{
return scaledHeight_;
}
void
DistantRenderer::paint(QPainter *painter)
{
auto distantImage = LRCInstance::renderer()->getFrame(distantRenderId_);
if (distantImage) {
auto scaledDistant = distantImage->scaled(size().toSize(), Qt::KeepAspectRatio);
auto xDiff = (width() - scaledDistant.width()) / 2;
auto yDiff = (height() - scaledDistant.height()) / 2;
painter->drawImage(QRect(xDiff, yDiff, scaledDistant.width(), scaledDistant.height()),
auto tempScaledWidth = static_cast<int>(scaledWidth_*1000);
auto tempScaledHeight = static_cast<int>(scaledHeight_*1000);
auto tempXOffset = xOffset_;
auto tempYOffset = yOffset_;
scaledWidth_ = static_cast<double>(scaledDistant.width())/static_cast<double>(distantImage->width());
scaledHeight_ = static_cast<double>(scaledDistant.height())/static_cast<double>(distantImage->height());
xOffset_ = (width() - scaledDistant.width()) / 2;
yOffset_ = (height() - scaledDistant.height()) / 2;
if (tempXOffset != xOffset_ or tempYOffset != yOffset_ or static_cast<int>(scaledWidth_*1000) != tempScaledWidth or static_cast<int>(scaledHeight_*1000) != tempScaledHeight) {
emit offsetChanged();
}
painter->drawImage(QRect(xOffset_, yOffset_, scaledDistant.width(), scaledDistant.height()),
scaledDistant);
}
}
\ No newline at end of file
......@@ -34,6 +34,13 @@ public:
~DistantRenderer();
Q_INVOKABLE void setRendererId(const QString &id);
Q_INVOKABLE int getXOffset() const;
Q_INVOKABLE int getYOffset() const;
Q_INVOKABLE double getScaledWidth() const;
Q_INVOKABLE double getScaledHeight() const;
signals:
void offsetChanged();
private:
void paint(QPainter *painter);
......@@ -42,4 +49,8 @@ private:
* Unique DistantRenderId for each call.
*/
QString distantRenderId_;
int xOffset_ {0};
int yOffset_ {0};
double scaledWidth_ {0};
double scaledHeight_ {0};
};
\ No newline at end of file
......@@ -229,7 +229,7 @@ public:
{
return getConversation(
!accountId.isEmpty() ? accountId : getCurrAccId(),
[&](const conversation::Info &conv) -> bool { return callId == conv.callId; },
[&](const conversation::Info &conv) -> bool { return callId == conv.callId or callId == conv.confId; },
filtered);
}
static const conversation::Info &
......
......@@ -35,6 +35,9 @@ Rectangle {
signal overlayChatButtonClicked
property var participantOverlays: []
property var participantComponent: Qt.createComponent("ParticipantOverlay.qml")
function setRecording(isRecording) {
callViewContextMenu.isRecording = isRecording
recordingRect.visible = isRecording
......@@ -52,6 +55,10 @@ Rectangle {
isConferenceCall)
}
function updateMaster() {
callOverlayButtonGroup.updateMaster()
}
function showOnHoldImage(visible) {
onHoldImage.visible = visible
}
......@@ -60,6 +67,41 @@ Rectangle {
ContactPickerCreation.closeContactPicker()
}
function handleParticipantsInfo(infos) {
videoCallOverlay.updateMaster()
var isMaster = CallAdapter.isCurrentMaster()
for (var p in participantOverlays) {
if (participantOverlays[p])
participantOverlays[p].destroy()
}
participantOverlays = []
if (infos.length == 0) {
previewRenderer.visible = true
} else {
previewRenderer.visible = false
for (var infoVariant in infos) {
var hover = participantComponent.createObject(callOverlayRectMouseArea, {
x: distantRenderer.getXOffset() + infos[infoVariant].x * distantRenderer.getScaledWidth(),
y: distantRenderer.getYOffset() + infos[infoVariant].y * distantRenderer.getScaledHeight(),
width: infos[infoVariant].w * distantRenderer.getScaledWidth(),
height: infos[infoVariant].h * distantRenderer.getScaledHeight(),
visible: infos[infoVariant].w != 0 && infos[infoVariant].h != 0
})
if (!hover) {
console.log("Error when creating the hover")
return
}
hover.setParticipantName(infos[infoVariant].bestName)
hover.active = infos[infoVariant].active;
hover.isLocal = infos[infoVariant].isLocal;
hover.setMenuVisible(isMaster)
hover.uri = infos[infoVariant].uri
hover.injectedContextMenu = participantContextMenu
participantOverlays.push(hover)
}
}
}
anchors.fill: parent
......@@ -313,10 +355,9 @@ Rectangle {
id: callOverlayRectMouseArea
anchors.top: callOverlayRect.top
anchors.topMargin: 50
width: callOverlayRect.width
height: callOverlayRect.height - callOverlayButtonGroup.height - 50
height: callOverlayRect.height
hoverEnabled: true
propagateComposedEvents: true
......@@ -370,4 +411,8 @@ Rectangle {
ContactPickerCreation.openContactPicker()
}
}
ParticipantContextMenu {
id: participantContextMenu
}
}
......@@ -34,13 +34,24 @@ Rectangle {
* since no other methods can make buttons at the layout center.
*/
property int buttonPreferredSize: 24
property var isMaster: true
property var isSip: false
signal chatButtonClicked
signal addToConferenceButtonClicked
function updateMaster() {
root.isMaster = CallAdapter.isCurrentMaster()
addToConferenceButton.visible = !root.isSip && root.isMaster
}
function setButtonStatus(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall) {
root.isMaster = CallAdapter.isCurrentMaster()
root.isSip = isSIP
noVideoButton.visible = !isAudioOnly
addToConferenceButton.visible = !isSIP
addToConferenceButton.visible = !isSIP && isMaster
transferCallButton.visible = isSIP
sipInputPanelButton.visible = isSIP
noMicButton.checked = isAudioMuted
noVideoButton.checked = isVideoMuted
......@@ -148,6 +159,7 @@ Rectangle {
Layout.preferredWidth: buttonPreferredSize * 2
Layout.preferredHeight: buttonPreferredSize * 2
visible: !isMaster
backgroundColor: Qt.rgba(0, 0, 0, 0.75)
onEnterColor: Qt.rgba(0, 0, 0, 0.6)
......
......@@ -157,11 +157,17 @@ Rectangle {
}
function onCallStatusChanged(status, accountId, convUid) {
if (responsibleConvUid === convUid
&& responsibleAccountId === accountId) {
if (responsibleConvUid === convUid && responsibleAccountId === accountId) {
outgoingCallPage.callStatusPresentation = status
}
}
function onUpdateParticipantsInfos(infos, accountId, callId) {
var responsibleCallId = ClientWrapper.utilsAdaptor.getCallId(responsibleAccountId, responsibleConvUid)
if (responsibleCallId === callId) {
videoCallPage.handleParticipantsInfo(infos)
}
}
}
AudioCallPage {
......@@ -198,6 +204,8 @@ Rectangle {
videoCallPage.parent = callStackMainView
VideoCallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer()
}
videoCallPage.handleParticipantsInfo(CallAdapter.getConferencesInfos())
}
}
......
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.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 3 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtGraphicalEffects 1.12
import net.jami.Models 1.0
import "../../commoncomponents"
import "../js/videodevicecontextmenuitemcreation.js" as VideoDeviceContextMenuItemCreation
import "../js/selectscreenwindowcreation.js" as SelectScreenWindowCreation
Menu {
id: root
property int generalMenuSeparatorCount: 0
property int commonBorderWidth: 1
font.pointSize: JamiTheme.textFontSize + 3
property var uri: ""
property var maximized: true
property var active: true
function showHangup(show) {
if (show) {
hangupItem.visible = true
hangupItem.height = hangupItem.preferredHeight
} else {
hangupItem.visible = false
hangupItem.height = 0
}
}
function showMaximize(show) {
if (show) {
maximizeItem.visible = true
maximizeItem.height = hangupItem.preferredHeight
} else {
maximizeItem.visible = false
maximizeItem.height = 0
}
}
function showMinimize(show) {
if (show) {
minimizeItem.visible = true
minimizeItem.height = hangupItem.preferredHeight
} else {
minimizeItem.visible = false
minimizeItem.height = 0
}
}
function setHeight(visibleItems) {
root.height = hangupItem.preferredHeight * visibleItems;
}
/*
* All GeneralMenuItems should remain the same width / height.
*/
GeneralMenuItem {
id: hangupItem
itemName: qsTr("Hangup")
iconSource: "qrc:/images/icons/ic_call_end_white_24px.svg"
icon.color: "black"
leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth
onClicked: {
CallAdapter.hangupCall(uri)
root.close()
}
}
GeneralMenuItem {
id: maximizeItem
itemName: qsTr("Maximize participant")
iconSource: "qrc:/images/icons/open_in_full-24px.svg"
leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth
visible: !maximized
onClicked: {
CallAdapter.maximizeParticipant(uri, active)
root.close()
}
}
GeneralMenuItem {
id: minimizeItem
itemName: qsTr("Minimize participant")
iconSource: "qrc:/images/icons/close_fullscreen-24px.svg"
leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth
visible: maximized
onClicked: {
CallAdapter.minimizeParticipant()
root.close()
}
}
background: Rectangle {
implicitWidth: hangupItem.preferredWidth
implicitHeight: hangupItem.preferredHeight * 3
border.width: commonBorderWidth
border.color: JamiTheme.tabbarBorderColor
}
}
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.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 3 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls.Universal 2.12
import QtGraphicalEffects 1.14
import net.jami.Models 1.0
import "../../commoncomponents"
Rectangle {
id: root
property int buttonPreferredSize: 12
property var uri: ""
property var active: true
property var isLocal: true
property var injectedContextMenu: null
function setParticipantName(name) {
participantName.text = name
}
function setMenuVisible(isVisible) {
optionsButton.visible = isVisible
}
border.width: 1
opacity: 0
color: "transparent"
z: 1
MouseArea {
id: mouseAreaHover
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
acceptedButtons: Qt.LeftButton
RowLayout {
id: bottomLabel
height: 24
width: parent.width
anchors.bottom: parent.bottom
Rectangle {
color: "black"
opacity: 0.8
height: parent.height
width: parent.width
Layout.fillWidth: true
Layout.preferredHeight: parent.height
Text {
id: participantName
anchors.fill: parent
leftPadding: 8.0
TextMetrics {
id: participantMetrics
elide: Text.ElideRight
elideWidth: bottomLabel.width - 8
}
text: participantMetrics.elidedText
color: "white"
font.pointSize: JamiTheme.textFontSize
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
Button {
id: optionsButton
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
background: Rectangle {
color: "transparent"
}
icon.color: "white"
icon.height: buttonPreferredSize
icon.width: buttonPreferredSize
icon.source: "qrc:/images/icons/more_vert-24px.svg"
onClicked: {
if (!injectedContextMenu) {
console.log("Participant's overlay don't have any injected context menu")
return
}
var mousePos = mapToItem(videoCallPageRect, parent.x, parent.y)
var layout = CallAdapter.getCurrentLayoutType()
var showMaximized = layout !== 2
var showMinimized = !(layout === 0 || (layout === 1 && !active))
injectedContextMenu.showHangup(!root.isLocal)
injectedContextMenu.showMaximize(showMaximized)
injectedContextMenu.showMinimize(showMinimized)
injectedContextMenu.setHeight(
(root.isLocal ? 0 : 1)
+ (showMaximized ? 1 : 0)
+ (showMinimized ? 1 : 0))
injectedContextMenu.uri = uri
injectedContextMenu.active = active
injectedContextMenu.x = mousePos.x
injectedContextMenu.y = mousePos.y - injectedContextMenu.height
injectedContextMenu.open()
}
}
}
}
onClicked: {
CallAdapter.maximizeParticipant(uri, active)
}
onEntered: {
root.state = "entered"
}
onExited: {
root.state = "exited"
}
}
states: [
State {
name: "entered"
PropertyChanges {
target: root
opacity: 1
}
},
State {
name: "exited"
PropertyChanges {
target: root
opacity: 0
}
}
]
transitions: Transition {
PropertyAnimation {
target: root
property: "opacity"
duration: 500
}
}
}
\ No newline at end of file
......@@ -42,6 +42,8 @@ Rectangle {
signal needToShowInFullScreen
function updateUI(accountId, convUid) {
videoCallOverlay.handleParticipantsInfo(CallAdapter.getConferencesInfos())
bestName = ClientWrapper.utilsAdaptor.getBestName(accountId, convUid)
var id = ClientWrapper.utilsAdaptor.getBestId(accountId, convUid)
......@@ -74,6 +76,15 @@ Rectangle {
videoCallOverlay.closePotentialContactPicker()
}
function handleParticipantsInfo(infos) {
if (infos.length === 0) {
bestName = ClientWrapper.utilsAdaptor.getBestName(accountId, convUid)
} else {
bestName = ""
}
videoCallOverlay.handleParticipantsInfo(infos)
}
function previewMagneticSnap() {
......@@ -225,6 +236,10 @@ Rectangle {
width: videoCallPageMainRect.width
height: videoCallPageMainRect.height
onOffsetChanged: {
videoCallOverlay.handleParticipantsInfo(CallAdapter.getConferencesInfos())
}
}
VideoCallPreviewRenderer {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment