Commit 2eefb501 authored by Andreas Traczyk's avatar Andreas Traczyk

callwidget: modify call state change behavior

Change-Id: Ia16943d8cf79ef38e9a9ea7709a2214437675a4a
parent bf315303
......@@ -262,7 +262,7 @@ CallWidget::navigated(bool to)
* This will resize/position the preview when returning from the settings
* in case of a resolution change.
*/
ui->videoView->resetPreview();
ui->videoView->resetPreviewWidget();
} else {
QObject::disconnect(smartlistSelectionConnection_);
smartListModel_.reset(nullptr);
......@@ -660,10 +660,6 @@ CallWidget::slotShowCallView(const std::string& accountId,
Q_UNUSED(accountId);
qDebug() << "slotShowCallView";
auto convModel = LRCInstance::getCurrentConversationModel();
auto bestName = QString::fromStdString(
Utils::bestNameForConversation(convInfo, *convModel));
// control visible callwidget buttons
setCallPanelVisibility(true);
......@@ -1297,48 +1293,64 @@ CallWidget::update()
void
CallWidget::connectAccount(const std::string& accId)
{
auto callModel = LRCInstance::accountModel().getAccountInfo(accId).callModel.get();
disconnect(callStatusChangedConnection_);
callStatusChangedConnection_ = QObject::connect(callModel, &lrc::api::NewCallModel::callStatusChanged,
[this, accId](const std::string& callId) {
auto callModel = LRCInstance::accountModel().getAccountInfo(accId).callModel.get();
auto call = callModel->getCall(callId);
switch (call.status) {
case lrc::api::call::Status::INVALID:
case lrc::api::call::Status::INACTIVE:
case lrc::api::call::Status::ENDED:
case lrc::api::call::Status::PEER_BUSY:
case lrc::api::call::Status::TIMEOUT:
case lrc::api::call::Status::TERMINATING:
{
setCallPanelVisibility(false);
showConversationView();
break;
}
default:
break;
}
});
auto& contactModel = LRCInstance::getCurrentAccountInfo().contactModel;
disconnect(contactAddedConnection_);
contactAddedConnection_ = connect(contactModel.get(), &lrc::api::ContactModel::contactAdded,
[this, &contactModel](const std::string & contactUri) {
auto convModel = LRCInstance::getCurrentConversationModel();
auto conversation = LRCInstance::getCurrentConversation();
if (conversation.uid.empty()) {
return;
}
if (contactUri == contactModel.get()->getContact(conversation.participants.at(0)).profileInfo.uri) {
// update call screen
auto avatarImg = QPixmap::fromImage(imageForConv(conversation.uid));
ui->callingPhoto->setPixmap(avatarImg);
ui->callerPhoto->setPixmap(avatarImg);
// update conversation
ui->messageView->clear();
setConversationProfileData(conversation);
ui->messageView->printHistory(*convModel, conversation.interactions);
}
});
try {
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accId);
auto callModel = accInfo.callModel.get();
QObject::disconnect(callStatusChangedConnection_);
callStatusChangedConnection_ = QObject::connect(callModel,
&lrc::api::NewCallModel::callStatusChanged,
[this, &accInfo, accId](const std::string& callId) {
auto& callModel = accInfo.callModel;
auto call = callModel->getCall(callId);
switch (call.status) {
case lrc::api::call::Status::INVALID:
case lrc::api::call::Status::INACTIVE:
case lrc::api::call::Status::ENDED:
case lrc::api::call::Status::PEER_BUSY:
case lrc::api::call::Status::TIMEOUT:
case lrc::api::call::Status::TERMINATING: {
setCallPanelVisibility(false);
showConversationView();
break;
}
case lrc::api::call::Status::CONNECTED:
case lrc::api::call::Status::IN_PROGRESS: {
auto convInfo = LRCInstance::getConversationFromCallId(callId, accId);
if (!convInfo.uid.empty() && convInfo.uid == LRCInstance::getSelectedConvUid()) {
accInfo.conversationModel->selectConversation(convInfo.uid);
}
LRCInstance::renderer()->addDistantRenderer(convInfo.callId);
break;
}
default:
break;
}
ui->smartList->update();
});
auto& contactModel = accInfo.contactModel;
disconnect(contactAddedConnection_);
contactAddedConnection_ = connect(contactModel.get(),
&lrc::api::ContactModel::contactAdded,
[this, &contactModel, &accInfo](const std::string& contactUri) {
auto convModel = LRCInstance::getCurrentConversationModel();
auto conversation = LRCInstance::getCurrentConversation();
if (conversation.uid.empty()) {
return;
}
if (contactUri == contactModel.get()->getContact(conversation.participants.at(0)).profileInfo.uri) {
// update call screen
auto avatarImg = QPixmap::fromImage(imageForConv(conversation.uid));
ui->callingPhoto->setPixmap(avatarImg);
ui->callerPhoto->setPixmap(avatarImg);
// update conversation
ui->messageView->clear();
setConversationProfileData(conversation);
ui->messageView->printHistory(*convModel, conversation.interactions);
}
});
} catch (...) {
qWarning() << "Couldn't get account: " << accId.c_str();
}
}
void
......
......@@ -270,42 +270,57 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
painter->drawText(rectInfo1, Qt::AlignVCenter | Qt::AlignRight, lastUsedStr);
}
// bottom-right: last interaction snippet
QString interactionStr = index.data(static_cast<int>(SmartListModel::Role::LastInteraction)).value<QString>();
if (!interactionStr.isNull()) {
painter->save();
font.setWeight(QFont::ExtraLight);
interactionStr = interactionStr.simplified();
auto type = Utils::toEnum<lrc::api::interaction::Type>(index
.data(static_cast<int>(SmartListModel::Role::LastInteractionType))
.value<int>());
if (type == lrc::api::interaction::Type::CALL ||
type == lrc::api::interaction::Type::CONTACT) {
font.setItalic(false);
font.setBold(false);
// bottom-right: last interaction snippet or call state (if in call)
if (index.data(static_cast<int>(SmartListModel::Role::InCall)).value<bool>()) {
QString callStateStr = index.data(static_cast<int>(SmartListModel::Role::CallStateStr)).value<QString>();
if (!callStateStr.isNull()) {
painter->save();
font.setWeight(QFont::DemiBold);
pen.setColor(RingTheme::grey_.darker(140));
painter->setPen(pen);
painter->setFont(font);
// strip emojis if it's a call/contact type message
VectorUInt emojiless;
for (auto unicode : interactionStr.toUcs4()) {
if (!(unicode >= 0x1F000 && unicode <= 0x1FFFF)) {
emojiless.push_back(unicode);
callStateStr = fontMetrics.elidedText(callStateStr, Qt::ElideRight, rectInfo2.width());
painter->drawText(rectInfo2, Qt::AlignVCenter | Qt::AlignRight, callStateStr);
painter->restore();
}
} else {
QString interactionStr = index.data(static_cast<int>(SmartListModel::Role::LastInteraction)).value<QString>();
if (!interactionStr.isNull()) {
painter->save();
font.setWeight(QFont::ExtraLight);
interactionStr = interactionStr.simplified();
auto type = Utils::toEnum<lrc::api::interaction::Type>(index
.data(static_cast<int>(SmartListModel::Role::LastInteractionType))
.value<int>());
if (type == lrc::api::interaction::Type::CALL ||
type == lrc::api::interaction::Type::CONTACT) {
font.setItalic(false);
font.setBold(false);
pen.setColor(RingTheme::grey_.darker(140));
painter->setPen(pen);
painter->setFont(font);
// strip emojis if it's a call/contact type message
VectorUInt emojiless;
for (auto unicode : interactionStr.toUcs4()) {
if (!(unicode >= 0x1F000 && unicode <= 0x1FFFF)) {
emojiless.push_back(unicode);
}
}
interactionStr = QString::fromUcs4(&emojiless.at(0), emojiless.size());
}
interactionStr = QString::fromUcs4(&emojiless.at(0), emojiless.size());
} else {
QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
emojiMsgFont.setItalic(false);
emojiMsgFont.setBold(false);
emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
rectInfo2.setTop(rectInfo2.top() - 6);
painter->setOpacity(0.7);
painter->setFont(emojiMsgFont);
else {
QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
emojiMsgFont.setItalic(false);
emojiMsgFont.setBold(false);
emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
rectInfo2.setTop(rectInfo2.top() - 6);
painter->setOpacity(0.7);
painter->setFont(emojiMsgFont);
}
interactionStr = fontMetrics.elidedText(interactionStr, Qt::ElideRight, rectInfo2.width());
painter->drawText(rectInfo2, Qt::AlignVCenter | Qt::AlignRight, interactionStr);
painter->restore();
}
interactionStr = fontMetrics.elidedText(interactionStr, Qt::ElideRight, rectInfo2.width());
painter->drawText(rectInfo2, Qt::AlignVCenter | Qt::AlignRight, interactionStr);
painter->restore();
}
}
......
......@@ -24,6 +24,14 @@
DistantWidget::DistantWidget(QWidget* parent)
: VideoWidgetBase(Qt::black, parent)
{
connect(LRCInstance::renderer(), &RenderManager::distantFrameUpdated,
[this](const std::string& id) {
if (id_ == id) repaint();
});
connect(LRCInstance::renderer(), &RenderManager::distantRenderingStopped,
[this](const std::string& id) {
if (id_ == id) repaint();
});
}
DistantWidget::~DistantWidget()
......@@ -44,12 +52,24 @@ DistantWidget::paintEvent(QPaintEvent* e)
painter.drawImage(QRect(xDiff, yDiff,
scaledDistant.width(), scaledDistant.height()),
scaledDistant);
} else {
paintBackground(&painter);
}
painter.end();
}
void
DistantWidget::paintBackground(QPainter* painter)
{
QBrush brush(Qt::black);
QPainterPath path;
path.addRect(this->rect());
painter->fillPath(path, brush);
}
void
DistantWidget::setRendererId(const std::string& id)
{
id_ = id;
update();
}
......@@ -35,6 +35,8 @@ public:
protected:
void paintEvent(QPaintEvent* e);
void paintBackground(QPainter* painter) override;
private:
std::string id_;
......
......@@ -295,7 +295,6 @@ void MainWindow::closeEvent(QCloseEvent* event)
this->hide();
event->ignore();
} else {
LRCInstance::renderer()->stopPreviewing(false);
settings.setValue(SettingsKey::geometry, saveGeometry());
settings.setValue(SettingsKey::windowState, saveState());
this->disconnect(screenChangedConnection_);
......
......@@ -23,22 +23,26 @@
PreviewWidget::PreviewWidget(QWidget * parent)
: VideoWidgetBase(Qt::transparent, parent)
{}
{
connect(LRCInstance::renderer(), &RenderManager::previewFrameUpdated,
[this]() {
repaint();
});
connect(LRCInstance::renderer(), &RenderManager::previewRenderingStopped,
[this]() {
repaint();
});
}
PreviewWidget::~PreviewWidget()
{}
void
PreviewWidget::paintBackgroundColor(QPainter* painter, QColor color, bool rounded)
PreviewWidget::paintBackground(QPainter* painter)
{
QBrush brush(color);
QBrush brush(Qt::black);
QPainterPath path;
auto r = this->rect().width() / 2;
if (rounded) {
path.addEllipse(QPoint(r, r), r, r);
} else {
path.addRect(this->rect());
}
path.addRect(this->rect());
painter->fillPath(path, brush);
}
......@@ -71,8 +75,7 @@ PreviewWidget::paintEvent(QPaintEvent* e)
scaledPreview = previewImage->scaled(previewWidth, previewHeight, Qt::KeepAspectRatio);
painter.drawImage(this->rect(), scaledPreview);
} else {
// clear to black
paintBackgroundColor(&painter, Qt::black, false);
paintBackground(&painter);
}
}
......@@ -102,11 +105,20 @@ PhotoboothPreviewWidget::paintEvent(QPaintEvent* e)
this->setGeometry(0, 0, scaledPreview.width(), scaledPreview.height());
painter.drawImage(this->rect(), scaledPreview);
} else {
// clear to black
paintBackgroundColor(&painter, Qt::black, true);
paintBackground(&painter);
}
}
void
PhotoboothPreviewWidget::paintBackground(QPainter* painter)
{
QBrush brush(Qt::black);
QPainterPath path;
auto r = this->rect().width() / 2;
path.addEllipse(QPoint(r, r), r, r);
painter->fillPath(path, brush);
}
QImage
PhotoboothPreviewWidget::takePhoto()
{
......
......@@ -36,9 +36,7 @@ public:
protected:
virtual void paintEvent(QPaintEvent* e) override;
void paintBackgroundColor(QPainter* painter,
QColor color,
bool rounded = false);
virtual void paintBackground(QPainter* painter) override;
};
// A rounded image for photobooths
......@@ -53,6 +51,8 @@ public:
protected:
void paintEvent(QPaintEvent* e) override;
void paintBackground(QPainter* painter) override;
};
// rounded corners for video calls
......
......@@ -148,7 +148,7 @@ FrameWrapper::slotRenderingStopped(const std::string& id)
emit renderingStopped(id);
}
#pragma optimize("", off)
RenderManager::RenderManager(AVModel& avModel)
:avModel_(avModel)
{
......@@ -179,7 +179,7 @@ RenderManager::RenderManager(AVModel& avModel)
previewFrameWrapper_->connectRendering();
}
#pragma optimize("", on)
RenderManager::~RenderManager()
{
previewFrameWrapper_.reset();
......
......@@ -19,18 +19,15 @@
#include "smartlistmodel.h"
// Qt
#include <QDateTime>
#include "pixbufmanipulator.h"
#include "utils.h"
#include "lrcinstance.h"
// LRC
#include "globalinstances.h"
#include "api/contactmodel.h"
#include "api/conversationmodel.h"
// Client
#include "pixbufmanipulator.h"
#include "utils.h"
#include "lrcinstance.h"
#include <QDateTime>
SmartListModel::SmartListModel(const std::string& accId, QObject *parent, bool contactList)
: QAbstractItemModel(parent),
......@@ -66,7 +63,7 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const
auto& accInfo = LRCInstance::accountModel().getAccountInfo(accId_);
lrc::api::conversation::Info item;
conversation::Info item;
if (contactList_) {
auto filterType = accInfo.profileInfo.type;
item = accInfo.conversationModel->getFilteredConversations(filterType).at(index.row());
......@@ -121,6 +118,27 @@ QVariant SmartListModel::data(const QModelIndex &index, int role) const
return QVariant(QString::fromStdString(item.uid));
case Role::ContextMenuOpen:
return QVariant(isContextMenuOpen);
case Role::InCall:
{
auto& convInfo = LRCInstance::getConversationFromConvUid(item.uid);
if (!convInfo.uid.empty()) {
auto callModel = LRCInstance::getCurrentCallModel();
return QVariant(callModel->hasCall(convInfo.callId));
}
return QVariant(false);
}
case Role::CallStateStr:
{
auto& convInfo = LRCInstance::getConversationFromConvUid(item.uid);
if (!convInfo.uid.empty()) {
auto call = LRCInstance::getCallInfoForConversation(convInfo);
if (call) {
auto statusString = call::to_string(call->status);
return QVariant(QString::fromStdString(statusString));
}
}
return QVariant();
}
}
} catch (...) {}
}
......
......@@ -47,7 +47,9 @@ public:
LastInteractionType,
ContactType,
UID,
ContextMenuOpen
ContextMenuOpen,
InCall,
CallStateStr
};
explicit SmartListModel(const std::string& accId, QObject *parent = 0, bool contactList = false);
......
......@@ -111,7 +111,8 @@ void
VideoOverlay::showOverlay()
{
fadeAnim_->stop();
fadeAnim_->targetObject()->setProperty(fadeAnim_->propertyName(), fadeAnim_->startValue());
fadeAnim_->targetObject()->setProperty(fadeAnim_->propertyName(),
fadeAnim_->startValue());
}
void
......@@ -125,10 +126,12 @@ VideoOverlay::fadeOverlayOut()
void
VideoOverlay::callStarted(const std::string& callId)
{
ui->timerLabel->setText("00:00");
callId_ = callId;
setTime();
connect(oneSecondTimer_, &QTimer::timeout, this, &VideoOverlay::setTime);
oneSecondTimer_->start(1000);
showOverlay();
fadeTimer_.start(startfadeOverlayTime_);
}
void
......@@ -137,6 +140,12 @@ VideoOverlay::setName(const QString& name)
ui->nameLabel->setText(name);
}
void
VideoOverlay::setPauseState(bool state)
{
ui->onHoldLabel->setVisible(state);
}
void
VideoOverlay::setTime()
{
......@@ -217,10 +226,7 @@ VideoOverlay::on_holdButton_toggled(bool checked)
callModel->togglePause(callId_);
onHold = callModel->getCall(callId_).status == lrc::api::call::Status::PAUSED;
}
// emit that the hold button status changed
emit holdStateChanged(onHold);
ui->onHoldLabel->setVisible(onHold);
}
void
......
......@@ -41,9 +41,9 @@ public:
public:
void setName(const QString& name);
void setPauseState(bool state);
void callStarted(const std::string & callId);
void setVideoMuteVisibility(bool visible);
bool shouldShowOverlay();
void simulateShowChatview(bool checked);
bool getShowChatView();
void setTransferCallAndSIPPanelAvailability(bool visible);
......@@ -71,6 +71,7 @@ protected:
void mouseMoveEvent(QMouseEvent* event);
private:
bool shouldShowOverlay();
void showOverlay();
private:
......
......@@ -62,9 +62,15 @@ VideoView::VideoView(QWidget* parent)
// chat panel
connect(LRCInstance::renderer(), &RenderManager::videoDeviceListChanged,
[this] {
resetPreviewAsync();
resetPreview();
});
connect(overlay_,
&VideoOverlay::videoMuteStateChanged,
this,
&VideoView::slotVideoMuteStateChanged,
Qt::UniqueConnection);
// audio only overlay
audioOnlyAvatar_ = new CallAudioOnlyAvatarOverlay(this);
......@@ -90,7 +96,7 @@ VideoView::resizeEvent(QResizeEvent* event)
moveAnim_->stop();
resetPreview();
resetPreviewWidget();
audioOnlyAvatar_->resize(this->size());
......@@ -111,6 +117,12 @@ VideoView::slotCallStatusChanged(const std::string& callId)
case Status::TERMINATING:
LRCInstance::renderer()->removeDistantRenderer(callId);
emit terminating(callId);
case Status::PAUSED:
resetPreview(false);
overlay_->setPauseState(true);
case Status::IN_PROGRESS:
resetPreview();
overlay_->setPauseState(false);
default:
break;
}
......@@ -218,8 +230,7 @@ VideoView::showContextMenu(const QPoint& position)
connect(deviceAction, &QAction::triggered,
[this, deviceName]() {
auto device = deviceName.toStdString();
connectDistantRenderer();
resetPreviewAsync();
resetPreview();
LRCInstance::avModel().switchInputTo(device);
LRCInstance::avModel().setCurrentVideoCaptureDevice(device);
});
......@@ -239,8 +250,7 @@ VideoView::showContextMenu(const QPoint& position)
#if defined(Q_OS_WIN) && (PROCESS_DPI_AWARE)
rect.setSize(Utils::getRealSize(screen));
#endif
connectDistantRenderer();
resetPreviewAsync();
resetPreview();
LRCInstance::avModel().setDisplay(screenNumber,
rect.x(), rect.y(), rect.width(), rect.height()
);
......@@ -254,8 +264,7 @@ VideoView::showContextMenu(const QPoint& position)
shareAreaAction->setCheckable(true);
connect(shareAreaAction, &QAction::triggered,
[this]() {
connectDistantRenderer();
resetPreviewAsync();
resetPreview();
SelectAreaDialog selectAreaDialog;
selectAreaDialog.exec();
sharingEntireScreen_ = false;
......@@ -274,8 +283,7 @@ VideoView::showContextMenu(const QPoint& position)
return;
fileNames = fileDialog.selectedFiles();
auto resource = QUrl::fromLocalFile(fileNames.at(0)).toString();
connectDistantRenderer();
resetPreviewAsync();
resetPreview();
LRCInstance::avModel().setInputFile(resource.toStdString());
});
......@@ -335,17 +343,16 @@ VideoView::setupForConversation(const std::string& accountId,
overlay_->setCurrentSelectedCalleeDisplayName(bestName);
overlay_->setName(bestName);
// TODO(atraczyk): this should be part of the overlay
resetAvatarOverlay(call->isAudioOnly);
audioOnlyAvatar_->setAvatarVisible(call->isAudioOnly);
if (call->isAudioOnly) {
audioOnlyAvatar_->writeAvatarOverlay(convInfo);
}
// preview
resetPreviewAsync();
// preview visibility
previewWidget_->setVisible(shouldShowPreview());
// distant
ui->distantWidget->setRendererId(call->id);
connectDistantRenderer();
// listen for the end of a call
disconnect(callStatusChangedConnection_);
......@@ -432,35 +439,11 @@ VideoView::mouseMoveEvent(QMouseEvent* event)
}
void
VideoView::resetAvatarOverlay(bool isAudioOnly)
{
audioOnlyAvatar_->setAvatarVisible(isAudioOnly);
connect(overlay_,
&VideoOverlay::holdStateChanged,
this,
&VideoView::slotHoldStateChanged,
Qt::UniqueConnection);
connect(overlay_,
&VideoOverlay::videoMuteStateChanged,
this,
&VideoView::slotVideoMuteStateChanged,
Qt::UniqueConnection);
}
void
VideoView::slotHoldStateChanged(bool state)
{
audioOnlyAvatar_->respondToPauseLabel(state);
resetPreviewAsync();
}
void
VideoView::slotVideoMuteStateChanged(bool state)
{
Q_UNUSED(state);
resetPreviewAsync();
resetPreview();
}
QPoint
......@@ -512,45 +495,39 @@ VideoView::resetPreviewPosition()
}
void
VideoView::resetPreviewAsync()
VideoView::resetPreview(bool async)
{
Utils::oneShotConnect(LRCInstance::renderer(),
&RenderManager::previewRenderingStopped,
[this] {
// hide preview once stopped
previewWidget_->hide();
Utils::oneShotConnect(LRCInstance::renderer(),
&RenderManager::previewRenderingStarted,
[this] {
Utils::oneShotConnect(LRCInstance::renderer(),
&RenderManager::previewFrameUpdated,
[this] {
// repostion and show once at least one
// frame is ready
resetPreview();
});
});
});
}
void
VideoView::connectDistantRenderer()
{
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
if (convInfo.uid.empty()) {
return;
if (async) {
Utils::oneShotConnect(LRCInstance::renderer(),
&RenderManager::previewRenderingStopped,
[this] {
// hide preview once stopped
previewWidget_->hide();
Utils::oneShotConnect(LRCInstance::renderer(),
&RenderManager::previewRenderingStarted,
[this] {
Utils::oneShotConnect(LRCInstance::renderer(),
&RenderManager::previewFrameUpdated,
[this] {
// repostion and show once at least one
// frame is ready
resetPreviewWidget();
});
});
});
} else {
resetPreviewWidget();
}
LRCInstance::renderer()->addDistantRenderer(convInfo.callId);
}
void
VideoView::resetPreview()
bool
VideoView::shouldShowPreview()
{
bool shouldShowPreview{ false };
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
if (convInfo.uid.empty()) {
return;
return shouldShowPreview;
}
bool shouldShowPreview = true;
auto call = LRCInstance::getCallInfoForConversation(convInfo);
if (call) {
shouldShowPreview =
......@@ -558,11 +535,20 @@ VideoView::resetPreview()
!(call->status == lrc::api::call::Status::PAUSED) &&
!call->videoMuted;
}
if (shouldShowPreview) {
return shouldShowPreview;
}
void
VideoView::resetPreviewWidget()
{