Commit 01da004a authored by Ming Rui Zhang's avatar Ming Rui Zhang Committed by Andreas Traczyk

transferCall: add blind/attended transfer call support

Change-Id: I7a159ac51cb7527ce8fc1010c2c6caebd7251c0e
parent 60a3e631
...@@ -642,11 +642,13 @@ void CallWidget::slotShowCallView(const std::string& accountId, ...@@ -642,11 +642,13 @@ void CallWidget::slotShowCallView(const std::string& accountId,
const lrc::api::conversation::Info& convInfo) const lrc::api::conversation::Info& convInfo)
{ {
Q_UNUSED(accountId); Q_UNUSED(accountId);
Q_UNUSED(convInfo);
qDebug() << "slotShowCallView"; qDebug() << "slotShowCallView";
setCallPanelVisibility(true); // find out the best name for current callee, remove the search result from smart list
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
auto convModel = LRCInstance::getCurrentConversationModel();
auto bestName = QString::fromStdString(Utils::bestNameForConversation(convInfo, *convModel));
ui->videoWidget->setCurrentCalleeName(bestName);
setCallPanelVisibility(true);
if (callModel->hasCall(convInfo.callId)) { if (callModel->hasCall(convInfo.callId)) {
auto call = callModel->getCall(convInfo.callId); auto call = callModel->getCall(convInfo.callId);
...@@ -659,7 +661,7 @@ void CallWidget::slotShowCallView(const std::string& accountId, ...@@ -659,7 +661,7 @@ void CallWidget::slotShowCallView(const std::string& accountId,
} }
ui->callStackWidget->setCurrentWidget(ui->videoPage); ui->callStackWidget->setCurrentWidget(ui->videoPage);
hideMiniSpinner(); hideMiniSpinner();
ui->videoWidget->pushRenderer(convInfo.callId); ui->videoWidget->pushRenderer(convInfo.callId, LRCInstance::accountModel().getAccountInfo(accountId).profileInfo.type == lrc::api::profile::Type::SIP);
} }
void CallWidget::slotShowIncomingCallView(const std::string& accountId, void CallWidget::slotShowIncomingCallView(const std::string& accountId,
...@@ -683,6 +685,7 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId, ...@@ -683,6 +685,7 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId,
auto call = callModel->getCall(convInfo.callId); auto call = callModel->getCall(convInfo.callId);
auto isCallSelected = LRCInstance::getSelectedConvUid() == convInfo.uid; auto isCallSelected = LRCInstance::getSelectedConvUid() == 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)));
ui->videoWidget->setCurrentCalleeName(bestName);
connect(callModel, &lrc::api::NewCallModel::callStatusChanged, ui->incomingCallPage, connect(callModel, &lrc::api::NewCallModel::callStatusChanged, ui->incomingCallPage,
[this, accountId](const std::string& callId) { [this, accountId](const std::string& callId) {
...@@ -726,7 +729,7 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId, ...@@ -726,7 +729,7 @@ void CallWidget::slotShowIncomingCallView(const std::string& accountId,
ui->messagesWidget->show(); ui->messagesWidget->show();
} }
ui->videoWidget->pushRenderer(convInfo.callId); ui->videoWidget->pushRenderer(convInfo.callId, LRCInstance::accountModel().getAccountInfo(accountId).profileInfo.type == lrc::api::profile::Type::SIP);
QFontMetrics primaryCallLabelFontMetrics(ui->callingBestNameLabel->font()); QFontMetrics primaryCallLabelFontMetrics(ui->callingBestNameLabel->font());
QFontMetrics sencondaryCallLabelFontMetrics(ui->callingBestIdLabel->font()); QFontMetrics sencondaryCallLabelFontMetrics(ui->callingBestIdLabel->font());
......
...@@ -73,9 +73,8 @@ ContactPicker::accept() ...@@ -73,9 +73,8 @@ ContactPicker::accept()
case Type::CONFERENCE: case Type::CONFERENCE:
emit contactWillJoinConference(thisCallId, contactUri); emit contactWillJoinConference(thisCallId, contactUri);
break; break;
case Type::BLIND_TRANSFER: case Type::TRANSFER:
case Type::ATTENDED_TRANSFER: emit contactWillDoTransfer(thisCallId, contactUri);
emit contactWillDoBlindTransfer(thisCallId, contactUri);
break; break;
default: default:
break; break;
...@@ -96,7 +95,6 @@ ContactPicker::mousePressEvent(QMouseEvent *event) ...@@ -96,7 +95,6 @@ ContactPicker::mousePressEvent(QMouseEvent *event)
{ {
auto contactPickerWidgetRect = ui->contactPickerWidget->rect(); auto contactPickerWidgetRect = ui->contactPickerWidget->rect();
if (!contactPickerWidgetRect.contains(event->pos())) { if (!contactPickerWidgetRect.contains(event->pos())) {
//close();
emit willClose(event); emit willClose(event);
} }
} }
...@@ -131,11 +129,17 @@ ContactPicker::setType(const Type& type) ...@@ -131,11 +129,17 @@ ContactPicker::setType(const Type& type)
!index.parent().isValid(); !index.parent().isValid();
}); });
break; break;
case Type::BLIND_TRANSFER: case Type::TRANSFER:
case Type::ATTENDED_TRANSFER:
selectableProxyModel_->setPredicate( selectableProxyModel_->setPredicate(
[this](const QModelIndex& index, const QRegExp& regexp) { [this](const QModelIndex& index, const QRegExp& regexp) {
return true; // Regex to remove current callee
QRegExp matchExcept= QRegExp(QString("\\b(?!" + CalleeDisplayName_ + "\\b)\\w+"));
bool match = false;
bool match_non_self = matchExcept.indexIn(index.data(Qt::DisplayRole).toString()) != -1;
if (match_non_self) {
match = regexp.indexIn(index.data(Qt::DisplayRole).toString()) != -1;
}
return match && !index.parent().isValid();
}); });
break; break;
default: default:
...@@ -143,3 +147,9 @@ ContactPicker::setType(const Type& type) ...@@ -143,3 +147,9 @@ ContactPicker::setType(const Type& type)
} }
selectableProxyModel_->invalidate(); selectableProxyModel_->invalidate();
} }
void
ContactPicker::setCurrentCalleeDisplayName(const QString& CalleeDisplayName)
{
CalleeDisplayName_ = CalleeDisplayName;
}
...@@ -63,8 +63,7 @@ class ContactPicker : public QDialog ...@@ -63,8 +63,7 @@ class ContactPicker : public QDialog
public: public:
enum class Type { enum class Type {
CONFERENCE, CONFERENCE,
BLIND_TRANSFER, TRANSFER,
ATTENDED_TRANSFER,
COUNT__ COUNT__
}; };
...@@ -72,13 +71,14 @@ public: ...@@ -72,13 +71,14 @@ public:
~ContactPicker(); ~ContactPicker();
void setTitle(const std::string& title); void setTitle(const std::string& title);
void setType(const Type& type); void setType(const Type& type);
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& callId, const std::string& contactUri);
void contactWillDoBlindTransfer(const std::string& callId, const std::string& contactUri); void contactWillDoTransfer(const std::string& callId, const std::string& contactUri);
void willClose(QMouseEvent *event); void willClose(QMouseEvent *event);
protected slots: protected slots:
...@@ -94,5 +94,6 @@ private: ...@@ -94,5 +94,6 @@ private:
std::unique_ptr<SmartListModel> smartListModel_; std::unique_ptr<SmartListModel> smartListModel_;
SelectableProxyModel* selectableProxyModel_; SelectableProxyModel* selectableProxyModel_;
Type type_; Type type_;
QString CalleeDisplayName_;
}; };
...@@ -190,7 +190,7 @@ ...@@ -190,7 +190,7 @@
<cursorShape>IBeamCursor</cursorShape> <cursorShape>IBeamCursor</cursorShape>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Search contact text input</string> <string>Search contact</string>
</property> </property>
<property name="maxLength"> <property name="maxLength">
<number>100</number> <number>100</number>
...@@ -251,10 +251,10 @@ ...@@ -251,10 +251,10 @@
<attribute name="headerVisible"> <attribute name="headerVisible">
<bool>false</bool> <bool>false</bool>
</attribute> </attribute>
<attribute name="headerDefaultSectionSize"> <attribute name="headerMinimumSectionSize">
<number>0</number> <number>0</number>
</attribute> </attribute>
<attribute name="headerMinimumSectionSize"> <attribute name="headerDefaultSectionSize">
<number>0</number> <number>0</number>
</attribute> </attribute>
</widget> </widget>
...@@ -294,7 +294,7 @@ ...@@ -294,7 +294,7 @@
<string/> <string/>
</property> </property>
<property name="pixmap"> <property name="pixmap">
<pixmap resource="ressources.qrc">:/images/spike.png</pixmap> <pixmap>:/images/spike.png</pixmap>
</property> </property>
</widget> </widget>
</item> </item>
...@@ -312,8 +312,6 @@ ...@@ -312,8 +312,6 @@
<header>smartlistview.h</header> <header>smartlistview.h</header>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources> <resources/>
<include location="ressources.qrc"/>
</resources>
<connections/> <connections/>
</ui> </ui>
...@@ -104,6 +104,7 @@ ContactPickerItemDelegate::paint(QPainter* painter ...@@ -104,6 +104,7 @@ ContactPickerItemDelegate::paint(QPainter* painter
paintRingContactItem(painter, option, rect, index); paintRingContactItem(painter, option, rect, index);
break; break;
case profile::Type::SIP: case profile::Type::SIP:
paintSIPContactItem(painter, option, rect, index);
break; break;
default: default:
paintRingContactItem(painter, option, rect, index); paintRingContactItem(painter, option, rect, index);
...@@ -183,9 +184,68 @@ ContactPickerItemDelegate::paintRingContactItem(QPainter* painter, ...@@ -183,9 +184,68 @@ ContactPickerItemDelegate::paintRingContactItem(QPainter* painter,
void void
ContactPickerItemDelegate::paintSIPContactItem(QPainter* painter, ContactPickerItemDelegate::paintSIPContactItem(QPainter* painter,
const QStyleOptionViewItem& option, const QStyleOptionViewItem& option,
const QRect& rect,
const QModelIndex& index) const const QModelIndex& index) const
{ {
Q_UNUSED(painter);
Q_UNUSED(option); Q_UNUSED(option);
Q_UNUSED(index); QRect rectName1;
QRect rectName2;
QFont font(painter->font());
QPen pen(painter->pen());
painter->setPen(pen);
auto scalingRatio = MainWindow::instance().getCurrentScalingRatio();
if (scalingRatio > 1.0) {
font.setPointSize(fontSize_ - 2);
} else {
font.setPointSize(fontSize_);
}
auto leftMargin = dx_ + sizeImage_ + dx_;
auto rightMargin = dx_;
auto topMargin = 4;
auto bottomMargin = 8;
if (!rect.isEmpty()) {
rectName1 = QRect(rect.left() + leftMargin,
rect.top() + topMargin,
rect.width() - leftMargin * 2,
rect.height() / 2 - 2);
rectName2 = QRect(rectName1.left(),
rectName1.top() + rectName1.height(),
rectName1.width(),
rectName1.height() - bottomMargin);
}
QFontMetrics fontMetrics(font);
// The name is displayed at the avatar's right
QString nameStr = index.data(static_cast<int>(SmartListModel::Role::DisplayName)).value<QString>();
if (!nameStr.isNull()) {
font.setItalic(false);
font.setBold(false);
pen.setColor(RingTheme::lightBlack_);
painter->setPen(pen);
painter->setFont(font);
if (!rectName1.isEmpty()) {
QString elidedNameStr = fontMetrics.elidedText(nameStr, Qt::ElideRight, rectName1.width());
painter->drawText(rectName1, Qt::AlignVCenter | Qt::AlignLeft, elidedNameStr);
}
}
// Display the ID under the name
QString idStr = index.data(static_cast<int>(SmartListModel::Role::DisplayID)).value<QString>();
if (idStr != nameStr && !idStr.isNull()) {
font.setItalic(false);
font.setBold(false);
pen.setColor(RingTheme::grey_);
painter->setPen(pen);
painter->setFont(font);
if (!rectName2.isEmpty()) {
idStr = fontMetrics.elidedText(idStr, Qt::ElideRight, rectName2.width());
painter->drawText(rectName2, Qt::AlignVCenter | Qt::AlignLeft, idStr);
}
}
} }
...@@ -35,7 +35,7 @@ protected: ...@@ -35,7 +35,7 @@ protected:
private: private:
void paintRingContactItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const; void paintRingContactItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const;
void paintSIPContactItem(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; void paintSIPContactItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const;
constexpr static int sizeImage_ = 48; constexpr static int sizeImage_ = 48;
constexpr static int cellHeight_ = 60; constexpr static int cellHeight_ = 60;
......
...@@ -177,7 +177,7 @@ QWidget#messageViewLayoutWidget, QWidget#welcomePage { ...@@ -177,7 +177,7 @@ QWidget#messageViewLayoutWidget, QWidget#welcomePage {
QPushButton#holdButton, QPushButton#chatButton, QPushButton#noMicButton, QPushButton#noVideoButton, QPushButton#holdButton, QPushButton#chatButton, QPushButton#noMicButton, QPushButton#noVideoButton,
QPushButton#transferButton, QPushButton#addPersonButton, QPushButton#joinButton, QPushButton#transferButton, QPushButton#addPersonButton, QPushButton#joinButton,
QPushButton#qualityButton, QPushButton#recButton { QPushButton#qualityButton, QPushButton#recButton, QPushButton#transferCallButton {
background-color: rgba(0, 0, 0, 140); background-color: rgba(0, 0, 0, 140);
border-radius: 18px; border-radius: 18px;
border: solid 1px; border: solid 1px;
...@@ -186,7 +186,7 @@ QPushButton#qualityButton, QPushButton#recButton { ...@@ -186,7 +186,7 @@ QPushButton#qualityButton, QPushButton#recButton {
QPushButton#holdButton:hover, QPushButton#chatButton:hover, QPushButton#noMicButton:hover, QPushButton#holdButton:hover, QPushButton#chatButton:hover, QPushButton#noMicButton:hover,
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#recButton:hover, QPushButton#transferCallButton:hover {
background-color: rgba(0, 192, 213, 0.6); background-color: rgba(0, 192, 213, 0.6);
} }
...@@ -199,7 +199,7 @@ QPushButton#recButton:pressed { ...@@ -199,7 +199,7 @@ QPushButton#recButton:pressed {
QPushButton#holdButton:checked, QPushButton#noMicButton:checked, QPushButton#holdButton:checked, QPushButton#noMicButton:checked,
QPushButton#noVideoButton:checked, QPushButton#recButton:checked, QPushButton#noVideoButton:checked, QPushButton#recButton:checked,
QPushButton#chatButton:checked{ QPushButton#chatButton:checked, QPushButton#transferCallButton:checked {
background-color: rgba(0, 192, 213, 0.8); background-color: rgba(0, 192, 213, 0.8);
} }
......
...@@ -44,6 +44,15 @@ VideoOverlay::VideoOverlay(QWidget* parent) : ...@@ -44,6 +44,15 @@ VideoOverlay::VideoOverlay(QWidget* parent) :
ui->onHoldLabel->setVisible(false); ui->onHoldLabel->setVisible(false);
ui->recButton->setVisible(false); ui->recButton->setVisible(false);
ui->transferCallButton->setVisible(false);
ui->transferCallButton->setCheckable(true);
contactPicker_->setVisible(false);
contactPicker_->setTitle("Select Peer to Tranfer");
connect(ui->transferCallButton, &QPushButton::toggled, this, &VideoOverlay::on_transferButton_toggled);
connect(contactPicker_, &ContactPicker::contactWillDoTransfer, this, &VideoOverlay::on_transferCall_requested);
} }
VideoOverlay::~VideoOverlay() VideoOverlay::~VideoOverlay()
...@@ -176,6 +185,79 @@ VideoOverlay::on_recButton_clicked() ...@@ -176,6 +185,79 @@ VideoOverlay::on_recButton_clicked()
} }
} }
void
VideoOverlay::setTransferCallAvailability(bool visible)
{
ui->transferCallButton->setVisible(visible);
}
void
VideoOverlay::on_transferButton_toggled(bool checked)
{
if (callId_.empty() || !checked) {
return;
}
contactPicker_->setType(ContactPicker::Type::TRANSFER);
QPoint globalPos_button = mapToGlobal(ui->transferCallButton->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 relativeCursorPos = ui->transferCallButton->mapFromGlobal(event->pos());
if (!ui->transferCallButton->rect().contains(relativeCursorPos)) {
ui->transferCallButton->setChecked(false);
}
});
// for esc key, receive reject signal
Utils::oneShotConnect(contactPicker_, &QDialog::rejected,
[this] {
ui->transferCallButton->setChecked(false);
});
contactPicker_->show();
}
void
VideoOverlay::on_transferCall_requested(const std::string& callId, const std::string& contactUri)
{
auto callModel = LRCInstance::getCurrentCallModel();
contactPicker_->hide();
ui->transferCallButton->setChecked(false);
std::string destCallId;
try {
//check if the call exist - (check non-finished calls)
auto callInfo = callModel->getCallFromURI(contactUri, true);
destCallId = callInfo.id;
} catch(std::exception& e) {
qDebug().noquote() << e.what();
destCallId = "";
}
// if no second call -> blind transfer
// if there is a second call -> attended transfer
if (destCallId.size() == 0) {
callModel->transfer(callId, "sip:" + contactUri);
callModel->hangUp(callId);
}else{
callModel->transferToCall(callId, destCallId);
callModel->hangUp(callId);
callModel->hangUp(destCallId);
}
}
void
VideoOverlay::setCurrentSelectedCalleeDisplayName(const QString& CalleeDisplayName)
{
contactPicker_->setCurrentCalleeDisplayName(CalleeDisplayName);
}
void void
VideoOverlay::resetOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding) VideoOverlay::resetOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding)
{ {
......
...@@ -45,6 +45,8 @@ public: ...@@ -45,6 +45,8 @@ public:
bool shouldShowOverlay(); bool shouldShowOverlay();
void simulateShowChatview(bool checked); void simulateShowChatview(bool checked);
bool getShowChatView(); bool getShowChatView();
void setTransferCallAvailability(bool visible);
void setCurrentSelectedCalleeDisplayName(const QString& CalleeDisplayName);
void resetOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding); void resetOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding);
//UI SLOTS //UI SLOTS
...@@ -56,6 +58,8 @@ private slots: ...@@ -56,6 +58,8 @@ private slots:
void on_noMicButton_toggled(bool checked); void on_noMicButton_toggled(bool checked);
void on_noVideoButton_toggled(bool checked); void on_noVideoButton_toggled(bool checked);
void on_recButton_clicked(); void on_recButton_clicked();
void on_transferButton_toggled(bool checked);
void on_transferCall_requested(const std::string& callId, const std::string& contactUri);
private: private:
Ui::VideoOverlay* ui; Ui::VideoOverlay* ui;
......
...@@ -333,7 +333,7 @@ VideoView::showContextMenu(const QPoint& pos) ...@@ -333,7 +333,7 @@ VideoView::showContextMenu(const QPoint& pos)
} }
void void
VideoView::pushRenderer(const std::string& callId) { VideoView::pushRenderer(const std::string& callId, bool isSIP) {
auto callModel = LRCInstance::getCurrentCallModel(); auto callModel = LRCInstance::getCurrentCallModel();
QObject::disconnect(ui->videoWidget); QObject::disconnect(ui->videoWidget);
...@@ -349,6 +349,8 @@ VideoView::pushRenderer(const std::string& callId) { ...@@ -349,6 +349,8 @@ VideoView::pushRenderer(const std::string& callId) {
return; return;
} }
// transfer call will only happen in SIP calls
this->overlay_->setTransferCallAvailability(isSIP);
this->overlay_->callStarted(callId); this->overlay_->callStarted(callId);
this->overlay_->setVideoMuteVisibility(!LRCInstance::getCurrentCallModel()->getCall(callId).isAudioOnly); this->overlay_->setVideoMuteVisibility(!LRCInstance::getCurrentCallModel()->getCall(callId).isAudioOnly);
...@@ -426,6 +428,13 @@ VideoView::mouseMoveEvent(QMouseEvent* event) ...@@ -426,6 +428,13 @@ VideoView::mouseMoveEvent(QMouseEvent* event)
and geometry().contains(event->pos())) and geometry().contains(event->pos()))
previewRect.setBottomRight(event->pos()); previewRect.setBottomRight(event->pos());
} }
void
VideoView::setCurrentCalleeName(const QString& CalleeDisplayName)
{
overlay_->setCurrentSelectedCalleeDisplayName(CalleeDisplayName);
}
void void
VideoView::resetVideoOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding) VideoView::resetVideoOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding)
{ {
......
...@@ -36,8 +36,10 @@ class VideoView : public QWidget ...@@ -36,8 +36,10 @@ class VideoView : public QWidget
public: public:
explicit VideoView(QWidget* parent = 0); explicit VideoView(QWidget* parent = 0);
~VideoView(); ~VideoView();
void pushRenderer(const std::string& callUid); void pushRenderer(const std::string& callUid, bool isSIP);
void showChatviewIfToggled();
void simulateShowChatview(bool checked); void simulateShowChatview(bool checked);
void setCurrentCalleeName(const QString& CalleeDisplayName);
void resetVideoOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding); void resetVideoOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding);
protected: protected:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment