From 4effc5dc6efbe6e312d530f8b985c1ffac0fbd6f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Jan 2017 11:31:33 +0100 Subject: [PATCH] feat(app): calls in progress (fix crash, remove `CaterpillarAnimation`) --- tests/resources.qrc | 3 +- tests/src/components/call/CallModel.cpp | 8 ++ tests/src/components/call/CallModel.hpp | 5 + tests/src/components/calls/CallsListModel.cpp | 25 ++++- tests/src/components/calls/CallsListModel.hpp | 3 + .../Common/{ => Animations}/BusyIndicator.qml | 4 +- .../Animations/CaterpillarAnimation.qml | 101 ------------------ tests/ui/modules/Common/qmldir | 5 +- tests/ui/modules/Linphone/Calls/Calls.qml | 47 +++++--- .../views/App/Calls/AbstractStartingCall.qml | 13 ++- tests/ui/views/App/Calls/CallsWindow.qml | 41 +++---- tests/ui/views/App/Calls/Incall.qml | 4 - tests/ui/views/App/Calls/IncomingCall.qml | 8 +- tests/ui/views/App/Calls/OutgoingCall.qml | 6 +- tests/ui/views/App/MainWindow/Contacts.qml | 4 +- .../ui/views/App/MainWindow/Conversation.qml | 6 +- tests/ui/views/App/MainWindow/MainWindow.qml | 4 +- .../App/Styles/Calls/StartingCallStyle.qml | 6 ++ 18 files changed, 122 insertions(+), 171 deletions(-) rename tests/ui/modules/Common/{ => Animations}/BusyIndicator.qml (95%) delete mode 100644 tests/ui/modules/Common/Animations/CaterpillarAnimation.qml diff --git a/tests/resources.qrc b/tests/resources.qrc index 3ecda11f3..06fca156e 100644 --- a/tests/resources.qrc +++ b/tests/resources.qrc @@ -143,9 +143,8 @@ assets/images/video_call_hovered.svg assets/images/video_call_normal.svg assets/images/video_call_pressed.svg - ui/modules/Common/Animations/CaterpillarAnimation.qml + ui/modules/Common/Animations/BusyIndicator.qml ui/modules/Common/Borders.qml - ui/modules/Common/BusyIndicator.qml ui/modules/Common/Collapse.qml ui/modules/Common/Colors.qml ui/modules/Common/Constants.qml diff --git a/tests/src/components/call/CallModel.cpp b/tests/src/components/call/CallModel.cpp index 7546e9443..e70a436fb 100644 --- a/tests/src/components/call/CallModel.cpp +++ b/tests/src/components/call/CallModel.cpp @@ -123,3 +123,11 @@ void CallModel::setPausedByUser (bool status) { emit pausedByUserChanged(false); } } + +bool CallModel::getVideoOutputEnabled () const { + // TODO +} + +void CallModel::setVideoOutputEnabled (bool status) { + // TODO +} diff --git a/tests/src/components/call/CallModel.hpp b/tests/src/components/call/CallModel.hpp index 9f98cd63c..a5b07c5e7 100644 --- a/tests/src/components/call/CallModel.hpp +++ b/tests/src/components/call/CallModel.hpp @@ -14,6 +14,7 @@ class CallModel : public QObject { Q_PROPERTY(bool isOutgoing READ isOutgoing CONSTANT); Q_PROPERTY(bool microMuted READ getMicroMuted WRITE setMicroMuted NOTIFY microMutedChanged); Q_PROPERTY(bool pausedByUser READ getPausedByUser WRITE setPausedByUser NOTIFY pausedByUserChanged); + Q_PROPERTY(bool videoOutputEnabled READ getVideoOutputEnabled WRITE setVideoOutputEnabled NOTIFY videoOutputEnabled); public: enum CallStatus { @@ -39,6 +40,7 @@ signals: void statusChanged (CallStatus status); void pausedByUserChanged (bool status); void microMutedChanged (bool status); + void videoOutputEnabled (bool status); private: QString getSipAddress () const; @@ -54,6 +56,9 @@ private: bool getPausedByUser () const; void setPausedByUser (bool status); + bool getVideoOutputEnabled () const; + void setVideoOutputEnabled (bool status); + bool m_micro_muted = false; linphone::CallState m_linphone_call_status = linphone::CallStateIdle; diff --git a/tests/src/components/calls/CallsListModel.cpp b/tests/src/components/calls/CallsListModel.cpp index 62fe0b5f0..64a72607b 100644 --- a/tests/src/components/calls/CallsListModel.cpp +++ b/tests/src/components/calls/CallsListModel.cpp @@ -2,6 +2,7 @@ #include #include "../../app/App.hpp" +#include "../../utils.hpp" #include "../core/CoreManager.hpp" #include "CallsListModel.hpp" @@ -60,6 +61,19 @@ QVariant CallsListModel::data (const QModelIndex &index, int role) const { // ----------------------------------------------------------------------------- +void CallsListModel::launchAudioCall (const QString &sip_uri) const { + shared_ptr core = CoreManager::getInstance()->getCore(); + core->inviteAddress( + core->interpretUrl(::Utils::qStringToLinphoneString(sip_uri)) + ); +} + +void CallsListModel::launchVideoCall (const QString &sip_uri) const { + // TODO +} + +// ----------------------------------------------------------------------------- + bool CallsListModel::removeRow (int row, const QModelIndex &parent) { return removeRows(row, 1, parent); } @@ -86,6 +100,9 @@ void CallsListModel::addCall (const shared_ptr &linphone_call) { App::getInstance()->getCallsWindow()->show(); CallModel *call = new CallModel(linphone_call); + + qInfo() << "Add call:" << call; + App::getInstance()->getEngine()->setObjectOwnership(call, QQmlEngine::CppOwnership); linphone_call->setData("call-model", *call); @@ -97,12 +114,12 @@ void CallsListModel::addCall (const shared_ptr &linphone_call) { } void CallsListModel::removeCall (const shared_ptr &linphone_call) { - CallModel *call = &linphone_call->getData("call-model"); - linphone_call->unsetData("call-model"); - // TODO: It will be (maybe) necessary to use a single scheduled function in the future. QTimer::singleShot( - DELAY_BEFORE_REMOVE_CALL, this, [this, call]() { + DELAY_BEFORE_REMOVE_CALL, this, [this, linphone_call]() { + CallModel *call = &linphone_call->getData("call-model"); + linphone_call->unsetData("call-model"); + qInfo() << "Removing call:" << call; int index = m_list.indexOf(call); diff --git a/tests/src/components/calls/CallsListModel.hpp b/tests/src/components/calls/CallsListModel.hpp index daf9ef5d7..715a2b9fb 100644 --- a/tests/src/components/calls/CallsListModel.hpp +++ b/tests/src/components/calls/CallsListModel.hpp @@ -21,6 +21,9 @@ public: QHash roleNames () const override; QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override; + Q_INVOKABLE void launchAudioCall (const QString &sip_uri) const; + Q_INVOKABLE void launchVideoCall (const QString &sip_uri) const; + private: bool removeRow (int row, const QModelIndex &parent = QModelIndex()); bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override; diff --git a/tests/ui/modules/Common/BusyIndicator.qml b/tests/ui/modules/Common/Animations/BusyIndicator.qml similarity index 95% rename from tests/ui/modules/Common/BusyIndicator.qml rename to tests/ui/modules/Common/Animations/BusyIndicator.qml index 86cb30e80..a62fe70a3 100644 --- a/tests/ui/modules/Common/BusyIndicator.qml +++ b/tests/ui/modules/Common/Animations/BusyIndicator.qml @@ -10,6 +10,8 @@ BusyIndicator { // --------------------------------------------------------------------------- + property color color: BusyIndicatorStyle.color + readonly property int _rotation: 360 readonly property int _size: width < height ? width : height @@ -58,7 +60,7 @@ BusyIndicator { height: item.height / 3 width: item.width / 3 - color: BusyIndicatorStyle.color + color: busyIndicator.color radius: (width > height ? width : height) / 2 transform: [ diff --git a/tests/ui/modules/Common/Animations/CaterpillarAnimation.qml b/tests/ui/modules/Common/Animations/CaterpillarAnimation.qml deleted file mode 100644 index 66e5212e4..000000000 --- a/tests/ui/modules/Common/Animations/CaterpillarAnimation.qml +++ /dev/null @@ -1,101 +0,0 @@ -import QtQuick 2.7 - -import Common.Styles 1.0 - -// ============================================================================= - -Row { - id: container - - property color sphereColor: CaterpillarAnimationStyle.sphere.color - property int animationDuration: CaterpillarAnimationStyle.animation.duration - property int nSpheres: CaterpillarAnimationStyle.nSpheres - property int sphereSize: CaterpillarAnimationStyle.sphere.size - property int animationSpace: CaterpillarAnimationStyle.animation.space - - spacing: CaterpillarAnimationStyle.spacing - - Repeater { - id: repeater - - model: nSpheres - - Rectangle { - id: sphere - - property bool forceRunning: false - property int previousY: 0 - - function startAnimation () { - if (!animator.running) { - animator.running = true - } else { - forceRunning = true - } - } - - color: sphereColor - height: width - radius: width / 2 - width: container.sphereSize - - // y can be: `0`, `animationSpace` or `animationSpace / 2` - onYChanged: { - // No call executed by last sphere. - if (index === nSpheres - 1) { - return - } - - if (y === (animationSpace / 2) && previousY === 0) { - repeater.itemAt(index + 1).startAnimation() - } - - previousY = y - } - - Component.onCompleted: { - // Only start first sphere. - if (index === 0) { - animator.running = true - } - } - - YAnimator on y { - id: animator - - duration: container.animationDuration - from: 0 - running: false - to: animationSpace / 2 - - onRunningChanged: { - if (running) { - return - } - - var mid = animationSpace / 2 - if (from === animationSpace && to === mid) { - from = mid - to = 0 - } else if (from === mid && to === 0) { - from = 0 - to = mid - - if (index !== 0 && !forceRunning) { - return - } - } else if (from === 0 && to === mid) { - from = mid - to = animationSpace - } else { - from = animationSpace - to = mid - } - - forceRunning = false - animator.running = true - } - } - } - } -} diff --git a/tests/ui/modules/Common/qmldir b/tests/ui/modules/Common/qmldir index ab7b8e95a..0830b2ed8 100644 --- a/tests/ui/modules/Common/qmldir +++ b/tests/ui/modules/Common/qmldir @@ -12,14 +12,11 @@ singleton Constants 1.0 Constants.qml # Components ------------------------------------------------------------------- # Animations -CaterpillarAnimation 1.0 Animations/CaterpillarAnimation.qml +BusyIndicator 1.0 Animations/BusyIndicator.qml # Chat Borders 1.0 Borders.qml -# BusyIndicator -BusyIndicator 1.0 BusyIndicator.qml - # Collapse Collapse 1.0 Collapse.qml diff --git a/tests/ui/modules/Linphone/Calls/Calls.qml b/tests/ui/modules/Linphone/Calls/Calls.qml index 6a37e87ff..01805226b 100644 --- a/tests/ui/modules/Linphone/Calls/Calls.qml +++ b/tests/ui/modules/Linphone/Calls/Calls.qml @@ -44,14 +44,14 @@ ListView { _mapStatusToParams[CallModel.CallStatusConnected] = { actions: [{ - name: qsTr('resumeCall'), - handler: (function (call) { call.pausedByUser = false }) + handler: (function (call) { call.pausedByUser = false }), + name: qsTr('resumeCall') }, { - name: qsTr('transferCall'), - handler: (function (call) { call.transfer() }) + handler: (function (call) { call.transfer() }), + name: qsTr('transferCall') }, { - name: qsTr('terminateCall'), - handler: (function (call) { call.terminate() }) + handler: (function (call) { call.terminate() }), + name: qsTr('terminateCall') }], component: callActions, string: 'connected' @@ -85,14 +85,14 @@ ListView { _mapStatusToParams[CallModel.CallStatusPaused] = { actions: [{ - name: qsTr('pauseCall'), - handler: (function (call) { call.pausedByUser = true }) + handler: (function (call) { call.pausedByUser = true }), + name: qsTr('pauseCall') }, { - name: qsTr('transferCall'), - handler: (function (call) { call.transfer() }) + handler: (function (call) { call.transfer() }), + name: qsTr('transferCall') }, { - name: qsTr('terminateCall'), - handler: (function (call) { call.terminate() }) + handler: (function (call) { call.terminate() }), + name: qsTr('terminateCall') }], component: callActions, string: 'paused' @@ -160,6 +160,29 @@ ListView { // --------------------------------------------------------------------------- + SmartConnect { + Component.onCompleted: { + this.connect(model, 'rowsAboutToBeRemoved', function (_, first, last) { + var index = calls.currentIndex + if (index >= first && index <= last) { // Remove current call. + if (model.rowCount() - (last - first + 1) <= 0) { + calls.currentIndex = -1 + } else { + calls.currentIndex = 0 + } + } else if (last < index) { // Remove before current call. + calls.currentIndex = index - (last - first + 1) + } + }) + + this.connect(model, 'rowsInserted', function (_, first, last) { + calls.currentIndex = first + }) + } + } + + // --------------------------------------------------------------------------- + delegate: CallControls { id: _callControls diff --git a/tests/ui/views/App/Calls/AbstractStartingCall.qml b/tests/ui/views/App/Calls/AbstractStartingCall.qml index f18641e90..4bc52158c 100644 --- a/tests/ui/views/App/Calls/AbstractStartingCall.qml +++ b/tests/ui/views/App/Calls/AbstractStartingCall.qml @@ -17,7 +17,8 @@ Rectangle { property var call default property alias _actionArea: actionArea.data - property var _contact: SipAddressesModel.mapSipAddressToContact(call.sipAddress) + + property var _contactObserver: SipAddressesModel.getContactObserver(sipAddress) // --------------------------------------------------------------------------- @@ -45,12 +46,16 @@ Rectangle { height: StartingCallStyle.contactDescriptionHeight horizontalTextAlignment: Text.AlignHCenter sipAddress: call.sipAddress - username: LinphoneUtils.getContactUsername(_contact || call.sipAddress) + username: LinphoneUtils.getContactUsername(_contactObserver.contact || call.sipAddress) width: parent.width } - CaterpillarAnimation { + BusyIndicator { anchors.horizontalCenter: parent.horizontalCenter + color: StartingCallStyle.busyIndicator.color + height: StartingCallStyle.busyIndicator.height + width: StartingCallStyle.busyIndicator.width + visible: call.isOutgoing } } @@ -81,7 +86,7 @@ Rectangle { anchors.centerIn: parent backgroundColor: StartingCallStyle.avatar.backgroundColor - image: _contact && _contact.avatar + image: _contactObserver.contact && _contactObserver.contact.avatar username: contactDescription.username height: _computeAvatarSize() diff --git a/tests/ui/views/App/Calls/CallsWindow.qml b/tests/ui/views/App/Calls/CallsWindow.qml index f69b25a32..df6baaccf 100644 --- a/tests/ui/views/App/Calls/CallsWindow.qml +++ b/tests/ui/views/App/Calls/CallsWindow.qml @@ -15,10 +15,7 @@ Window { // --------------------------------------------------------------------------- - readonly property var call: { - console.log('hihi') - return calls.selectedCall - } + readonly property var call: calls.selectedCall readonly property var sipAddress: { if (call) { return call.sipAddress @@ -27,18 +24,6 @@ Window { // --------------------------------------------------------------------------- - function launchAudioCall (sipAddress) { - window.show() - - } - - function launchVideoCall (sipAddress) { - window.show() - - } - - // --------------------------------------------------------------------------- - minimumHeight: CallsWindowStyle.minimumHeight minimumWidth: CallsWindowStyle.minimumWidth title: CallsWindowStyle.title @@ -125,7 +110,6 @@ Window { id: incomingCall IncomingCall { - anchors.fill: parent call: window.call } } @@ -134,7 +118,6 @@ Window { id: outgoingCall OutgoingCall { - anchors.fill: parent call: window.call } } @@ -143,11 +126,20 @@ Window { id: incall Incall { - anchors.fill: parent call: window.call } } + Component { + id: chat + + Chat { + proxyModel: ChatProxyModel { + sipAddress: window.sipAddress + } + } + } + // ----------------------------------------------------------------------- childA: Loader { @@ -158,11 +150,12 @@ Window { if (!call) { return null } - return incomingCall + var status = call.status if (status === CallModel.CallStatusIncoming) { return incomingCall } + if (status === CallModel.CallStatusOutgoing) { return outgoingCall } @@ -174,13 +167,7 @@ Window { childB: Loader { active: Boolean(window.call) anchors.fill: parent - - sourceComponent: Chat { - anchors.fill: parent - proxyModel: ChatProxyModel { - sipAddress: window.sipAddress || '' - } - } + sourceComponent: window.call ? chat : null } } } diff --git a/tests/ui/views/App/Calls/Incall.qml b/tests/ui/views/App/Calls/Incall.qml index 7662f03c0..82d4353a4 100644 --- a/tests/ui/views/App/Calls/Incall.qml +++ b/tests/ui/views/App/Calls/Incall.qml @@ -11,10 +11,6 @@ import App.Styles 1.0 // ============================================================================= Rectangle { - id: call - - // --------------------------------------------------------------------------- - property var call property var _contactObserver: SipAddressesModel.getContactObserver(sipAddress) diff --git a/tests/ui/views/App/Calls/IncomingCall.qml b/tests/ui/views/App/Calls/IncomingCall.qml index e0fa0e67d..dfa9abc95 100644 --- a/tests/ui/views/App/Calls/IncomingCall.qml +++ b/tests/ui/views/App/Calls/IncomingCall.qml @@ -2,7 +2,7 @@ import Common 1.0 import App.Styles 1.0 -// =================================================================== +// ============================================================================= AbstractStartingCall { ActionBar { @@ -11,18 +11,22 @@ AbstractStartingCall { ActionButton { icon: 'video_call_accept' + + onClicked: call.acceptWithVideo() } ActionButton { icon: 'call_accept' + + onClicked: call.accept() } } ActionBar { anchors { - verticalCenter: parent.verticalCenter right: parent.right rightMargin: StartingCallStyle.rightButtonsGroupMargin + verticalCenter: parent.verticalCenter } iconSize: StartingCallStyle.iconSize diff --git a/tests/ui/views/App/Calls/OutgoingCall.qml b/tests/ui/views/App/Calls/OutgoingCall.qml index 4604b696f..b9ae4daed 100644 --- a/tests/ui/views/App/Calls/OutgoingCall.qml +++ b/tests/ui/views/App/Calls/OutgoingCall.qml @@ -10,8 +10,8 @@ import App.Styles 1.0 AbstractStartingCall { GridLayout { + columns: parent.width < 415 && call.videoOutputEnabled ? 1 : 2 rowSpacing: ActionBarStyle.spacing - columns: parent.width < 415 && call.isVideoCall ? 1 : 2 anchors { left: parent.left @@ -24,7 +24,7 @@ AbstractStartingCall { icon: 'micro' iconSize: StartingCallStyle.iconSize - onClicked: call.microMuted = !enabled + onClicked: call.microMuted = enabled } ActionSwitch { @@ -40,7 +40,7 @@ AbstractStartingCall { height: StartingCallStyle.userVideo.height width: StartingCallStyle.userVideo.width - visible: isVideoCall + visible: call.videoOutputEnabled } ActionBar { diff --git a/tests/ui/views/App/MainWindow/Contacts.qml b/tests/ui/views/App/MainWindow/Contacts.qml index dadfe78d2..837d4f55e 100644 --- a/tests/ui/views/App/MainWindow/Contacts.qml +++ b/tests/ui/views/App/MainWindow/Contacts.qml @@ -131,12 +131,12 @@ ColumnLayout { ActionButton { icon: 'video_call' - onClicked: CallsWindow.launchVideoCall($contact.vcard.sipAddresses[0]) // FIXME: Display menu if many addresses. + onClicked: CallsListModel.launchVideoCall($contact.vcard.sipAddresses[0]) // FIXME: Display menu if many addresses. } ActionButton { icon: 'call' - onClicked: CallsWindow.launchAudioCall($contact.vcard.sipAddresses[0]) // FIXME: Display menu if many addresses. + onClicked: CallsListModel.launchAudioCall($contact.vcard.sipAddresses[0]) // FIXME: Display menu if many addresses. } ActionButton { diff --git a/tests/ui/views/App/MainWindow/Conversation.qml b/tests/ui/views/App/MainWindow/Conversation.qml index 878f7c4b6..03f77b91b 100644 --- a/tests/ui/views/App/MainWindow/Conversation.qml +++ b/tests/ui/views/App/MainWindow/Conversation.qml @@ -79,12 +79,12 @@ ColumnLayout { ActionButton { icon: 'video_call' - onClicked: CallsWindow.launchVideoCall(conversation.sipAddress) + onClicked: CallsListModel.launchVideoCall(conversation.sipAddress) } ActionButton { icon: 'call' - onClicked: CallsWindow.launchAudioCall(conversation.sipAddress) + onClicked: CallsListModel.launchAudioCall(conversation.sipAddress) } } @@ -92,7 +92,7 @@ ColumnLayout { anchors.verticalCenter: parent.verticalCenter ActionButton { - icon: _contact ? 'contact_add' : 'contact_edit' + icon: !_contact ? 'contact_add' : 'contact_edit' iconSize: ConversationStyle.bar.actions.edit.iconSize onClicked: window.setView('ContactEdit', { diff --git a/tests/ui/views/App/MainWindow/MainWindow.qml b/tests/ui/views/App/MainWindow/MainWindow.qml index 95a04d84e..39da05487 100644 --- a/tests/ui/views/App/MainWindow/MainWindow.qml +++ b/tests/ui/views/App/MainWindow/MainWindow.qml @@ -160,14 +160,14 @@ ApplicationWindow { }) } - onLaunchCall: CallsWindow.launchAudioCall(sipAddress) + onLaunchCall: CallsListModel.launchAudioCall(sipAddress) onLaunchChat: { window.ensureCollapsed() window.setView('Conversation', { sipAddress: sipAddress }) } - onLaunchVideoCall: CallsWindow.launchVideoCall(sipAddress) + onLaunchVideoCall: CallsListModel.launchVideoCall(sipAddress) onEntryClicked: { window.ensureCollapsed() diff --git a/tests/ui/views/App/Styles/Calls/StartingCallStyle.qml b/tests/ui/views/App/Styles/Calls/StartingCallStyle.qml index d21d67864..e5dbf2531 100644 --- a/tests/ui/views/App/Styles/Calls/StartingCallStyle.qml +++ b/tests/ui/views/App/Styles/Calls/StartingCallStyle.qml @@ -19,6 +19,12 @@ QtObject { property int maxSize: 300 } + property QtObject busyIndicator: QtObject { + property color color: Colors.g + property int height: 30 + property int width: 30 + } + property QtObject header: QtObject { property int spacing: 10 property int topMargin: 26