Files
jami-client-qt/src/app/currentcall.cpp
Andreas Traczyk 14ae000686 mainapp: dynamically load views
Introduces the ViewCoordinator component to promote dynamic view loading and reduce coupling between components.

The following objects are now created and destroyed as needed:
- SettingsView
- WizardView
- dialogs

Further refactoring will be required in order to do the same with the ConversationView, which now parents the ChatView and the CallStackView.

Gitlab: #897
Change-Id: Ice6a0c133e62e1e0c8d7fb99ec2c41234c049b59
2023-02-17 13:59:28 -05:00

339 lines
9.8 KiB
C++

/*
* Copyright (C) 2022-2023 Savoir-faire Linux Inc.
*
* 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/>.
*/
#include "currentcall.h"
#include <api/callparticipantsmodel.h>
CurrentCall::CurrentCall(LRCInstance* lrcInstance, QObject* parent)
: QObject(parent)
, lrcInstance_(lrcInstance)
{
connect(lrcInstance_,
&LRCInstance::currentAccountIdChanged,
this,
&CurrentCall::onCurrentAccountIdChanged);
connect(lrcInstance_,
&LRCInstance::selectedConvUidChanged,
this,
&CurrentCall::onCurrentConvIdChanged);
connect(&lrcInstance_->behaviorController(),
&BehaviorController::showIncomingCallView,
this,
&CurrentCall::onShowIncomingCallView);
connectModel();
}
void
CurrentCall::updateId(QString callId)
{
auto convId = lrcInstance_->get_selectedConvUid();
auto optConv = lrcInstance_->getCurrentConversationModel()->getConversationForUid(convId);
if (!optConv.has_value()) {
return;
}
// If the optional parameter callId is empty, then we've just
// changed conversation selection and need to check the current
// conv's callId for an existing call.
// Otherwise, return if callId doesn't belong to this conversation.
if (callId.isEmpty()) {
callId = optConv->get().getCallId();
} else if (optConv->get().getCallId() != callId) {
return;
}
// Set the current id_ if there is a call.
auto& accInfo = lrcInstance_->getCurrentAccountInfo();
set_id((accInfo.callModel->hasCall(callId) ? callId : QString()));
}
void
CurrentCall::updateCallStatus()
{
call::Status status {};
auto callModel = lrcInstance_->getCurrentCallModel();
if (callModel->hasCall(id_)) {
auto callInfo = callModel->getCall(id_);
status = callInfo.status;
}
set_status(status);
set_isActive(status_ == call::Status::CONNECTED || status_ == call::Status::IN_PROGRESS
|| status_ == call::Status::PAUSED);
set_isPaused(status_ == call::Status::PAUSED);
}
void
CurrentCall::updateParticipants()
{
auto callModel = lrcInstance_->getCurrentCallModel();
QStringList uris;
auto& participantsModel = callModel->getParticipantsInfos(id_);
for (int index = 0; index < participantsModel.getParticipants().size(); index++) {
auto participantInfo = participantsModel.toQJsonObject(index);
uris.append(participantInfo[ParticipantsInfosStrings::URI].toString());
}
set_uris(uris);
set_isConference(uris.size());
}
void
CurrentCall::updateCallInfo()
{
auto callModel = lrcInstance_->getCurrentCallModel();
if (!callModel->hasCall(id_)) {
return;
}
auto callInfo = callModel->getCall(id_);
set_isOutgoing(callInfo.isOutgoing);
set_isGrid(callInfo.layout == call::Layout::GRID);
set_isAudioOnly(callInfo.isAudioOnly);
bool isAudioMuted {};
bool isVideoMuted {};
bool isSharing {};
QString sharingSource {};
bool isCapturing {};
QString previewId {};
using namespace libjami::Media;
if (callInfo.status != lrc::api::call::Status::ENDED) {
for (const auto& media : callInfo.mediaList) {
if (media[MediaAttributeKey::MEDIA_TYPE] == Details::MEDIA_TYPE_VIDEO) {
if (media[MediaAttributeKey::SOURCE].startsWith(VideoProtocolPrefix::DISPLAY)
|| media[MediaAttributeKey::SOURCE].startsWith(VideoProtocolPrefix::FILE)) {
isSharing = true;
sharingSource = media[MediaAttributeKey::SOURCE];
}
if (media[MediaAttributeKey::ENABLED] == TRUE_STR
&& media[MediaAttributeKey::MUTED] == FALSE_STR && previewId.isEmpty()) {
previewId = media[libjami::Media::MediaAttributeKey::SOURCE];
}
if (media[libjami::Media::MediaAttributeKey::SOURCE].startsWith(
libjami::Media::VideoProtocolPrefix::CAMERA)) {
isVideoMuted |= media[MediaAttributeKey::MUTED] == TRUE_STR;
isCapturing = media[MediaAttributeKey::MUTED] == FALSE_STR;
}
} else if (media[MediaAttributeKey::MEDIA_TYPE] == Details::MEDIA_TYPE_AUDIO) {
if (media[MediaAttributeKey::LABEL] == "audio_0") {
isAudioMuted |= media[libjami::Media::MediaAttributeKey::MUTED] == TRUE_STR;
}
}
}
}
set_previewId(previewId);
set_isAudioMuted(isAudioMuted);
set_isVideoMuted(isVideoMuted);
set_isSharing(isSharing);
set_sharingSource(sharingSource);
set_isCapturing(isCapturing);
set_isHandRaised(callModel->isHandRaised(id_));
set_isModerator(callModel->isModerator(id_));
QStringList recorders {};
if (callModel->hasCall(id_)) {
auto callInfo = callModel->getCall(id_);
recorders = callInfo.recordingPeers;
}
updateRecordingState(callModel->isRecording(id_));
updateRemoteRecorders(recorders);
}
void
CurrentCall::updateRemoteRecorders(const QStringList& recorders)
{
auto& accInfo = lrcInstance_->getCurrentAccountInfo();
remoteRecorderNameList_.clear();
Q_FOREACH (const auto& uri, recorders) {
auto bestName = accInfo.contactModel->bestNameForContact(uri);
if (!bestName.isEmpty()) {
remoteRecorderNameList_.append(bestName);
}
}
// Convenience flag.
set_isRecordingRemotely(!remoteRecorderNameList_.isEmpty());
Q_EMIT remoteRecorderNameListChanged();
}
void
CurrentCall::updateRecordingState(bool state)
{
set_isRecordingLocally(state);
}
void
CurrentCall::connectModel()
{
auto callModel = lrcInstance_->getCurrentCallModel();
if (callModel == nullptr) {
return;
}
connect(callModel,
&CallModel::callStatusChanged,
this,
&CurrentCall::onCallStatusChanged,
Qt::UniqueConnection);
connect(callModel,
&CallModel::callInfosChanged,
this,
&CurrentCall::onCallInfosChanged,
Qt::UniqueConnection);
connect(callModel,
&CallModel::currentCallChanged,
this,
&CurrentCall::onCurrentCallChanged,
Qt::UniqueConnection);
connect(callModel,
&CallModel::participantsChanged,
this,
&CurrentCall::onParticipantsChanged,
Qt::UniqueConnection);
connect(callModel,
&CallModel::remoteRecordersChanged,
this,
&CurrentCall::onRemoteRecordersChanged,
Qt::UniqueConnection);
connect(callModel,
&CallModel::recordingStateChanged,
this,
&CurrentCall::onRecordingStateChanged,
Qt::UniqueConnection);
}
void
CurrentCall::onCurrentConvIdChanged()
{
updateId();
updateCallStatus();
updateParticipants();
updateCallInfo();
auto callModel = lrcInstance_->getCurrentCallModel();
QStringList recorders {};
if (callModel->hasCall(id_)) {
auto callInfo = callModel->getCall(id_);
recorders = callInfo.recordingPeers;
}
updateRecordingState(callModel->isRecording(id_));
updateRemoteRecorders(recorders);
}
void
CurrentCall::onCurrentAccountIdChanged()
{
try {
auto& accInfo = lrcInstance_->getCurrentAccountInfo();
set_isSIP(accInfo.profileInfo.type == profile::Type::SIP);
} catch (const std::exception& e) {
qWarning() << "Can't update current call type" << e.what();
}
connectModel();
}
void
CurrentCall::onCallStatusChanged(const QString& callId, int code)
{
Q_UNUSED(code)
if (id_ != callId) {
return;
}
updateCallStatus();
}
void
CurrentCall::onCallInfosChanged(const QString& accountId, const QString& callId)
{
if (id_ != callId) {
return;
}
updateCallInfo();
}
void
CurrentCall::onCurrentCallChanged(const QString& callId)
{
// If this status change's callId is not the current, it's possible that
// the current value of id_ is stale, and needs to be updated after checking
// the current conversation's getCallId(). Other slots need not do this, as the
// id_ is updated in CurrentCall::updateId.
if (id_ == callId) {
return;
}
updateId(callId);
updateCallStatus();
updateParticipants();
updateCallInfo();
}
void
CurrentCall::onParticipantsChanged(const QString& callId)
{
if (id_ != callId) {
return;
}
updateParticipants();
}
void
CurrentCall::onRemoteRecordersChanged(const QString& callId, const QStringList& recorders)
{
if (id_ != callId) {
return;
}
updateRemoteRecorders(recorders);
}
void
CurrentCall::onRecordingStateChanged(const QString& callId, bool state)
{
if (id_ != callId) {
return;
}
updateRecordingState(state);
}
void
CurrentCall::onShowIncomingCallView(const QString& accountId, const QString& convUid)
{
if (accountId != lrcInstance_->get_currentAccountId()
|| convUid != lrcInstance_->get_selectedConvUid()) {
return;
}
// Update the id in case the current conversation now has a call
// that matches the current id.
updateId();
updateCallStatus();
updateCallInfo();
}