Skip to content
Snippets Groups Projects
Commit 4968dcf8 authored by Andreas Traczyk's avatar Andreas Traczyk
Browse files

call: add conference feature

Change-Id: I84382a10725b53913c28d2fd66d7ddead12da1a0
parent 3b71cdad
Branches
No related tags found
No related merge requests found
...@@ -183,7 +183,7 @@ CallWidget::CallWidget(QWidget* parent) : ...@@ -183,7 +183,7 @@ CallWidget::CallWidget(QWidget* parent) :
connect(ui->messageView, &MessageWebView::invitationAccepted, connect(ui->messageView, &MessageWebView::invitationAccepted,
[this] { [this] {
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->makePermanent(convUid); LRCInstance::getCurrentConversationModel()->makePermanent(convUid);
ui->sendContactRequestButton->hide(); ui->sendContactRequestButton->hide();
}); });
...@@ -318,7 +318,7 @@ CallWidget::onIncomingMessage(const std::string& accountId, const std::string& c ...@@ -318,7 +318,7 @@ CallWidget::onIncomingMessage(const std::string& accountId, const std::string& c
QString::fromStdString(interaction.body)); QString::fromStdString(interaction.body));
} }
updateConversationsFilterWidget(); updateConversationsFilterWidget();
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
return; return;
} }
convModel->clearUnreadInteractions(convUid); convModel->clearUnreadInteractions(convUid);
...@@ -360,7 +360,7 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos) ...@@ -360,7 +360,7 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos)
[this, convUid, conversation, convModel]() { [this, convUid, conversation, convModel]() {
convModel->placeCall(convUid); convModel->placeCall(convUid);
ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid))); ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid)));
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
selectConversation(conversation, *convModel); selectConversation(conversation, *convModel);
} }
}); });
...@@ -371,7 +371,7 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos) ...@@ -371,7 +371,7 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos)
[this, convUid, conversation, convModel]() { [this, convUid, conversation, convModel]() {
convModel->placeAudioOnlyCall(convUid); convModel->placeAudioOnlyCall(convUid);
ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid))); ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(convUid)));
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
selectConversation(conversation, *convModel); selectConversation(conversation, *convModel);
} }
}); });
...@@ -497,7 +497,7 @@ CallWidget::on_cancelButton_clicked() ...@@ -497,7 +497,7 @@ CallWidget::on_cancelButton_clicked()
void void
CallWidget::showConversationView() CallWidget::showConversationView()
{ {
if (LRCInstance::getSelectedConvUid().empty()) { if (LRCInstance::getCurrentConvUid().empty()) {
backToWelcomePage(); backToWelcomePage();
return; return;
} }
...@@ -543,9 +543,9 @@ CallWidget::on_smartList_doubleClicked(const QModelIndex& index) ...@@ -543,9 +543,9 @@ CallWidget::on_smartList_doubleClicked(const QModelIndex& index)
selectConversation(index); selectConversation(index);
LRCInstance::getCurrentConversationModel()->placeCall(LRCInstance::getSelectedConvUid()); LRCInstance::getCurrentConversationModel()->placeCall(LRCInstance::getCurrentConvUid());
ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(LRCInstance::getSelectedConvUid()))); ui->callingPhoto->setPixmap(QPixmap::fromImage(imageForConv(LRCInstance::getCurrentConvUid())));
} }
QImage QImage
...@@ -642,7 +642,7 @@ void ...@@ -642,7 +642,7 @@ void
CallWidget::slotBlockInviteClicked(const QModelIndex & index) CallWidget::slotBlockInviteClicked(const QModelIndex & index)
{ {
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString(); auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString();
if (!convUid.empty() && convUid == LRCInstance::getSelectedConvUid()) { if (!convUid.empty() && convUid == LRCInstance::getCurrentConvUid()) {
backToWelcomePage(); backToWelcomePage();
} }
LRCInstance::getCurrentConversationModel()->removeConversation(convUid, true); LRCInstance::getCurrentConversationModel()->removeConversation(convUid, true);
...@@ -652,7 +652,7 @@ void ...@@ -652,7 +652,7 @@ void
CallWidget::slotIgnoreInviteClicked(const QModelIndex & index) CallWidget::slotIgnoreInviteClicked(const QModelIndex & index)
{ {
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString(); auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString();
if (!convUid.empty() && convUid == LRCInstance::getSelectedConvUid()) { if (!convUid.empty() && convUid == LRCInstance::getCurrentConvUid()) {
backToWelcomePage(); backToWelcomePage();
} }
LRCInstance::getCurrentConversationModel()->removeConversation(convUid, false); LRCInstance::getCurrentConversationModel()->removeConversation(convUid, false);
...@@ -688,7 +688,7 @@ CallWidget::slotShowCallView(const std::string& accountId, ...@@ -688,7 +688,7 @@ CallWidget::slotShowCallView(const std::string& accountId,
ui->callStackWidget->setCurrentWidget(ui->videoPage); ui->callStackWidget->setCurrentWidget(ui->videoPage);
hideMiniSpinner(); hideMiniSpinner();
ui->videoView->setupForConversation(accountId, convInfo.uid); ui->videoView->updateCall(convInfo.uid, accountId);
ui->videoView->show(); ui->videoView->show();
ui->videoView->setFocus(); ui->videoView->setFocus();
} }
...@@ -713,7 +713,7 @@ CallWidget::slotShowIncomingCallView(const std::string& accountId, ...@@ -713,7 +713,7 @@ CallWidget::slotShowIncomingCallView(const std::string& accountId,
auto finalBestId = (bestName != bestId) ? bestId : ""; auto finalBestId = (bestName != bestId) ? bestId : "";
auto call = callModel->getCall(convInfo.callId); auto call = callModel->getCall(convInfo.callId);
auto isCallSelected = LRCInstance::getSelectedConvUid() == convInfo.uid; auto isCallSelected = LRCInstance::getCurrentConvUid() == convInfo.uid;
ui->callingStatusLabel->setText(QString::fromStdString(lrc::api::call::to_string(call.status))); ui->callingStatusLabel->setText(QString::fromStdString(lrc::api::call::to_string(call.status)));
connect(callModel, &lrc::api::NewCallModel::callStatusChanged, ui->incomingCallPage, connect(callModel, &lrc::api::NewCallModel::callStatusChanged, ui->incomingCallPage,
...@@ -1132,7 +1132,7 @@ CallWidget::connectConversationModel() ...@@ -1132,7 +1132,7 @@ CallWidget::connectConversationModel()
ui->messageView->clear(); ui->messageView->clear();
// if currently selected, // if currently selected,
// switch to welcome screen (deselecting current smartlist item ) // switch to welcome screen (deselecting current smartlist item )
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
return; return;
} }
backToWelcomePage(); backToWelcomePage();
...@@ -1141,7 +1141,7 @@ CallWidget::connectConversationModel() ...@@ -1141,7 +1141,7 @@ CallWidget::connectConversationModel()
interactionStatusUpdatedConnection_ = QObject::connect( interactionStatusUpdatedConnection_ = QObject::connect(
currentConversationModel, &lrc::api::ConversationModel::interactionStatusUpdated, currentConversationModel, &lrc::api::ConversationModel::interactionStatusUpdated,
[this](const std::string& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction) { [this](const std::string& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction) {
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
return; return;
} }
auto& currentAccountInfo = LRCInstance::getCurrentAccountInfo(); auto& currentAccountInfo = LRCInstance::getCurrentAccountInfo();
...@@ -1175,7 +1175,7 @@ CallWidget::connectConversationModel() ...@@ -1175,7 +1175,7 @@ CallWidget::connectConversationModel()
void void
CallWidget::updateConversationView(const std::string& convUid) CallWidget::updateConversationView(const std::string& convUid)
{ {
if (convUid != LRCInstance::getSelectedConvUid()) { if (convUid != LRCInstance::getCurrentConvUid()) {
return; return;
} }
} }
...@@ -1193,7 +1193,7 @@ CallWidget::selectConversation(const QModelIndex& index) ...@@ -1193,7 +1193,7 @@ CallWidget::selectConversation(const QModelIndex& index)
if (selectConversation(item, *convModel)) { if (selectConversation(item, *convModel)) {
showChatView(index); showChatView(index);
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
if (!lastConvUid_.compare(convUid)) { if (!lastConvUid_.compare(convUid)) {
return; return;
} }
...@@ -1215,7 +1215,7 @@ bool ...@@ -1215,7 +1215,7 @@ bool
CallWidget::selectConversation( const lrc::api::conversation::Info& item, CallWidget::selectConversation( const lrc::api::conversation::Info& item,
lrc::api::ConversationModel& convModel) lrc::api::ConversationModel& convModel)
{ {
if (LRCInstance::getSelectedConvUid() == item.uid) { if (LRCInstance::getCurrentConvUid() == item.uid) {
return false; return false;
} else if (item.participants.size() > 0) { } else if (item.participants.size() > 0) {
LRCInstance::setSelectedConvId(item.uid); LRCInstance::setSelectedConvId(item.uid);
...@@ -1229,7 +1229,7 @@ CallWidget::selectConversation( const lrc::api::conversation::Info& item, ...@@ -1229,7 +1229,7 @@ CallWidget::selectConversation( const lrc::api::conversation::Info& item,
void void
CallWidget::deselectConversation() CallWidget::deselectConversation()
{ {
if (LRCInstance::getSelectedConvUid().empty()) { if (LRCInstance::getCurrentConvUid().empty()) {
return; return;
} }
...@@ -1257,7 +1257,7 @@ CallWidget::updateConversationForNewContact(const std::string& convUid) ...@@ -1257,7 +1257,7 @@ CallWidget::updateConversationForNewContact(const std::string& convUid)
return; return;
} }
ui->ringContactLineEdit->setText(""); ui->ringContactLineEdit->setText("");
auto selectedUid = LRCInstance::getSelectedConvUid(); auto selectedUid = LRCInstance::getCurrentConvUid();
auto& conversation = LRCInstance::getConversationFromConvUid(convUid, {}, true); auto& conversation = LRCInstance::getConversationFromConvUid(convUid, {}, true);
if (!conversation.uid.empty()) { if (!conversation.uid.empty()) {
try { try {
...@@ -1313,15 +1313,16 @@ CallWidget::update() ...@@ -1313,15 +1313,16 @@ CallWidget::update()
} }
void void
CallWidget::connectAccount(const std::string& accId) CallWidget::connectAccount(const std::string& accountId)
{ {
try { try {
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accId); auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
auto callModel = accInfo.callModel.get();
QObject::disconnect(callStatusChangedConnection_); QObject::disconnect(callStatusChangedConnection_);
callStatusChangedConnection_ = QObject::connect(callModel, callStatusChangedConnection_ = QObject::connect(
accInfo.callModel.get(),
&lrc::api::NewCallModel::callStatusChanged, &lrc::api::NewCallModel::callStatusChanged,
[this, &accInfo, accId](const std::string& callId) { [this, accountId](const std::string& callId) {
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
auto& callModel = accInfo.callModel; auto& callModel = accInfo.callModel;
auto call = callModel->getCall(callId); auto call = callModel->getCall(callId);
switch (call.status) { switch (call.status) {
...@@ -1331,35 +1332,43 @@ CallWidget::connectAccount(const std::string& accId) ...@@ -1331,35 +1332,43 @@ CallWidget::connectAccount(const std::string& accId)
case lrc::api::call::Status::PEER_BUSY: case lrc::api::call::Status::PEER_BUSY:
case lrc::api::call::Status::TIMEOUT: case lrc::api::call::Status::TIMEOUT:
case lrc::api::call::Status::TERMINATING: { case lrc::api::call::Status::TERMINATING: {
LRCInstance::renderer()->removeDistantRenderer(callId);
ui->videoView->updateCall();
setCallPanelVisibility(false); setCallPanelVisibility(false);
showConversationView(); showConversationView();
break; break;
} }
case lrc::api::call::Status::CONNECTED: case lrc::api::call::Status::CONNECTED:
case lrc::api::call::Status::IN_PROGRESS: { case lrc::api::call::Status::IN_PROGRESS: {
auto convInfo = LRCInstance::getConversationFromCallId(callId, accId); auto convInfo = LRCInstance::getConversationFromCallId(callId, accountId);
if (!convInfo.uid.empty() && convInfo.uid == LRCInstance::getSelectedConvUid()) { if (!convInfo.uid.empty() && convInfo.uid == LRCInstance::getCurrentConvUid()) {
accInfo.conversationModel->selectConversation(convInfo.uid); accInfo.conversationModel->selectConversation(convInfo.uid);
} }
LRCInstance::renderer()->addDistantRenderer(convInfo.callId); LRCInstance::renderer()->addDistantRenderer(callId);
ui->videoView->updateCall();
break; break;
} }
case lrc::api::call::Status::PAUSED:
ui->videoView->resetPreview();
ui->videoView->updateCall();
default: default:
break; break;
} }
ui->smartList->update(); ui->smartList->update();
}); });
auto& contactModel = accInfo.contactModel; QObject::disconnect(contactAddedConnection_);
disconnect(contactAddedConnection_); contactAddedConnection_ = QObject::connect(
contactAddedConnection_ = connect(contactModel.get(), accInfo.contactModel.get(),
&lrc::api::ContactModel::contactAdded, &lrc::api::ContactModel::contactAdded,
[this, &contactModel, &accInfo](const std::string& contactUri) { [this, accountId](const std::string& contactUri) {
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
auto convModel = LRCInstance::getCurrentConversationModel(); auto convModel = LRCInstance::getCurrentConversationModel();
auto conversation = LRCInstance::getCurrentConversation(); auto conversation = LRCInstance::getCurrentConversation();
if (conversation.uid.empty()) { if (conversation.uid.empty()) {
return; return;
} }
if (contactUri == contactModel.get()->getContact(conversation.participants.at(0)).profileInfo.uri) { if (contactUri == accInfo.contactModel->getContact(conversation.participants.at(0)).profileInfo.uri) {
// update call screen // update call screen
auto avatarImg = QPixmap::fromImage(imageForConv(conversation.uid)); auto avatarImg = QPixmap::fromImage(imageForConv(conversation.uid));
ui->callingPhoto->setPixmap(avatarImg); ui->callingPhoto->setPixmap(avatarImg);
...@@ -1370,8 +1379,17 @@ CallWidget::connectAccount(const std::string& accId) ...@@ -1370,8 +1379,17 @@ CallWidget::connectAccount(const std::string& accId)
ui->messageView->printHistory(*convModel, conversation.interactions); ui->messageView->printHistory(*convModel, conversation.interactions);
} }
}); });
QObject::disconnect(addedToConferenceConnection_);
addedToConferenceConnection_ = QObject::connect(
accInfo.callModel.get(),
&NewCallModel::callAddedToConference,
[this](const std::string& callId, const std::string& confId) {
Q_UNUSED(callId);
LRCInstance::renderer()->addDistantRenderer(confId);
ui->videoView->updateCall();
});
} catch (...) { } catch (...) {
qWarning() << "Couldn't get account: " << accId.c_str(); qWarning() << "Couldn't get account: " << accountId.c_str();
} }
} }
......
...@@ -164,5 +164,6 @@ private: ...@@ -164,5 +164,6 @@ private:
QMetaObject::Connection interactionRemovedConnection_; QMetaObject::Connection interactionRemovedConnection_;
QMetaObject::Connection contactAddedConnection_; QMetaObject::Connection contactAddedConnection_;
QMetaObject::Connection callStatusChangedConnection_; QMetaObject::Connection callStatusChangedConnection_;
QMetaObject::Connection addedToConferenceConnection_;
}; };
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
ContactPicker::ContactPicker(QWidget *parent) : ContactPicker::ContactPicker(QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::ContactPicker), ui(new Ui::ContactPicker),
type_(Type::CONFERENCE) listModeltype_(SmartListModel::Type::CONFERENCE)
{ {
ui->setupUi(this); ui->setupUi(this);
...@@ -58,24 +58,34 @@ ContactPicker::on_smartList_clicked(const QModelIndex &index) ...@@ -58,24 +58,34 @@ ContactPicker::on_smartList_clicked(const QModelIndex &index)
void void
ContactPicker::accept() ContactPicker::accept()
{ {
auto idx = ui->smartList->currentIndex(); auto index = ui->smartList->currentIndex();
if (idx.isValid()) { if (index.isValid()) {
// get current call id and peer uri // let parent deal with this as this dialog will be destroyed
auto conversation = LRCInstance::getCurrentConversation(); switch (listModeltype_) {
if (conversation.uid.empty()) { case SmartListModel::Type::CONFERENCE:
{
auto sectionName = index.data(SmartListModel::Role::SectionName).value<QString>();
if (!sectionName.isEmpty()) {
smartListModel_->toggleSection(sectionName);
return; return;
} }
auto thisCallId = conversation.callId; auto convUid = index.data(SmartListModel::Role::UID).value<QString>().toStdString();
auto contactUri = idx.data(static_cast<int>(SmartListModel::Role::URI)).value<QString>().toStdString(); auto accId = index.data(SmartListModel::Role::AccountId).value<QString>().toStdString();
auto callId = LRCInstance::getCallIdForConversationUid(convUid, accId);
// let parent deal with this as this dialog will be destroyed if (!callId.empty()) {
switch (type_) { emit callWillJoinConference(callId);
case Type::CONFERENCE: } else {
emit contactWillJoinConference(thisCallId, contactUri); auto contactUri = index.data(SmartListModel::Role::URI).value<QString>().toStdString();
emit contactWillJoinConference(contactUri);
}
}
break; break;
case Type::TRANSFER: case SmartListModel::Type::TRANSFER:
emit contactWillDoTransfer(thisCallId, contactUri); {
auto contactUri = index.data(SmartListModel::Role::URI).value<QString>().toStdString();
emit contactWillDoTransfer(contactUri);
}
break; break;
default: default:
break; break;
...@@ -88,6 +98,9 @@ ContactPicker::accept() ...@@ -88,6 +98,9 @@ ContactPicker::accept()
void void
ContactPicker::on_ringContactLineEdit_textChanged(const QString &arg1) ContactPicker::on_ringContactLineEdit_textChanged(const QString &arg1)
{ {
if (listModeltype_ == SmartListModel::Type::CONFERENCE) {
smartListModel_->setConferenceableFilter(arg1.toStdString());
}
selectableProxyModel_->setFilterRegExp(QRegExp(arg1, Qt::CaseInsensitive, QRegExp::FixedString)); selectableProxyModel_->setFilterRegExp(QRegExp(arg1, Qt::CaseInsensitive, QRegExp::FixedString));
} }
...@@ -107,29 +120,20 @@ ContactPicker::setTitle(const QString& title) ...@@ -107,29 +120,20 @@ ContactPicker::setTitle(const QString& title)
} }
void void
ContactPicker::setType(const Type& type) ContactPicker::setType(const SmartListModel::Type& type)
{ {
type_ = type; listModeltype_ = type;
smartListModel_.reset(new SmartListModel(LRCInstance::getCurrAccId(), this, true)); smartListModel_.reset(new SmartListModel(LRCInstance::getCurrAccId(), this, type, LRCInstance::getCurrentConvUid()));
selectableProxyModel_->setSourceModel(smartListModel_.get()); selectableProxyModel_->setSourceModel(smartListModel_.get());
// adjust filter // adjust filter
switch (type_) { switch (listModeltype_) {
case Type::CONFERENCE: case SmartListModel::Type::CONFERENCE:
selectableProxyModel_->setPredicate( selectableProxyModel_->setPredicate(
[this](const QModelIndex& index, const QRegExp& regexp) { [this](const QModelIndex&, const QRegExp&) {
bool match = regexp.indexIn(index.data(Qt::DisplayRole).toString()) != -1; return true;
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString();
auto conversation = LRCInstance::getConversationFromConvUid(convUid);
if (conversation.uid.empty()) {
return false;
}
auto callModel = LRCInstance::getCurrentCallModel();
return match &&
!(callModel->hasCall(conversation.callId) || callModel->hasCall(conversation.confId)) &&
!index.parent().isValid();
}); });
break; break;
case Type::TRANSFER: case SmartListModel::Type::TRANSFER:
selectableProxyModel_->setPredicate( selectableProxyModel_->setPredicate(
[this](const QModelIndex& index, const QRegExp& regexp) { [this](const QModelIndex& index, const QRegExp& regexp) {
// Regex to remove current callee // Regex to remove current callee
......
...@@ -19,13 +19,13 @@ ...@@ -19,13 +19,13 @@
#pragma once #pragma once
#include <QDialog>
#include <QSortFilterProxyModel>
#include "smartlistmodel.h" #include "smartlistmodel.h"
#include "utils.h" #include "utils.h"
#include "lrcinstance.h" #include "lrcinstance.h"
#include <QDialog>
#include <QSortFilterProxyModel>
namespace Ui { namespace Ui {
class ContactPicker; class ContactPicker;
} }
...@@ -61,24 +61,19 @@ class ContactPicker : public QDialog ...@@ -61,24 +61,19 @@ class ContactPicker : public QDialog
Q_OBJECT; Q_OBJECT;
public: public:
enum class Type {
CONFERENCE,
TRANSFER,
COUNT__
};
explicit ContactPicker(QWidget *parent = 0); explicit ContactPicker(QWidget *parent = 0);
~ContactPicker(); ~ContactPicker();
void setTitle(const QString& title); void setTitle(const QString& title);
void setType(const Type& type); void setType(const SmartListModel::Type& type);
void setCurrentCalleeDisplayName(const QString& CalleeDisplayName); void setCurrentCalleeDisplayName(const QString& CalleeDisplayName);
protected: protected:
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event);
signals: signals:
void contactWillJoinConference(const std::string& callId, const std::string& contactUri); void contactWillJoinConference(const std::string& contactUri);
void contactWillDoTransfer(const std::string& callId, const std::string& contactUri); void callWillJoinConference(const std::string& callId);
void contactWillDoTransfer(const std::string& contactUri);
void willClose(QMouseEvent *event); void willClose(QMouseEvent *event);
protected slots: protected slots:
...@@ -93,7 +88,7 @@ private: ...@@ -93,7 +88,7 @@ private:
std::unique_ptr<SmartListModel> smartListModel_; std::unique_ptr<SmartListModel> smartListModel_;
SelectableProxyModel* selectableProxyModel_; SelectableProxyModel* selectableProxyModel_;
Type type_;
QString CalleeDisplayName_; QString CalleeDisplayName_;
SmartListModel::Type listModeltype_;
}; };
...@@ -57,6 +57,29 @@ ContactPickerItemDelegate::paint(QPainter* painter ...@@ -57,6 +57,29 @@ ContactPickerItemDelegate::paint(QPainter* painter
highlightMap_[index.row()] = option.state & QStyle::State_MouseOver; highlightMap_[index.row()] = option.state & QStyle::State_MouseOver;
} }
QRect &rect = opt.rect;
QString sectionName = index.data(static_cast<int>(SmartListModel::Role::SectionName)).value<QString>();
if (!sectionName.isEmpty()) {
painter->fillRect(option.rect, RingTheme::lightGrey_);
QFont font(painter->font());
QPen pen(painter->pen());
auto scalingRatio = MainWindow::instance().getCurrentScalingRatio();
if (scalingRatio > 1.0) {
font.setPointSize(fontSize_ - 2);
} else {
font.setPointSize(fontSize_);
}
font.setItalic(false);
font.setBold(false);
pen.setColor(RingTheme::lightBlack_);
painter->setPen(pen);
painter->setFont(font);
QMargins padding(4, 0, 0, 0);
painter->drawText(rect - padding, Qt::AlignVCenter | Qt::AlignLeft, sectionName);
return;
}
QColor presenceBorderColor = Qt::white; QColor presenceBorderColor = Qt::white;
auto rowHighlight = highlightMap_.find(index.row()); auto rowHighlight = highlightMap_.find(index.row());
if (selected) { if (selected) {
...@@ -67,8 +90,6 @@ ContactPickerItemDelegate::paint(QPainter* painter ...@@ -67,8 +90,6 @@ ContactPickerItemDelegate::paint(QPainter* painter
presenceBorderColor = RingTheme::smartlistHighlight_; presenceBorderColor = RingTheme::smartlistHighlight_;
} }
QRect &rect = opt.rect;
// Avatar drawing // Avatar drawing
opt.decorationSize = QSize(sizeImage_, sizeImage_); opt.decorationSize = QSize(sizeImage_, sizeImage_);
opt.decorationPosition = QStyleOptionViewItem::Left; opt.decorationPosition = QStyleOptionViewItem::Left;
...@@ -117,7 +138,11 @@ ContactPickerItemDelegate::sizeHint(const QStyleOptionViewItem& option, ...@@ -117,7 +138,11 @@ ContactPickerItemDelegate::sizeHint(const QStyleOptionViewItem& option,
const QModelIndex& index) const const QModelIndex& index) const
{ {
Q_UNUSED(option); Q_UNUSED(option);
Q_UNUSED(index); if (!index.data(static_cast<int>(SmartListModel::Role::SectionName))
.value<QString>()
.isEmpty()) {
return QSize(0, sectionCellHeight_);
}
return QSize(0, cellHeight_); return QSize(0, cellHeight_);
} }
...@@ -130,7 +155,6 @@ ContactPickerItemDelegate::paintRingContactItem(QPainter* painter, ...@@ -130,7 +155,6 @@ ContactPickerItemDelegate::paintRingContactItem(QPainter* painter,
Q_UNUSED(option); Q_UNUSED(option);
QFont font(painter->font()); QFont font(painter->font());
QPen pen(painter->pen()); QPen pen(painter->pen());
painter->setPen(pen);
auto scalingRatio = MainWindow::instance().getCurrentScalingRatio(); auto scalingRatio = MainWindow::instance().getCurrentScalingRatio();
if (scalingRatio > 1.0) { if (scalingRatio > 1.0) {
......
...@@ -39,6 +39,7 @@ private: ...@@ -39,6 +39,7 @@ private:
constexpr static int sizeImage_ = 48; constexpr static int sizeImage_ = 48;
constexpr static int cellHeight_ = 60; constexpr static int cellHeight_ = 60;
constexpr static int sectionCellHeight_ = 24;
constexpr static int dy_ = 6; constexpr static int dy_ = 6;
constexpr static int dx_ = 12; constexpr static int dx_ = 12;
constexpr static int fontSize_ = 11; constexpr static int fontSize_ = 11;
......
...@@ -122,15 +122,37 @@ public: ...@@ -122,15 +122,37 @@ public:
} }
return result; return result;
}; };
static std::string
getCallIdForConversationUid(const std::string& convUid, const std::string& accountId)
{
auto convInfo = LRCInstance::getConversationFromConvUid(convUid, accountId);
if (convInfo.uid.empty()) {
return {};
}
return convInfo.confId.empty() ? convInfo.callId : convInfo.confId;
}
static const call::Info*
getCallInfo(const std::string& callId, const std::string& accountId) {
try {
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
if (!accInfo.callModel->hasCall(callId)) {
return nullptr;
}
return &accInfo.callModel->getCall(callId);
} catch (...) {
return nullptr;
}
}
static const call::Info* static const call::Info*
getCallInfoForConversation(const conversation::Info& convInfo) { getCallInfoForConversation(const conversation::Info& convInfo) {
try { try {
auto accountId = convInfo.accountId; auto accountId = convInfo.accountId;
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId); auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId);
if (!accInfo.callModel->hasCall(convInfo.callId)) { auto callId = convInfo.confId.empty() ? convInfo.callId : convInfo.confId;
if (!accInfo.callModel->hasCall(callId)) {
return nullptr; return nullptr;
} }
return &accInfo.callModel->getCall(convInfo.callId); return &accInfo.callModel->getCall(callId);
} catch(...) { } catch(...) {
return nullptr; return nullptr;
} }
...@@ -194,7 +216,7 @@ public: ...@@ -194,7 +216,7 @@ public:
} }
static const conversation::Info& static const conversation::Info&
getCurrentConversation() { getCurrentConversation() {
return getConversationFromConvUid(getSelectedConvUid()); return getConversationFromConvUid(getCurrentConvUid());
} }
static ConversationModel* static ConversationModel*
...@@ -221,7 +243,7 @@ public: ...@@ -221,7 +243,7 @@ public:
settings.setValue(SettingsKey::selectedAccount, QString::fromStdString(accountId)); settings.setValue(SettingsKey::selectedAccount, QString::fromStdString(accountId));
}; };
static const std::string& getSelectedConvUid() { static const std::string& getCurrentConvUid() {
return instance().selectedConvUid_; return instance().selectedConvUid_;
}; };
......
...@@ -418,7 +418,7 @@ PrivateBridging::deleteInteraction(const QString& arg) ...@@ -418,7 +418,7 @@ PrivateBridging::deleteInteraction(const QString& arg)
uint64_t interactionUid = arg.toULongLong(&ok); uint64_t interactionUid = arg.toULongLong(&ok);
if (ok) { if (ok) {
LRCInstance::getCurrentConversationModel()->clearInteractionFromConversation( LRCInstance::getCurrentConversationModel()->clearInteractionFromConversation(
LRCInstance::getSelectedConvUid(), LRCInstance::getCurrentConvUid(),
interactionUid interactionUid
); );
} else { } else {
...@@ -434,7 +434,7 @@ PrivateBridging::retryInteraction(const QString& arg) ...@@ -434,7 +434,7 @@ PrivateBridging::retryInteraction(const QString& arg)
uint64_t interactionUid = arg.toULongLong(&ok); uint64_t interactionUid = arg.toULongLong(&ok);
if (ok) { if (ok) {
LRCInstance::getCurrentConversationModel()->retryInteraction( LRCInstance::getCurrentConversationModel()->retryInteraction(
LRCInstance::getSelectedConvUid(), LRCInstance::getCurrentConvUid(),
interactionUid interactionUid
); );
} else { } else {
...@@ -461,7 +461,7 @@ PrivateBridging::acceptFile(const QString& arg) ...@@ -461,7 +461,7 @@ PrivateBridging::acceptFile(const QString& arg)
auto interactionUid = std::stoull(arg.toStdString()); auto interactionUid = std::stoull(arg.toStdString());
lrc::api::datatransfer::Info info = {}; lrc::api::datatransfer::Info info = {};
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->getTransferInfo(interactionUid, info); LRCInstance::getCurrentConversationModel()->getTransferInfo(interactionUid, info);
// get full path // get full path
...@@ -490,7 +490,7 @@ PrivateBridging::refuseFile(const QString& arg) ...@@ -490,7 +490,7 @@ PrivateBridging::refuseFile(const QString& arg)
{ {
try { try {
auto interactionUid = std::stoull(arg.toStdString()); auto interactionUid = std::stoull(arg.toStdString());
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->cancelTransfer(convUid, interactionUid); LRCInstance::getCurrentConversationModel()->cancelTransfer(convUid, interactionUid);
} catch (...) { } catch (...) {
qDebug() << "JS bridging - exception during refuseFile:" << arg; qDebug() << "JS bridging - exception during refuseFile:" << arg;
...@@ -502,7 +502,7 @@ Q_INVOKABLE int ...@@ -502,7 +502,7 @@ Q_INVOKABLE int
PrivateBridging::sendMessage(const QString& arg) PrivateBridging::sendMessage(const QString& arg)
{ {
try { try {
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->sendMessage(convUid, arg.toStdString()); LRCInstance::getCurrentConversationModel()->sendMessage(convUid, arg.toStdString());
} catch (...) { } catch (...) {
qDebug() << "JS bridging - exception during sendMessage:" << arg; qDebug() << "JS bridging - exception during sendMessage:" << arg;
...@@ -533,7 +533,7 @@ PrivateBridging::sendImage(const QString& arg) ...@@ -533,7 +533,7 @@ PrivateBridging::sendImage(const QString& arg)
} }
try { try {
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->sendFile(convUid, path.toStdString(), fileName.toStdString()); LRCInstance::getCurrentConversationModel()->sendFile(convUid, path.toStdString(), fileName.toStdString());
} catch (...) { } catch (...) {
qDebug().noquote() << "JS bridging - exception during sendFile - base64 img" << "\n"; qDebug().noquote() << "JS bridging - exception during sendFile - base64 img" << "\n";
...@@ -545,7 +545,7 @@ PrivateBridging::sendImage(const QString& arg) ...@@ -545,7 +545,7 @@ PrivateBridging::sendImage(const QString& arg)
QFileInfo fi(arg); QFileInfo fi(arg);
QString fileName = fi.fileName(); QString fileName = fi.fileName();
try { try {
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->sendFile(convUid, arg.toStdString(), fileName.toStdString()); LRCInstance::getCurrentConversationModel()->sendFile(convUid, arg.toStdString(), fileName.toStdString());
} catch (...) { } catch (...) {
qDebug().noquote() << "JS bridging - exception during sendFile - image from path" << "\n"; qDebug().noquote() << "JS bridging - exception during sendFile - image from path" << "\n";
...@@ -562,7 +562,7 @@ PrivateBridging::sendFile(const QString&path) ...@@ -562,7 +562,7 @@ PrivateBridging::sendFile(const QString&path)
QFileInfo fi(path); QFileInfo fi(path);
QString fileName = fi.fileName(); QString fileName = fi.fileName();
try { try {
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->sendFile(convUid, path.toStdString(), fileName.toStdString()); LRCInstance::getCurrentConversationModel()->sendFile(convUid, path.toStdString(), fileName.toStdString());
} catch (...) { } catch (...) {
qDebug() << "JS bridging - exception during sendFile"; qDebug() << "JS bridging - exception during sendFile";
...@@ -604,7 +604,7 @@ Q_INVOKABLE int ...@@ -604,7 +604,7 @@ Q_INVOKABLE int
PrivateBridging::refuseInvitation() PrivateBridging::refuseInvitation()
{ {
try { try {
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->removeConversation(convUid, false); LRCInstance::getCurrentConversationModel()->removeConversation(convUid, false);
if (auto messageView = qobject_cast<MessageWebView*>(this->parent())) { if (auto messageView = qobject_cast<MessageWebView*>(this->parent())) {
messageView->setInvitation(false); messageView->setInvitation(false);
...@@ -620,7 +620,7 @@ Q_INVOKABLE int ...@@ -620,7 +620,7 @@ Q_INVOKABLE int
PrivateBridging::blockConversation() PrivateBridging::blockConversation()
{ {
try { try {
auto convUid = LRCInstance::getSelectedConvUid(); auto convUid = LRCInstance::getCurrentConvUid();
LRCInstance::getCurrentConversationModel()->removeConversation(convUid, true); LRCInstance::getCurrentConversationModel()->removeConversation(convUid, true);
if (auto messageView = qobject_cast<MessageWebView*>(this->parent())) { if (auto messageView = qobject_cast<MessageWebView*>(this->parent())) {
messageView->setInvitation(false); messageView->setInvitation(false);
......
...@@ -48,10 +48,15 @@ FrameWrapper::connectStartRendering() ...@@ -48,10 +48,15 @@ FrameWrapper::connectStartRendering()
&FrameWrapper::slotRenderingStarted); &FrameWrapper::slotRenderingStarted);
} }
void bool
FrameWrapper::startRendering() FrameWrapper::startRendering()
{ {
try {
renderer_ = const_cast<video::Renderer*>(&avModel_.getRenderer(id_)); renderer_ = const_cast<video::Renderer*>(&avModel_.getRenderer(id_));
} catch (std::out_of_range& e) {
qWarning() << e.what();
return false;
}
QObject::disconnect(renderConnections_.updated); QObject::disconnect(renderConnections_.updated);
QObject::disconnect(renderConnections_.stopped); QObject::disconnect(renderConnections_.stopped);
...@@ -67,6 +72,8 @@ FrameWrapper::startRendering() ...@@ -67,6 +72,8 @@ FrameWrapper::startRendering()
&AVModel::rendererStopped, &AVModel::rendererStopped,
this, this,
&FrameWrapper::slotRenderingStopped); &FrameWrapper::slotRenderingStopped);
return true;
} }
QImage* QImage*
...@@ -88,7 +95,10 @@ FrameWrapper::slotRenderingStarted(const std::string& id) ...@@ -88,7 +95,10 @@ FrameWrapper::slotRenderingStarted(const std::string& id)
return; return;
} }
startRendering(); if (!startRendering()) {
qWarning() << "Couldn't start rendering for id: " << id_.c_str();
return;
}
isRendering_ = true; isRendering_ = true;
...@@ -256,7 +266,9 @@ RenderManager::addDistantRenderer(const std::string& id) ...@@ -256,7 +266,9 @@ RenderManager::addDistantRenderer(const std::string& id)
// check if a FrameWrapper with this id exists // check if a FrameWrapper with this id exists
auto dfwIt = distantFrameWrapperMap_.find(id); auto dfwIt = distantFrameWrapperMap_.find(id);
if ( dfwIt != distantFrameWrapperMap_.end()) { if ( dfwIt != distantFrameWrapperMap_.end()) {
dfwIt->second->startRendering(); if (!dfwIt->second->startRendering()) {
qWarning() << "Couldn't start rendering for id: " << id.c_str();
}
} else { } else {
auto dfw = std::make_unique<FrameWrapper>(avModel_, id); auto dfw = std::make_unique<FrameWrapper>(avModel_, id);
......
...@@ -56,8 +56,9 @@ public: ...@@ -56,8 +56,9 @@ public:
/** /**
* Get a pointer to the renderer and reconnect the update/stopped * Get a pointer to the renderer and reconnect the update/stopped
* rendering connections for this object. * rendering connections for this object.
* @return whether the start succeeded or not
*/ */
void startRendering(); bool startRendering();
/** /**
* Get the most recently rendered frame as a QImage. * Get the most recently rendered frame as a QImage.
......
/*************************************************************************** /***************************************************************************
* Copyright (C) 2017-2019 by Savoir-faire Linux * * Copyright (C) 2017-2019 by Savoir-faire Linux *
* Author: Anthony Lonard <anthony.leonard@savoirfairelinux.com> * * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> *
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> * * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
...@@ -25,24 +25,41 @@ ...@@ -25,24 +25,41 @@
#include "globalinstances.h" #include "globalinstances.h"
#include "api/contactmodel.h" #include "api/contactmodel.h"
#include "api/conversationmodel.h"
#include <QDateTime> #include <QDateTime>
SmartListModel::SmartListModel(const std::string& accId, QObject *parent, bool contactList) SmartListModel::SmartListModel(const std::string& accId,
: QAbstractItemModel(parent), QObject *parent,
accId_(accId), SmartListModel::Type listModelType,
contactList_(contactList) const std::string& convUid)
: QAbstractItemModel(parent)
, accountId_(accId)
, listModelType_(listModelType)
, convUid_(convUid)
{ {
if (listModelType_ == Type::CONFERENCE) {
setConferenceableFilter();
}
} }
int SmartListModel::rowCount(const QModelIndex &parent) const int SmartListModel::rowCount(const QModelIndex &parent) const
{ {
if (!parent.isValid()) { if (!parent.isValid()) {
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accId_); auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
if (contactList_) { auto& convModel = accInfo.conversationModel;
if (listModelType_ == Type::TRANSFER) {
auto filterType = accInfo.profileInfo.type; auto filterType = accInfo.profileInfo.type;
return accInfo.conversationModel->getFilteredConversations(filterType).size(); return convModel->getFilteredConversations(filterType).size();
} else if (listModelType_ == Type::CONFERENCE) {
auto calls = conferenceables_.at(ConferenceableItem::CALL);
auto contacts = conferenceables_.at(ConferenceableItem::CONTACT);
auto rowCount = contacts.size();
if (calls.size()) {
rowCount = 2;
rowCount += sectionState_[tr("Calls")] ? calls.size() : 0;
rowCount += sectionState_[tr("Contacts")] ? contacts.size() : 0;
}
return rowCount;
} }
return accInfo.conversationModel->allFilteredConversations().size(); return accInfo.conversationModel->allFilteredConversations().size();
} }
...@@ -61,41 +78,122 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const ...@@ -61,41 +78,122 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const
return QVariant(); return QVariant();
} }
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accId_); try {
auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
conversation::Info item; auto& convModel = accountInfo.conversationModel;
if (contactList_) { lrc::api::conversation::Info item;
auto filterType = accInfo.profileInfo.type; if (listModelType_ == Type::TRANSFER) {
item = accInfo.conversationModel->getFilteredConversations(filterType).at(index.row()); auto filterType = accountInfo.profileInfo.type;
item = convModel->getFilteredConversations(filterType).at(index.row());
return getConversationItemData(item, accountInfo, role);
} else if (listModelType_ == Type::CONFERENCE) {
auto calls = conferenceables_.at(ConferenceableItem::CALL);
auto contacts = conferenceables_.at(ConferenceableItem::CONTACT);
std::string itemConvUid{}, itemAccId{};
if (calls.size() == 0) {
itemConvUid = contacts.at(index.row()).at(0).convId;
itemAccId = contacts.at(index.row()).at(0).accountId;
} else { } else {
item = accInfo.conversationModel->filteredConversation(index.row()); bool callsOpen = sectionState_[tr("Calls")];
bool contactsOpen = sectionState_[tr("Contacts")];
auto callSectionEnd = callsOpen ? calls.size() + 1 : 1;
auto contactSectionEnd = contactsOpen ?
callSectionEnd + contacts.size() + 1 :
callSectionEnd + 1;
if (index.row() < callSectionEnd) {
if (index.row() == 0) {
return QVariant(role == Role::SectionName ?
(callsOpen ? "➖ " : "➕ ") + QString(tr("Calls")) :
"");
} else {
auto idx = index.row() - 1;
itemConvUid = calls.at(idx).at(0).convId;
itemAccId = calls.at(idx).at(0).accountId;
}
} else if (index.row() < contactSectionEnd) {
if (index.row() == callSectionEnd) {
return QVariant(role == Role::SectionName ?
(contactsOpen ? "➖ " : "➕ ") + QString(tr("Contacts")) :
"");
} else {
auto idx = index.row() - (callSectionEnd + 1);
itemConvUid = contacts.at(idx).at(0).convId;
itemAccId = contacts.at(idx).at(0).accountId;
}
}
}
if (role == Role::AccountId) {
return QVariant(QString::fromStdString(itemAccId));
}
item = LRCInstance::getConversationFromConvUid(itemConvUid, itemAccId);
auto& itemAccountInfo = LRCInstance::accountModel().getAccountInfo(itemAccId);
return getConversationItemData(item, itemAccountInfo, role);
} else if (listModelType_ == Type::CONVERSATION) {
item = convModel->filteredConversation(index.row());
return getConversationItemData(item, accountInfo, role);
}
} catch (const std::exception& e) {
qWarning() << e.what();
}
return QVariant();
} }
if (item.participants.size() > 0) { void
try { SmartListModel::setConferenceableFilter(const std::string& filter)
{
beginResetModel();
auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
auto& convModel = accountInfo.conversationModel;
conferenceables_ = convModel->getConferenceableConversations(convUid_, filter);
sectionState_[tr("Calls")] = true;
sectionState_[tr("Contacts")] = true;
endResetModel();
}
void
SmartListModel::toggleSection(const QString& section)
{
beginResetModel();
if (section.contains(tr("Calls"))) {
sectionState_[tr("Calls")] ^= true;
} else if (section.contains(tr("Contacts"))) {
sectionState_[tr("Contacts")] ^= true;
}
endResetModel();
}
QVariant
SmartListModel::getConversationItemData(const conversation::Info& item,
const account::Info& accountInfo,
int role) const
{
if (item.participants.size() <= 0) {
return QVariant();
}
auto& contactModel = accountInfo.contactModel;
switch (role) { switch (role) {
case Role::Picture: case Role::Picture:
case Qt::DecorationRole: case Qt::DecorationRole:
return GlobalInstances::pixmapManipulator().decorationRole(item, accInfo); return GlobalInstances::pixmapManipulator().decorationRole(item, accountInfo);
case Role::DisplayName: case Role::DisplayName:
case Qt::DisplayRole: case Qt::DisplayRole:
{ {
auto& contact = accInfo.contactModel->getContact(item.participants[0]); auto& contact = contactModel->getContact(item.participants[0]);
return QVariant(QString::fromStdString(Utils::bestNameForContact(contact))); return QVariant(QString::fromStdString(Utils::bestNameForContact(contact)));
} }
case Role::DisplayID: case Role::DisplayID:
{ {
auto& contact = accInfo.contactModel->getContact(item.participants[0]); auto& contact = contactModel->getContact(item.participants[0]);
return QVariant(QString::fromStdString(Utils::bestIdForContact(contact))); return QVariant(QString::fromStdString(Utils::bestIdForContact(contact)));
} }
case Role::Presence: case Role::Presence:
{ {
auto& contact = accInfo.contactModel->getContact(item.participants[0]); auto& contact = contactModel->getContact(item.participants[0]);
return QVariant(contact.isPresent); return QVariant(contact.isPresent);
} }
case Role::URI: case Role::URI:
{ {
auto& contact = accInfo.contactModel->getContact(item.participants[0]); auto& contact = contactModel->getContact(item.participants[0]);
return QVariant(QString::fromStdString(contact.profileInfo.uri)); return QVariant(QString::fromStdString(contact.profileInfo.uri));
} }
case Role::UnreadMessagesCount: case Role::UnreadMessagesCount:
...@@ -111,7 +209,7 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const ...@@ -111,7 +209,7 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const
return QVariant(Utils::toUnderlyingValue(item.interactions.at(item.lastMessageUid).type)); return QVariant(Utils::toUnderlyingValue(item.interactions.at(item.lastMessageUid).type));
case Role::ContactType: case Role::ContactType:
{ {
auto& contact = accInfo.contactModel->getContact(item.participants[0]); auto& contact = contactModel->getContact(item.participants[0]);
return QVariant(Utils::toUnderlyingValue(contact.profileInfo.type)); return QVariant(Utils::toUnderlyingValue(contact.profileInfo.type));
} }
case Role::UID: case Role::UID:
...@@ -139,8 +237,8 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const ...@@ -139,8 +237,8 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const
} }
return QVariant(); return QVariant();
} }
} case Role::SectionName:
} catch (...) {} return QVariant(QString());
} }
return QVariant(); return QVariant();
} }
...@@ -168,21 +266,20 @@ Qt::ItemFlags SmartListModel::flags(const QModelIndex &index) const ...@@ -168,21 +266,20 @@ Qt::ItemFlags SmartListModel::flags(const QModelIndex &index) const
{ {
auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable; auto flags = QAbstractItemModel::flags(index) | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable;
auto type = Utils::toEnum<lrc::api::profile::Type>(data(index, Role::ContactType).value<int>()); auto type = Utils::toEnum<lrc::api::profile::Type>(data(index, Role::ContactType).value<int>());
auto displayName = data(index, Role::DisplayName).value<QString>();
auto uid = data(index, Role::UID).value<QString>(); auto uid = data(index, Role::UID).value<QString>();
if (!index.isValid()) { if (!index.isValid()) {
return QAbstractItemModel::flags(index); return QAbstractItemModel::flags(index);
} else if ( type == lrc::api::profile::Type::TEMPORARY && } else if ( (type == lrc::api::profile::Type::TEMPORARY &&
uid.isEmpty()) { uid.isEmpty())) {
flags &= ~(Qt::ItemIsSelectable); flags &= ~(Qt::ItemIsSelectable);
} }
return flags; return flags;
} }
void void
SmartListModel::setAccount(const std::string& accId) SmartListModel::setAccount(const std::string& accountId)
{ {
beginResetModel(); beginResetModel();
accId_ = accId; accountId_ = accountId;
endResetModel(); endResetModel();
} }
/*************************************************************************** /**************************************************************************
* Copyright (C) 2017-2019 by Savoir-faire Linux * * Copyright (C) 2017-2019 by Savoir-faire Linux *
* Author: Anthony L�onard <anthony.leonard@savoirfairelinux.com> * * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> *
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -17,15 +18,14 @@ ...@@ -17,15 +18,14 @@
**************************************************************************/ **************************************************************************/
#pragma once #pragma once
// Qt include
#include <QAbstractItemModel>
// LRC
#include "api/account.h" #include "api/account.h"
#include "api/conversation.h" #include "api/conversation.h"
#include "api/conversationmodel.h"
#include "api/contact.h" #include "api/contact.h"
namespace lrc { namespace api { class ConversationModel; } } #include <QAbstractItemModel>
using namespace lrc::api;
class SmartListModel : public QAbstractItemModel class SmartListModel : public QAbstractItemModel
{ {
...@@ -35,6 +35,13 @@ public: ...@@ -35,6 +35,13 @@ public:
using ConversationInfo = lrc::api::conversation::Info; using ConversationInfo = lrc::api::conversation::Info;
using ContactInfo = lrc::api::contact::Info; using ContactInfo = lrc::api::contact::Info;
enum class Type {
CONVERSATION,
CONFERENCE,
TRANSFER,
COUNT__
};
enum Role { enum Role {
DisplayName = Qt::UserRole + 1, DisplayName = Qt::UserRole + 1,
DisplayID, DisplayID,
...@@ -49,10 +56,15 @@ public: ...@@ -49,10 +56,15 @@ public:
UID, UID,
ContextMenuOpen, ContextMenuOpen,
InCall, InCall,
CallStateStr CallStateStr,
SectionName,
AccountId
}; };
explicit SmartListModel(const std::string& accId, QObject *parent = 0, bool contactList = false); explicit SmartListModel(const std::string& accId,
QObject *parent = 0,
SmartListModel::Type listModelType = Type::CONVERSATION,
const std::string& convUid = {});
// QAbstractItemModel // QAbstractItemModel
int rowCount(const QModelIndex &parent = QModelIndex()) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override;
...@@ -63,11 +75,22 @@ public: ...@@ -63,11 +75,22 @@ public:
Qt::ItemFlags flags(const QModelIndex &index) const; Qt::ItemFlags flags(const QModelIndex &index) const;
void setAccount(const std::string& accId); void setAccount(const std::string& accId);
void setConferenceableFilter(const std::string& filter = {});
void toggleSection(const QString& section);
// hack for context menu highlight retention // hack for context menu highlight retention
bool isContextMenuOpen{ false }; bool isContextMenuOpen{ false };
private: private:
std::string accId_; std::string accountId_;
bool contactList_;
QVariant getConversationItemData(const ConversationInfo& item,
const AccountInfo& accountInfo,
int role) const;
// list sectioning
std::string convUid_;
Type listModelType_;
QMap<QString, bool> sectionState_;
std::map<ConferenceableItem, ConferenceableValue> conferenceables_;
}; };
\ No newline at end of file
...@@ -188,7 +188,7 @@ QWidget#messageViewLayoutWidget, QWidget#welcomePage { ...@@ -188,7 +188,7 @@ QWidget#messageViewLayoutWidget, QWidget#welcomePage {
QPushButton#holdButton, QPushButton#chatButton, QPushButton#noMicButton, QPushButton#noVideoButton, QPushButton#hangupButton, QPushButton#holdButton, QPushButton#chatButton, QPushButton#noMicButton, QPushButton#noVideoButton, QPushButton#hangupButton,
QPushButton#transferButton, QPushButton#addPersonButton, QPushButton#joinButton, QPushButton#transferButton, QPushButton#addPersonButton, QPushButton#joinButton,
QPushButton#qualityButton, QPushButton#recButton, QPushButton#transferCallButton, QPushButton#qualityButton, QPushButton#recButton, QPushButton#transferCallButton,
QPushButton#sipInputPanelButton { QPushButton#sipInputPanelButton, QPushButton#addToConferenceButton {
background-color: transparent; background-color: transparent;
border-radius: 18px; border-radius: 18px;
border: solid 1px; border: solid 1px;
...@@ -198,7 +198,7 @@ QPushButton#holdButton:hover, QPushButton#chatButton:hover, QPushButton#noMicBut ...@@ -198,7 +198,7 @@ QPushButton#holdButton:hover, QPushButton#chatButton:hover, QPushButton#noMicBut
QPushButton#noVideoButton:hover, QPushButton#transferButton:hover, QPushButton#addPersonButton:hover, QPushButton#noVideoButton:hover, QPushButton#transferButton:hover, QPushButton#addPersonButton:hover,
QPushButton#joinButton:hover, QPushButton#qualityButton:hover, QPushButton#addToContactButton:hover, QPushButton#joinButton:hover, QPushButton#qualityButton:hover, QPushButton#addToContactButton:hover,
QPushButton#recButton:hover, QPushButton#transferCallButton:hover, QPushButton#recButton:hover, QPushButton#transferCallButton:hover,
QPushButton#sipInputPanelButton:hover { QPushButton#sipInputPanelButton:hover, QPushButton#addToConferenceButton:hover {
background-color: transparent; background-color: transparent;
border-radius: 18px; border-radius: 18px;
border: solid 1px; border: solid 1px;
...@@ -207,7 +207,7 @@ QPushButton#sipInputPanelButton:hover { ...@@ -207,7 +207,7 @@ QPushButton#sipInputPanelButton:hover {
QPushButton#holdButton:pressed, QPushButton#chatButton:pressed, QPushButton#noMicButton:pressed, QPushButton#hangupButton:pressed, QPushButton#holdButton:pressed, QPushButton#chatButton:pressed, QPushButton#noMicButton:pressed, QPushButton#hangupButton:pressed,
QPushButton#noVideoButton:pressed, QPushButton#transferButton:pressed, QPushButton#addPersonButton:pressed, QPushButton#noVideoButton:pressed, QPushButton#transferButton:pressed, QPushButton#addPersonButton:pressed,
QPushButton#joinButton:pressed, QPushButton#qualityButton:pressed, QPushButton#addToContactButton:pressed, QPushButton#joinButton:pressed, QPushButton#qualityButton:pressed, QPushButton#addToContactButton:pressed,
QPushButton#recButton:pressed { QPushButton#recButton:pressed, QPushButton#addToConferenceButton:pressed {
background-color: transparent; background-color: transparent;
border-radius: 18px; border-radius: 18px;
border: solid 1px; border: solid 1px;
...@@ -216,7 +216,7 @@ QPushButton#recButton:pressed { ...@@ -216,7 +216,7 @@ QPushButton#recButton:pressed {
QPushButton#holdButton:checked, QPushButton#noMicButton:checked, QPushButton#hangupButton:checked, QPushButton#holdButton:checked, QPushButton#noMicButton:checked, QPushButton#hangupButton:checked,
QPushButton#noVideoButton:checked, QPushButton#recButton:checked, QPushButton#noVideoButton:checked, QPushButton#recButton:checked,
QPushButton#chatButton:checked, QPushButton#transferCallButton:checked, QPushButton#chatButton:checked, QPushButton#transferCallButton:checked,
QPushButton#sipInputPanelButton:checked { QPushButton#sipInputPanelButton:checked, QPushButton#addToConferenceButton:checked {
background-color: transparent; background-color: transparent;
border-radius: 18px; border-radius: 18px;
border: solid 1px; border: solid 1px;
...@@ -851,3 +851,7 @@ QLabel#nameLabel { ...@@ -851,3 +851,7 @@ QLabel#nameLabel {
qproperty-alignment: AlignCenter; qproperty-alignment: AlignCenter;
color: white; color: white;
} }
QWidget#videoPage {
background: black;
}
...@@ -50,13 +50,21 @@ VideoOverlay::VideoOverlay(QWidget* parent) : ...@@ -50,13 +50,21 @@ VideoOverlay::VideoOverlay(QWidget* parent) :
ui->transferCallButton->setVisible(false); ui->transferCallButton->setVisible(false);
ui->transferCallButton->setCheckable(true); ui->transferCallButton->setCheckable(true);
ui->addToConferenceButton->setVisible(true);
ui->addToConferenceButton->setCheckable(true);
contactPicker_->setVisible(false); contactPicker_->setVisible(false);
contactPicker_->setTitle(QObject::tr("Select peer to transfer to"));
sipInputPanel_->setVisible(false); sipInputPanel_->setVisible(false);
connect(contactPicker_, &ContactPicker::contactWillDoTransfer, this, &VideoOverlay::slotWillDoTransfer); connect(contactPicker_, &ContactPicker::contactWillJoinConference,
connect(sipInputPanel_, &SipInputPanel::sipInputPanelClicked, this, &VideoOverlay::slotSIPInputPanelClicked); this, &VideoOverlay::slotContactWillJoinConference);
connect(contactPicker_, &ContactPicker::callWillJoinConference,
this, &VideoOverlay::slotCallWillJoinConference);
connect(contactPicker_, &ContactPicker::contactWillDoTransfer,
this, &VideoOverlay::slotWillDoTransfer);
connect(sipInputPanel_, &SipInputPanel::sipInputPanelClicked,
this, &VideoOverlay::slotSIPInputPanelClicked);
// fading mechanism // fading mechanism
auto effect = new QGraphicsOpacityEffect(this); auto effect = new QGraphicsOpacityEffect(this);
...@@ -124,59 +132,81 @@ VideoOverlay::fadeOverlayOut() ...@@ -124,59 +132,81 @@ VideoOverlay::fadeOverlayOut()
} }
void void
VideoOverlay::callStarted(const std::string& callId) VideoOverlay::updateCall(const conversation::Info& convInfo)
{ {
callId_ = callId; accountId_ = convInfo.accountId;
convUid_ = convInfo.uid;
setTime(); setTime();
connect(oneSecondTimer_, &QTimer::timeout, this, &VideoOverlay::setTime); QObject::disconnect(oneSecondTimer_);
QObject::connect(oneSecondTimer_, &QTimer::timeout,
this, &VideoOverlay::setTime);
oneSecondTimer_->start(1000); oneSecondTimer_->start(1000);
showOverlay(); showOverlay();
fadeTimer_.start(startfadeOverlayTime_); fadeTimer_.start(startfadeOverlayTime_);
}
void // close chat panel
VideoOverlay::setName(const QString& name) emit setChatVisibility(false);
{
ui->nameLabel->setText(name); auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
auto& convModel = accInfo.conversationModel;
auto call = LRCInstance::getCallInfoForConversation(convInfo);
if (!call) {
return;
} }
void auto bestName = QString::fromStdString(
VideoOverlay::setPauseState(bool state) Utils::bestNameForConversation(convInfo, *convModel));
{ contactPicker_->setCurrentCalleeDisplayName(bestName);
ui->onHoldLabel->setVisible(state); ui->nameLabel->setText(bestName);
bool isPaused = call->status == lrc::api::call::Status::PAUSED;
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);
//Set irrelevant buttons invisible
ui->noVideoButton->setVisible(!isAudioOnly);
// Block the signals of buttons
Utils::whileBlocking(ui->noMicButton)->setOverlayButtonChecked(isAudioMuted);
Utils::whileBlocking(ui->noVideoButton)->setOverlayButtonChecked(isVideoMuted);
Utils::whileBlocking(ui->recButton)->setOverlayButtonChecked(isRecording);
Utils::whileBlocking(ui->holdButton)->setOverlayButtonChecked(isPaused);
Utils::whileBlocking(ui->onHoldLabel)->setVisible(isPaused);
bool isSIP = accInfo.profileInfo.type == lrc::api::profile::Type::SIP;
ui->addToConferenceButton->setVisible(!isSIP);
ui->transferCallButton->setVisible(isSIP);
ui->sipInputPanelButton->setVisible(isSIP);
} }
void void
VideoOverlay::setTime() VideoOverlay::setTime()
{ {
if (callId_.empty()) { auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if (callId.empty() || !LRCInstance::getCurrentCallModel()->hasCall(callId)) {
return; return;
} }
try { auto callInfo = LRCInstance::getCurrentCallModel()->getCall(callId);
auto callInfo = LRCInstance::getCurrentCallModel()->getCall(callId_);
if (callInfo.status == lrc::api::call::Status::IN_PROGRESS || if (callInfo.status == lrc::api::call::Status::IN_PROGRESS ||
callInfo.status == lrc::api::call::Status::PAUSED) { callInfo.status == lrc::api::call::Status::PAUSED) {
int numSeconds = std::chrono::duration_cast<std::chrono::seconds>( auto timeString = LRCInstance::getCurrentCallModel()->getFormattedCallDuration(callId);
std::chrono::steady_clock::now() - callInfo.startTime).count(); ui->timerLabel->setText(QString::fromStdString(timeString));
QTime t(0, 0, numSeconds);
ui->timerLabel->setText(t.toString(numSeconds > 3600 ? "hh:mm:ss" : "mm:ss"));
}
} catch (...) { }
} }
void
VideoOverlay::setVideoMuteVisibility(bool visible)
{
ui->noVideoButton->setVisible(visible);
} }
bool bool
VideoOverlay::shouldShowOverlay() VideoOverlay::shouldShowOverlay()
{ {
if (!LRCInstance::getCurrentCallModel()->hasCall(callId_)) { auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if (callId.empty() || !LRCInstance::getCurrentCallModel()->hasCall(callId)) {
return false; return false;
} }
auto callInfo = LRCInstance::getCurrentCallModel()->getCall(callId_); auto callInfo = LRCInstance::getCurrentCallModel()->getCall(callId);
bool hoveringOnButtons = ui->bottomButtons->underMouse() || ui->topInfoBar->underMouse(); bool hoveringOnButtons = ui->bottomButtons->underMouse() || ui->topInfoBar->underMouse();
return hoveringOnButtons || return hoveringOnButtons ||
(callInfo.status == lrc::api::call::Status::PAUSED) || (callInfo.status == lrc::api::call::Status::PAUSED) ||
...@@ -190,12 +220,6 @@ VideoOverlay::simulateShowChatview(bool checked) ...@@ -190,12 +220,6 @@ VideoOverlay::simulateShowChatview(bool checked)
ui->chatButton->setChecked(checked); ui->chatButton->setChecked(checked);
} }
bool
VideoOverlay::getShowChatView()
{
return ui->chatButton->isChecked();
}
void void
VideoOverlay::on_hangupButton_clicked() VideoOverlay::on_hangupButton_clicked()
{ {
...@@ -220,11 +244,15 @@ VideoOverlay::on_holdButton_toggled(bool checked) ...@@ -220,11 +244,15 @@ VideoOverlay::on_holdButton_toggled(bool checked)
{ {
// why is 'checked' unused? // why is 'checked' unused?
Q_UNUSED(checked); Q_UNUSED(checked);
auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if (callId.empty() || !LRCInstance::getCurrentCallModel()->hasCall(callId)) {
return;
}
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
bool onHold { false }; bool onHold { false };
if (callModel->hasCall(callId_)) { if (callModel->hasCall(callId)) {
callModel->togglePause(callId_); callModel->togglePause(callId);
onHold = callModel->getCall(callId_).status == lrc::api::call::Status::PAUSED; onHold = callModel->getCall(callId).status == lrc::api::call::Status::PAUSED;
} }
ui->onHoldLabel->setVisible(onHold); ui->onHoldLabel->setVisible(onHold);
} }
...@@ -233,9 +261,13 @@ void ...@@ -233,9 +261,13 @@ void
VideoOverlay::on_noMicButton_toggled(bool checked) VideoOverlay::on_noMicButton_toggled(bool checked)
{ {
Q_UNUSED(checked); Q_UNUSED(checked);
auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if (callId.empty() || !LRCInstance::getCurrentCallModel()->hasCall(callId)) {
return;
}
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
if (callModel->hasCall(callId_)) { if (callModel->hasCall(callId)) {
callModel->toggleMedia(callId_, lrc::api::NewCallModel::Media::AUDIO); callModel->toggleMedia(callId, lrc::api::NewCallModel::Media::AUDIO);
} }
} }
...@@ -243,9 +275,13 @@ void ...@@ -243,9 +275,13 @@ void
VideoOverlay::on_noVideoButton_toggled(bool checked) VideoOverlay::on_noVideoButton_toggled(bool checked)
{ {
Q_UNUSED(checked); Q_UNUSED(checked);
auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if (callId.empty() || !LRCInstance::getCurrentCallModel()->hasCall(callId)) {
return;
}
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
if (callModel->hasCall(callId_)) { if (callModel->hasCall(callId)) {
callModel->toggleMedia(callId_, lrc::api::NewCallModel::Media::VIDEO); callModel->toggleMedia(callId, lrc::api::NewCallModel::Media::VIDEO);
} }
emit videoMuteStateChanged(checked); emit videoMuteStateChanged(checked);
} }
...@@ -253,26 +289,68 @@ VideoOverlay::on_noVideoButton_toggled(bool checked) ...@@ -253,26 +289,68 @@ VideoOverlay::on_noVideoButton_toggled(bool checked)
void void
VideoOverlay::on_recButton_clicked() VideoOverlay::on_recButton_clicked()
{ {
auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if (callId.empty() || !LRCInstance::getCurrentCallModel()->hasCall(callId)) {
return;
}
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
if (callModel->hasCall(callId_)) { if (callModel->hasCall(callId)) {
callModel->toggleAudioRecord(callId_); callModel->toggleAudioRecord(callId);
} }
} }
void void
VideoOverlay::setTransferCallAndSIPPanelAvailability(bool visible) VideoOverlay::on_addToConferenceButton_toggled(bool checked)
{ {
ui->transferCallButton->setVisible(visible); auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
ui->sipInputPanelButton->setVisible(visible); if ( callId.empty() ||
!LRCInstance::getCurrentCallModel()->hasCall(callId) ||
!checked) {
return;
}
contactPicker_->setType(SmartListModel::Type::CONFERENCE);
contactPicker_->setTitle(QObject::tr("Add to conference"));
QPoint globalPos_button = mapToGlobal(ui->addToConferenceButton->pos());
QPoint globalPos_bottomButtons = mapToGlobal(ui->bottomButtons->pos());
contactPicker_->move(globalPos_button.x(), globalPos_bottomButtons.y() - contactPicker_->height());
// receive the signal that ensure the button checked status is correct and contactpicker
// is properly hidden
Utils::oneShotConnect(contactPicker_, &ContactPicker::willClose,
[this](QMouseEvent* event) {
contactPicker_->hide();
// check if current mouse position is on button
auto relativeClickPos = ui->addToConferenceButton->mapFromGlobal(event->globalPos());
if (!ui->addToConferenceButton->rect().contains(relativeClickPos)) {
ui->addToConferenceButton->setChecked(false);
ui->addToConferenceButton->resetToOriginal();
}
});
// for esc key, receive reject signal
Utils::oneShotConnect(contactPicker_, &QDialog::rejected,
[this] {
ui->addToConferenceButton->setChecked(false);
ui->addToConferenceButton->resetToOriginal();
});
contactPicker_->show();
} }
void void
VideoOverlay::on_transferCallButton_toggled(bool checked) VideoOverlay::on_transferCallButton_toggled(bool checked)
{ {
if (callId_.empty() || !checked) { auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if (callId.empty() ||
!LRCInstance::getCurrentCallModel()->hasCall(callId) ||
!checked) {
return; return;
} }
contactPicker_->setType(ContactPicker::Type::TRANSFER); contactPicker_->setType(SmartListModel::Type::TRANSFER);
contactPicker_->setTitle(QObject::tr("Select peer to transfer to"));
QPoint globalPos_button = mapToGlobal(ui->transferCallButton->pos()); QPoint globalPos_button = mapToGlobal(ui->transferCallButton->pos());
QPoint globalPos_bottomButtons = mapToGlobal(ui->bottomButtons->pos()); QPoint globalPos_bottomButtons = mapToGlobal(ui->bottomButtons->pos());
...@@ -303,11 +381,19 @@ VideoOverlay::on_transferCallButton_toggled(bool checked) ...@@ -303,11 +381,19 @@ VideoOverlay::on_transferCallButton_toggled(bool checked)
} }
void void
VideoOverlay::slotWillDoTransfer(const std::string& callId, const std::string& contactUri) VideoOverlay::slotWillDoTransfer(const std::string& contactUri)
{ {
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
contactPicker_->hide(); contactPicker_->hide();
ui->transferCallButton->setChecked(false); ui->transferCallButton->setChecked(false);
ui->transferCallButton->resetToOriginal();
auto conversation = LRCInstance::getCurrentConversation();
if (conversation.uid.empty()) {
return;
}
auto callId = conversation.confId.empty() ? conversation.callId : conversation.confId;
std::string destCallId; std::string destCallId;
try { try {
...@@ -331,28 +417,45 @@ VideoOverlay::slotWillDoTransfer(const std::string& callId, const std::string& c ...@@ -331,28 +417,45 @@ VideoOverlay::slotWillDoTransfer(const std::string& callId, const std::string& c
} }
void void
VideoOverlay::setCurrentSelectedCalleeDisplayName(const QString& CalleeDisplayName) VideoOverlay::slotContactWillJoinConference(const std::string& contactUri)
{ {
contactPicker_->setCurrentCalleeDisplayName(CalleeDisplayName); auto callModel = LRCInstance::getCurrentCallModel();
contactPicker_->hide();
ui->addToConferenceButton->setChecked(false);
ui->addToConferenceButton->resetToOriginal();
auto conversation = LRCInstance::getCurrentConversation();
auto call = LRCInstance::getCallInfoForConversation(conversation);
if (!call) {
return;
}
callModel->callAndAddParticipant(contactUri, call->id, call->isAudioOnly);
} }
void void
VideoOverlay::resetOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding, bool isAudioOnly) VideoOverlay::slotCallWillJoinConference(const std::string& callId)
{ {
//Set irrelevant buttons invisible auto callModel = LRCInstance::getCurrentCallModel();
ui->noVideoButton->setVisible(!isAudioOnly); contactPicker_->hide();
// Block the signals of buttons ui->addToConferenceButton->setChecked(false);
Utils::whileBlocking(ui->noMicButton)->setOverlayButtonChecked(isAudioMuted); ui->addToConferenceButton->resetToOriginal();
Utils::whileBlocking(ui->noVideoButton)->setOverlayButtonChecked(isVideoMuted);
Utils::whileBlocking(ui->recButton)->setOverlayButtonChecked(isRecording); auto conversation = LRCInstance::getCurrentConversation();
Utils::whileBlocking(ui->holdButton)->setOverlayButtonChecked(isHolding); if (conversation.uid.empty()) {
Utils::whileBlocking(ui->onHoldLabel)->setVisible(isHolding); return;
}
auto thisCallId = conversation.confId.empty() ? conversation.callId : conversation.confId;
callModel->joinCalls(thisCallId, callId);
} }
void void
VideoOverlay::on_sipInputPanelButton_toggled(bool checked) VideoOverlay::on_sipInputPanelButton_toggled(bool checked)
{ {
if (callId_.empty() || !checked) { auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if (callId.empty() ||
!LRCInstance::getCurrentCallModel()->hasCall(callId) ||
!checked) {
return; return;
} }
...@@ -387,16 +490,22 @@ VideoOverlay::on_sipInputPanelButton_toggled(bool checked) ...@@ -387,16 +490,22 @@ VideoOverlay::on_sipInputPanelButton_toggled(bool checked)
void void
VideoOverlay::slotSIPInputPanelClicked(const int& id) VideoOverlay::slotSIPInputPanelClicked(const int& id)
{ {
auto callId = LRCInstance::getCallIdForConversationUid(convUid_, accountId_);
if ( callId.empty() ||
!LRCInstance::getCurrentCallModel()->hasCall(callId)) {
return;
}
switch (id) switch (id)
{ {
case 10: case 10:
LRCInstance::getCurrentCallModel()->playDTMF(callId_, "#"); LRCInstance::getCurrentCallModel()->playDTMF(callId, "#");
break; break;
case 11: case 11:
LRCInstance::getCurrentCallModel()->playDTMF(callId_, "*"); LRCInstance::getCurrentCallModel()->playDTMF(callId, "*");
break; break;
default: default:
LRCInstance::getCurrentCallModel()->playDTMF(callId_, std::to_string(id)); LRCInstance::getCurrentCallModel()->playDTMF(callId, std::to_string(id));
break; break;
} }
} }
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#pragma once #pragma once
#include "api/conversationmodel.h"
#include <QWidget> #include <QWidget>
#include <QMenu> #include <QMenu>
#include <QTimer> #include <QTimer>
...@@ -31,6 +33,8 @@ namespace Ui { ...@@ -31,6 +33,8 @@ namespace Ui {
class VideoOverlay; class VideoOverlay;
} }
using namespace lrc::api;
class VideoOverlay : public QWidget class VideoOverlay : public QWidget
{ {
Q_OBJECT Q_OBJECT
...@@ -39,19 +43,16 @@ public: ...@@ -39,19 +43,16 @@ public:
explicit VideoOverlay(QWidget* parent = 0); explicit VideoOverlay(QWidget* parent = 0);
~VideoOverlay(); ~VideoOverlay();
public: void updateCall(const conversation::Info& convInfo);
void setName(const QString& name);
void setPauseState(bool state);
void callStarted(const std::string & callId);
void setVideoMuteVisibility(bool visible);
void simulateShowChatview(bool checked); void simulateShowChatview(bool checked);
bool getShowChatView();
void setTransferCallAndSIPPanelAvailability(bool visible);
void setCurrentSelectedCalleeDisplayName(const QString& CalleeDisplayName);
void resetOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding, bool isAudioOnly);
//UI SLOTS signals:
void setChatVisibility(bool visible);
void holdStateChanged(bool state);
void videoMuteStateChanged(bool state);
private slots: private slots:
void fadeOverlayOut();
void setTime(); void setTime();
void on_hangupButton_clicked(); void on_hangupButton_clicked();
void on_chatButton_toggled(bool checked); void on_chatButton_toggled(bool checked);
...@@ -60,27 +61,28 @@ private slots: ...@@ -60,27 +61,28 @@ private slots:
void on_noVideoButton_toggled(bool checked); void on_noVideoButton_toggled(bool checked);
void on_recButton_clicked(); void on_recButton_clicked();
void on_transferCallButton_toggled(bool checked); void on_transferCallButton_toggled(bool checked);
void on_addToConferenceButton_toggled(bool checked);
void on_sipInputPanelButton_toggled(bool checked); void on_sipInputPanelButton_toggled(bool checked);
void slotWillDoTransfer(const std::string& callId, const std::string& contactUri); void slotWillDoTransfer(const std::string& contactUri);
void slotContactWillJoinConference(const std::string& contactUri);
void slotCallWillJoinConference(const std::string& callId);
void slotSIPInputPanelClicked(const int& id); void slotSIPInputPanelClicked(const int& id);
void fadeOverlayOut();
protected: protected:
void enterEvent(QEvent* event); void enterEvent(QEvent* event);
void leaveEvent(QEvent* event); void leaveEvent(QEvent* event);
void mouseMoveEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event);
private:
bool shouldShowOverlay();
void showOverlay();
private: private:
Ui::VideoOverlay* ui; Ui::VideoOverlay* ui;
// for current conf/call info
std::string accountId_;
std::string convUid_;
ContactPicker* contactPicker_; ContactPicker* contactPicker_;
SipInputPanel* sipInputPanel_; SipInputPanel* sipInputPanel_;
QTimer* oneSecondTimer_; QTimer* oneSecondTimer_;
std::string callId_;
QTimer fadeTimer_; QTimer fadeTimer_;
QPropertyAnimation* fadeAnim_; QPropertyAnimation* fadeAnim_;
...@@ -97,9 +99,6 @@ private: ...@@ -97,9 +99,6 @@ private:
// https://bugreports.qt.io/browse/QTBUG-66803 // https://bugreports.qt.io/browse/QTBUG-66803
constexpr static qreal maxOverlayOpacity_ = 0.9999999999980000442; constexpr static qreal maxOverlayOpacity_ = 0.9999999999980000442;
signals: bool shouldShowOverlay();
void setChatVisibility(bool visible); void showOverlay();
void holdStateChanged(bool state);
void videoMuteStateChanged(bool state);
}; };
...@@ -124,6 +124,47 @@ ...@@ -124,6 +124,47 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="OverlayButton" name="addToConferenceButton">
<property name="minimumSize">
<size>
<width>36</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>36</width>
<height>36</height>
</size>
</property>
<property name="toolTip">
<string>Add a contact to this call</string>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="originPix" stdset="0">
<pixmap resource="ressources.qrc">:/images/icons/ic_group_add_white_24dp.png</pixmap>
</property>
<property name="checkedPix" stdset="0">
<pixmap resource="ressources.qrc">:/images/icons/ic_group_add_white_24dp.png</pixmap>
</property>
<property name="tintColor" stdset="0">
<color>
<red>0</red>
<green>170</green>
<blue>255</blue>
</color>
</property>
</widget>
</item>
<item> <item>
<widget class="OverlayButton" name="transferCallButton"> <widget class="OverlayButton" name="transferCallButton">
<property name="minimumSize"> <property name="minimumSize">
...@@ -144,6 +185,12 @@ ...@@ -144,6 +185,12 @@
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="originPix" stdset="0"> <property name="originPix" stdset="0">
<pixmap resource="ressources.qrc">:/images/icons/ic_call_transfer_white_24px.png</pixmap> <pixmap resource="ressources.qrc">:/images/icons/ic_call_transfer_white_24px.png</pixmap>
</property> </property>
...@@ -581,6 +628,7 @@ ...@@ -581,6 +628,7 @@
</customwidgets> </customwidgets>
<resources> <resources>
<include location="ressources.qrc"/> <include location="ressources.qrc"/>
<include location="ressources.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>
...@@ -113,45 +113,10 @@ VideoView::resizeEvent(QResizeEvent* event) ...@@ -113,45 +113,10 @@ VideoView::resizeEvent(QResizeEvent* event)
overlay_->raise(); overlay_->raise();
} }
void
VideoView::slotCallStatusChanged(const std::string& callId)
{
try {
auto& accInfo = LRCInstance::getAccountInfo(accountId_);
auto call = accInfo.callModel->getCall(callId);
using namespace lrc::api::call;
// all calls
switch (call.status) {
case Status::ENDED:
case Status::TERMINATING:
LRCInstance::renderer()->removeDistantRenderer(callId);
emit terminating(callId);
default:
break;
}
// this call
auto conversation = LRCInstance::getCurrentConversation();
if (conversation.uid.empty() || conversation.callId != callId) {
return;
}
switch (call.status) {
case Status::PAUSED:
resetPreview();
overlay_->setPauseState(true);
case Status::IN_PROGRESS:
resetPreview();
overlay_->setPauseState(false);
default:
break;
}
} catch (...) {}
}
void void
VideoView::simulateShowChatview(bool checked) VideoView::simulateShowChatview(bool checked)
{ {
Q_UNUSED(checked); overlay_->simulateShowChatview(checked);
overlay_->simulateShowChatview(true);
} }
void void
...@@ -212,31 +177,16 @@ VideoView::showContextMenu(const QPoint& position) ...@@ -212,31 +177,16 @@ VideoView::showContextMenu(const QPoint& position)
QMenu menu; QMenu menu;
auto conversation = LRCInstance::getCurrentConversation(); auto conversation = LRCInstance::getCurrentConversation();
if (conversation.uid.empty()) { auto call = LRCInstance::getCallInfoForConversation(conversation);
return; if (!call || call->isAudioOnly) {
}
if (auto call = LRCInstance::getCallInfoForConversation(conversation)) {
if (call->isAudioOnly) {
return;
}
}
auto callIdList = LRCInstance::getActiveCalls();
std::string thisCallId;
for (auto callId : callIdList) {
if (callId == conversation.callId) {
thisCallId = callId;
break;
}
}
if (thisCallId.empty()) {
return; return;
} }
auto activeDevice = LRCInstance::avModel().getCurrentRenderedDevice(thisCallId); auto activeDevice = LRCInstance::avModel().getCurrentRenderedDevice(call->id);
// video input devices // video input devices
auto devices = LRCInstance::avModel().getDevices(); auto devices = LRCInstance::avModel().getDevices();
auto device = LRCInstance::avModel().getDefaultDeviceName(); auto device = LRCInstance::avModel().getCurrentVideoCaptureDevice();
for (auto d : devices) { for (auto d : devices) {
auto deviceName = QString::fromStdString(d).toUtf8(); auto deviceName = QString::fromStdString(d).toUtf8();
auto deviceAction = new QAction(deviceName, this); auto deviceAction = new QAction(deviceName, this);
...@@ -332,11 +282,11 @@ VideoView::showContextMenu(const QPoint& position) ...@@ -332,11 +282,11 @@ VideoView::showContextMenu(const QPoint& position)
} }
void void
VideoView::setupForConversation(const std::string& accountId, VideoView::updateCall(const std::string& convUid,
const std::string& convUid) const std::string& accountId)
{ {
accountId_ = accountId; accountId_ = accountId.empty() ? accountId_ : accountId;
convUid_ = convUid; convUid_ = convUid.empty() ? convUid_ : convUid;
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_); auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
if (convInfo.uid.empty()) { if (convInfo.uid.empty()) {
...@@ -347,48 +297,21 @@ VideoView::setupForConversation(const std::string& accountId, ...@@ -347,48 +297,21 @@ VideoView::setupForConversation(const std::string& accountId,
if (!call) { if (!call) {
return; return;
} }
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
overlay_->updateCall(convInfo);
bool isPaused = call->status == lrc::api::call::Status::PAUSED;
bool isAudioOny = call->isAudioOnly && !isPaused;
bool isAudioMuted = call->audioMuted && (call->status != lrc::api::call::Status::PAUSED);
bool isVideoMuted = call->videoMuted && !isPaused && !call->isAudioOnly;
// close chat panel
emit overlay_->setChatVisibility(false);
// setup overlay
// TODO(atraczyk): all of this could be done with conversation::Info
// transfer call will only happen in SIP calls
bool isSIP = accInfo.profileInfo.type == lrc::api::profile::Type::SIP;
auto& convModel = accInfo.conversationModel;
auto bestName = QString::fromStdString(Utils::bestNameForConversation(convInfo, *convModel));
bool isRecording = accInfo.callModel->isRecording(convInfo.callId);
overlay_->callStarted(convInfo.callId);
overlay_->setTransferCallAndSIPPanelAvailability(isSIP);
overlay_->setVideoMuteVisibility(!call->isAudioOnly);
overlay_->resetOverlay(isAudioMuted, isVideoMuted, isRecording, isPaused, isAudioOny);
overlay_->setCurrentSelectedCalleeDisplayName(bestName);
overlay_->setName(bestName);
// TODO(atraczyk): this should be part of the overlay // TODO(atraczyk): this should be part of the overlay
audioOnlyAvatar_->setAvatarVisible(call->isAudioOnly); audioOnlyAvatar_->setAvatarVisible(call->isAudioOnly);
if (call->isAudioOnly) { if (call->isAudioOnly) {
audioOnlyAvatar_->writeAvatarOverlay(convInfo); audioOnlyAvatar_->writeAvatarOverlay(convInfo);
} }
// preview visibility // preview
previewWidget_->setVisible(shouldShowPreview()); previewWidget_->setVisible(shouldShowPreview());
// distant // distant
ui->distantWidget->setRendererId(call->id); ui->distantWidget->setRendererId(call->id);
auto isPaused = call->status == lrc::api::call::Status::PAUSED;
// listen for the end of a call ui->distantWidget->setVisible(!isPaused);
disconnect(callStatusChangedConnection_);
callStatusChangedConnection_ = connect(
accInfo.callModel.get(),
&NewCallModel::callStatusChanged,
this,
&VideoView::slotCallStatusChanged);
} }
void void
...@@ -487,7 +410,8 @@ VideoView::shouldShowPreview() ...@@ -487,7 +410,8 @@ VideoView::shouldShowPreview()
shouldShowPreview = shouldShowPreview =
!call->isAudioOnly && !call->isAudioOnly &&
!(call->status == lrc::api::call::Status::PAUSED) && !(call->status == lrc::api::call::Status::PAUSED) &&
!call->videoMuted; !call->videoMuted &&
call->type != lrc::api::call::Type::CONFERENCE;
} }
return shouldShowPreview; return shouldShowPreview;
} }
...@@ -496,7 +420,11 @@ void ...@@ -496,7 +420,11 @@ void
VideoView::resetPreview() VideoView::resetPreview()
{ {
if (shouldShowPreview()) { if (!shouldShowPreview()) {
previewWidget_->setVisible(false);
return;
}
previewWidget_->setContainerSize(this->size()); previewWidget_->setContainerSize(this->size());
auto previewImage = LRCInstance::renderer()->getPreviewFrame(); auto previewImage = LRCInstance::renderer()->getPreviewFrame();
int width; int width;
...@@ -519,10 +447,8 @@ VideoView::resetPreview() ...@@ -519,10 +447,8 @@ VideoView::resetPreview()
} }
auto newSize = previewWidget_->getScaledSize(width, height); auto newSize = previewWidget_->getScaledSize(width, height);
previewWidget_->setupGeometry(newSize); previewWidget_->setupGeometry(newSize);
previewWidget_->setVisible(true); previewWidget_->setVisible(true);
} else {
previewWidget_->setVisible(false);
}
} }
......
...@@ -44,9 +44,8 @@ public: ...@@ -44,9 +44,8 @@ public:
explicit VideoView(QWidget* parent = 0); explicit VideoView(QWidget* parent = 0);
~VideoView(); ~VideoView();
void setupForConversation(const std::string& accountId, void updateCall(const std::string& convUid = {},
const std::string& convUid); const std::string& accountId = {});
void showChatviewIfToggled();
void simulateShowChatview(bool checked); void simulateShowChatview(bool checked);
void resetPreview(); void resetPreview();
...@@ -64,31 +63,24 @@ protected: ...@@ -64,31 +63,24 @@ protected:
void keyReleaseEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event);
private slots: private slots:
void slotCallStatusChanged(const std::string& callId);
void showContextMenu(const QPoint& position); void showContextMenu(const QPoint& position);
void slotVideoMuteStateChanged(bool state); void slotVideoMuteStateChanged(bool state);
private: private:
Ui::VideoView* ui; Ui::VideoView* ui;
// for current conf/call info
std::string accountId_; std::string accountId_;
std::string convUid_; std::string convUid_;
// preview // overlay
PreviewSnap currentPreviewLocation_ = PreviewSnap::SE;
VideoCallPreviewWidget* previewWidget_;
constexpr static int previewMargin_ = 15;
// video overlay
VideoOverlay* overlay_; VideoOverlay* overlay_;
// audio only overlay // audio only overlay
// TODO: put this into the VideoOverlay class // TODO: put this into the VideoOverlay class
CallAudioOnlyAvatarOverlay* audioOnlyAvatar_; CallAudioOnlyAvatarOverlay* audioOnlyAvatar_;
QMetaObject::Connection callStatusChangedConnection_; // preview
VideoCallPreviewWidget* previewWidget_;
// dragging the preview
QPropertyAnimation* moveAnim_; QPropertyAnimation* moveAnim_;
QPoint originMouseDisplacement_; QPoint originMouseDisplacement_;
bool draggingPreview_ = false; bool draggingPreview_ = false;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment