From 22db039cdd0f758248f805a506f4ad2eae8a2251 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 30 May 2017 11:31:03 +0200 Subject: [PATCH] feat(ui/views/App/Calls/CallsWindow): supports call transfer --- linphone-desktop/assets/languages/en.ts | 11 ++ linphone-desktop/assets/languages/fr.ts | 11 ++ linphone-desktop/resources.qrc | 2 + .../src/components/call/CallModel.cpp | 11 ++ .../src/components/call/CallModel.hpp | 2 + .../src/components/calls/CallsListModel.cpp | 30 +++--- .../src/components/calls/CallsListModel.hpp | 1 + .../src/components/core/CoreHandlers.cpp | 53 ++++++++- .../src/components/core/CoreHandlers.hpp | 8 ++ .../ui/views/App/Calls/CallsWindow.js | 11 +- .../views/App/Calls/Dialogs/CallTransfer.qml | 102 ++++++++++++++++++ .../Calls/Dialogs/CallTransferStyle.qml | 12 +++ linphone-desktop/ui/views/App/Styles/qmldir | 2 + 13 files changed, 238 insertions(+), 18 deletions(-) create mode 100644 linphone-desktop/ui/views/App/Calls/Dialogs/CallTransfer.qml create mode 100644 linphone-desktop/ui/views/App/Styles/Calls/Dialogs/CallTransferStyle.qml 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