diff --git a/linphone-desktop/assets/languages/en.ts b/linphone-desktop/assets/languages/en.ts
index 8adc2ca6b..5d14a2aa3 100644
--- a/linphone-desktop/assets/languages/en.ts
+++ b/linphone-desktop/assets/languages/en.ts
@@ -280,6 +280,17 @@
Video
+
+ CallTransfer
+
+ cancel
+ CANCEL
+
+
+ callTransferDescription
+ Do you want to transfer this call ?
+
+
Calls
diff --git a/linphone-desktop/assets/languages/fr.ts b/linphone-desktop/assets/languages/fr.ts
index 6155dc0f4..228ac12fe 100644
--- a/linphone-desktop/assets/languages/fr.ts
+++ b/linphone-desktop/assets/languages/fr.ts
@@ -280,6 +280,17 @@
Vidéo
+
+ CallTransfer
+
+ cancel
+ ANNULER
+
+
+ callTransferDescription
+ Voulez-vous transférer cet appel ?
+
+
Calls
diff --git a/linphone-desktop/resources.qrc b/linphone-desktop/resources.qrc
index 181a5c5ef..5b8b2f316 100644
--- a/linphone-desktop/resources.qrc
+++ b/linphone-desktop/resources.qrc
@@ -358,6 +358,7 @@
ui/views/App/Calls/CallsWindow.qml
ui/views/App/Calls/ConferenceManager.qml
ui/views/App/Calls/Conference.qml
+ ui/views/App/Calls/Dialogs/CallTransfer.qml
ui/views/App/Calls/EndedCall.qml
ui/views/App/Calls/IncallFullscreenWindow.qml
ui/views/App/Calls/Incall.js
@@ -408,6 +409,7 @@
ui/views/App/Styles/Calls/CallsWindowStyle.qml
ui/views/App/Styles/Calls/ConferenceManagerStyle.qml
ui/views/App/Styles/Calls/ConferenceStyle.qml
+ ui/views/App/Styles/Calls/Dialogs/CallTransferStyle.qml
ui/views/App/Styles/Main/AboutStyle.qml
ui/views/App/Styles/Main/Assistant/ActivateLinphoneSipAccountWithEmailStyle.qml
ui/views/App/Styles/Main/Assistant/AssistantAbstractViewStyle.qml
diff --git a/linphone-desktop/src/components/call/CallModel.cpp b/linphone-desktop/src/components/call/CallModel.cpp
index a9937adb2..d164e234c 100644
--- a/linphone-desktop/src/components/call/CallModel.cpp
+++ b/linphone-desktop/src/components/call/CallModel.cpp
@@ -135,10 +135,21 @@ void CallModel::terminate () {
core->unlockVideoRender();
}
+// -----------------------------------------------------------------------------
+
void CallModel::askForTransfer () {
CoreManager::getInstance()->getCallsListModel()->askForTransfer(this);
}
+bool CallModel::transferTo (const QString &sipAddress) {
+ bool status = !!mCall->transfer(::Utils::qStringToLinphoneString(sipAddress));
+ if (status)
+ qWarning() << QStringLiteral("Unable to transfer: `%1`.").arg(sipAddress);
+ return status;
+}
+
+// -----------------------------------------------------------------------------
+
void CallModel::acceptVideoRequest () {
shared_ptr core = CoreManager::getInstance()->getCore();
shared_ptr params = core->createCallParams(mCall);
diff --git a/linphone-desktop/src/components/call/CallModel.hpp b/linphone-desktop/src/components/call/CallModel.hpp
index 3e816a277..e1a9f30b2 100644
--- a/linphone-desktop/src/components/call/CallModel.hpp
+++ b/linphone-desktop/src/components/call/CallModel.hpp
@@ -86,7 +86,9 @@ public:
Q_INVOKABLE void accept ();
Q_INVOKABLE void acceptWithVideo ();
Q_INVOKABLE void terminate ();
+
Q_INVOKABLE void askForTransfer ();
+ Q_INVOKABLE bool transferTo (const QString &sipAddress);
Q_INVOKABLE void acceptVideoRequest ();
Q_INVOKABLE void rejectVideoRequest ();
diff --git a/linphone-desktop/src/components/calls/CallsListModel.cpp b/linphone-desktop/src/components/calls/CallsListModel.cpp
index 79b0c0bb0..c96f9a403 100644
--- a/linphone-desktop/src/components/calls/CallsListModel.cpp
+++ b/linphone-desktop/src/components/calls/CallsListModel.cpp
@@ -212,18 +212,20 @@ void CallsListModel::removeCall (const shared_ptr &call) {
return;
}
- QTimer::singleShot(
- DELAY_BEFORE_REMOVE_CALL, this, [this, callModel]() {
- qInfo() << QStringLiteral("Removing call:") << callModel;
-
- int index = mList.indexOf(callModel);
- if (index == -1 || !removeRow(index))
- qWarning() << QStringLiteral("Unable to remove call:") << callModel;
-
- if (mList.empty() && ConferenceHelperModel::getInstancesNumber() == 0) {
- qInfo() << QStringLiteral("Last call terminated, close calls window.");
- App::getInstance()->getCallsWindow()->close();
- }
- }
- );
+ QTimer::singleShot(DELAY_BEFORE_REMOVE_CALL, this, [this, callModel] {
+ removeCallCb(callModel);
+ });
+}
+
+void CallsListModel::removeCallCb (CallModel *callModel) {
+ qInfo() << QStringLiteral("Removing call:") << callModel;
+
+ int index = mList.indexOf(callModel);
+ if (index == -1 || !removeRow(index))
+ qWarning() << QStringLiteral("Unable to remove call:") << callModel;
+
+ if (mList.empty() && ConferenceHelperModel::getInstancesNumber() == 0) {
+ qInfo() << QStringLiteral("Last call terminated, close calls window.");
+ App::getInstance()->getCallsWindow()->close();
+ }
}
diff --git a/linphone-desktop/src/components/calls/CallsListModel.hpp b/linphone-desktop/src/components/calls/CallsListModel.hpp
index 4dbe29515..ae9c92e09 100644
--- a/linphone-desktop/src/components/calls/CallsListModel.hpp
+++ b/linphone-desktop/src/components/calls/CallsListModel.hpp
@@ -64,6 +64,7 @@ private:
void addCall (const std::shared_ptr &call);
void removeCall (const std::shared_ptr &call);
+ void removeCallCb (CallModel *callModel);
QList mList;
diff --git a/linphone-desktop/src/components/core/CoreHandlers.cpp b/linphone-desktop/src/components/core/CoreHandlers.cpp
index d177222d6..bafdc8410 100644
--- a/linphone-desktop/src/components/core/CoreHandlers.cpp
+++ b/linphone-desktop/src/components/core/CoreHandlers.cpp
@@ -38,9 +38,9 @@ using namespace std;
// Schedule a function in app context.
void scheduleFunctionInApp (function func) {
App *app = App::getInstance();
- if (QThread::currentThread() != app->thread()) {
+ if (QThread::currentThread() != app->thread())
QTimer::singleShot(0, app, func);
- } else
+ else
func();
}
@@ -168,3 +168,52 @@ void CoreHandlers::onRegistrationStateChanged (
) {
emit registrationStateChanged(proxyConfig, state);
}
+
+void CoreHandlers::onTransferStateChanged (
+ const shared_ptr &,
+ const shared_ptr &call,
+ linphone::CallState state
+) {
+ switch (state) {
+ case linphone::CallStateEarlyUpdatedByRemote:
+ case linphone::CallStateEarlyUpdating:
+ case linphone::CallStateIdle:
+ case linphone::CallStateIncomingEarlyMedia:
+ case linphone::CallStateIncomingReceived:
+ case linphone::CallStateOutgoingEarlyMedia:
+ case linphone::CallStateOutgoingRinging:
+ case linphone::CallStatePaused:
+ case linphone::CallStatePausedByRemote:
+ case linphone::CallStatePausing:
+ case linphone::CallStateRefered:
+ case linphone::CallStateReleased:
+ case linphone::CallStateResuming:
+ case linphone::CallStateStreamsRunning:
+ case linphone::CallStateUpdatedByRemote:
+ case linphone::CallStateUpdating:
+ break; // Nothing.
+
+ // 1. Init.
+ case linphone::CallStateOutgoingInit:
+ qInfo() << QStringLiteral("Call transfer init.");
+ break;
+
+ // 2. In progress.
+ case linphone::CallStateOutgoingProgress:
+ qInfo() << QStringLiteral("Call transfer in progress.");
+ break;
+
+ // 3. Done.
+ case linphone::CallStateConnected:
+ qInfo() << QStringLiteral("Call transfer succeeded.");
+ emit callTransferSucceeded(call);
+ break;
+
+ // 4. Error.
+ case linphone::CallStateEnd:
+ case linphone::CallStateError:
+ qWarning() << QStringLiteral("Call transfer failed.");
+ emit callTransferFailed(call);
+ break;
+ }
+}
diff --git a/linphone-desktop/src/components/core/CoreHandlers.hpp b/linphone-desktop/src/components/core/CoreHandlers.hpp
index e3132a128..740ea8263 100644
--- a/linphone-desktop/src/components/core/CoreHandlers.hpp
+++ b/linphone-desktop/src/components/core/CoreHandlers.hpp
@@ -43,6 +43,8 @@ public:
signals:
void authenticationRequested (const std::shared_ptr &authInfo);
void callStateChanged (const std::shared_ptr &call, linphone::CallState state);
+ void callTransferFailed (const std::shared_ptr &call);
+ void callTransferSucceeded (const std::shared_ptr &call);
void coreStarted ();
void messageReceived (const std::shared_ptr &message);
void presenceReceived (const QString &sipAddress, const std::shared_ptr &presenceModel);
@@ -107,6 +109,12 @@ private:
const std::string &message
) override;
+ void onTransferStateChanged (
+ const std::shared_ptr &core,
+ const std::shared_ptr &call,
+ linphone::CallState state
+ ) override;
+
// ---------------------------------------------------------------------------
bool mCoreCreated = false;
diff --git a/linphone-desktop/ui/views/App/Calls/CallsWindow.js b/linphone-desktop/ui/views/App/Calls/CallsWindow.js
index 879cee6a4..789a50d84 100644
--- a/linphone-desktop/ui/views/App/Calls/CallsWindow.js
+++ b/linphone-desktop/ui/views/App/Calls/CallsWindow.js
@@ -22,7 +22,7 @@ function handleClosing (close) {
}
window.attachVirtualWindow(Utils.buildDialogUri('ConfirmDialog'), {
- descriptionText: qsTr('acceptClosingDescription'),
+ descriptionText: qsTr('acceptClosingDescription')
}, function (status) {
if (status) {
forceClose = true
@@ -71,5 +71,12 @@ function getContent () {
// -----------------------------------------------------------------------------
function handleCallTransferAsked (call) {
- console.log('TODO: handle call transfer')
+ if (!call) {
+ return
+ }
+
+ window.detachVirtualWindow()
+ window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/CallTransfer.qml'), {
+ call: call
+ })
}
diff --git a/linphone-desktop/ui/views/App/Calls/Dialogs/CallTransfer.qml b/linphone-desktop/ui/views/App/Calls/Dialogs/CallTransfer.qml
new file mode 100644
index 000000000..e8a5a9eb3
--- /dev/null
+++ b/linphone-desktop/ui/views/App/Calls/Dialogs/CallTransfer.qml
@@ -0,0 +1,102 @@
+import QtQuick 2.7
+import QtQuick.Layouts 1.3
+
+import Common 1.0
+import Linphone 1.0
+
+import App.Styles 1.0
+
+// =============================================================================
+
+DialogPlus {
+ id: callTransfer
+
+ // ---------------------------------------------------------------------------
+
+ property var call
+
+ // ---------------------------------------------------------------------------
+
+ buttons: [
+ TextButtonA {
+ text: qsTr('cancel')
+
+ onClicked: exit(0)
+ }
+ ]
+
+ centeredButtons: true
+ descriptionText: qsTr('callTransferDescription')
+
+ height: CallTransferStyle.height
+ width: CallTransferStyle.width
+
+ onCallChanged: !call && exit(0)
+
+ // ---------------------------------------------------------------------------
+
+ ColumnLayout {
+ anchors {
+ fill: parent
+ leftMargin: CallTransferStyle.leftMargin
+ rightMargin: CallTransferStyle.rightMargin
+ }
+
+ spacing: 0
+
+ Contact {
+ Layout.fillWidth: true
+
+ entry: SipAddressesModel.getSipAddressObserver(call ? call.sipAddress : '')
+ }
+
+ // -------------------------------------------------------------------------
+ // Address selector.
+ // -------------------------------------------------------------------------
+
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: CallTransferStyle.spacing
+
+ TextField {
+ id: filter
+
+ Layout.fillWidth: true
+
+ icon: 'search'
+
+ onTextChanged: sipAddressesModel.setFilter(text)
+ }
+
+ ScrollableListViewField {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ SipAddressesView {
+ anchors.fill: parent
+
+ actions: [{
+ icon: 'transfer',
+ handler: function (entry) {
+ callTransfer.call.transferTo(entry.sipAddress)
+ exit(1)
+ }
+ }]
+
+ genSipAddress: filter.text
+
+ model: SipAddressesProxyModel {
+ id: sipAddressesModel
+ }
+
+ onEntryClicked: actions[0].handler(entry)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/linphone-desktop/ui/views/App/Styles/Calls/Dialogs/CallTransferStyle.qml b/linphone-desktop/ui/views/App/Styles/Calls/Dialogs/CallTransferStyle.qml
new file mode 100644
index 000000000..8c3d0480b
--- /dev/null
+++ b/linphone-desktop/ui/views/App/Styles/Calls/Dialogs/CallTransferStyle.qml
@@ -0,0 +1,12 @@
+pragma Singleton
+import QtQuick 2.7
+
+// =============================================================================
+
+QtObject {
+ property int height: 420
+ property int leftMargin: 35
+ property int rightMargin: 35
+ property int spacing: 10
+ property int width: 450
+}
diff --git a/linphone-desktop/ui/views/App/Styles/qmldir b/linphone-desktop/ui/views/App/Styles/qmldir
index 598bd49a3..ce9b4f680 100644
--- a/linphone-desktop/ui/views/App/Styles/qmldir
+++ b/linphone-desktop/ui/views/App/Styles/qmldir
@@ -9,6 +9,8 @@ singleton CallsWindowStyle 1.0 Calls/CallsWindowStyle.qm
singleton ConferenceManagerStyle 1.0 Calls/ConferenceManagerStyle.qml
singleton ConferenceStyle 1.0 Calls/ConferenceStyle.qml
+singleton CallTransferStyle 1.0 Calls/Dialogs/CallTransferStyle.qml
+
singleton ActivateLinphoneSipAccountWithEmailStyle 1.0 Main/Assistant/ActivateLinphoneSipAccountWithEmailStyle.qml
singleton AssistantAbstractViewStyle 1.0 Main/Assistant/AssistantAbstractViewStyle.qml
singleton AssistantHomeStyle 1.0 Main/Assistant/AssistantHomeStyle.qml