diff --git a/tests/assets/images/call_sign_ended.svg b/tests/assets/images/call_sign_ended.svg
new file mode 100644
index 000000000..ddee9dc58
--- /dev/null
+++ b/tests/assets/images/call_sign_ended.svg
@@ -0,0 +1,13 @@
+
+
diff --git a/tests/assets/languages/en.ts b/tests/assets/languages/en.ts
index edc62bce0..ae4ec4710 100644
--- a/tests/assets/languages/en.ts
+++ b/tests/assets/languages/en.ts
@@ -40,15 +40,15 @@
resumeCall
-
+ RESUME CALL
transferCall
-
+ TRANSFER CALL
pauseCall
-
+ PAUSE CALL
diff --git a/tests/assets/languages/fr.ts b/tests/assets/languages/fr.ts
index 612bdf29b..6b954c919 100644
--- a/tests/assets/languages/fr.ts
+++ b/tests/assets/languages/fr.ts
@@ -32,15 +32,15 @@
resumeCall
-
+ REPRENDRE APPEL
transferCall
-
+ TRANSFERER APPEL
pauseCall
-
+ PAUSE
diff --git a/tests/resources.qrc b/tests/resources.qrc
index 398691972..e44b070ef 100644
--- a/tests/resources.qrc
+++ b/tests/resources.qrc
@@ -26,6 +26,7 @@
assets/images/call_quality_2.svg
assets/images/call_quality_3.svg
assets/images/call_sign_connected.svg
+ assets/images/call_sign_ended.svg
assets/images/call_sign_incoming.svg
assets/images/call_sign_outgoing.svg
assets/images/call_sign_paused.svg
diff --git a/tests/src/app/App.cpp b/tests/src/app/App.cpp
index 3479084c3..62a00d9bd 100644
--- a/tests/src/app/App.cpp
+++ b/tests/src/app/App.cpp
@@ -62,6 +62,14 @@ App::App (int &argc, char **argv) : QApplication(argc, argv) {
// -----------------------------------------------------------------------------
+QQuickWindow *App::getCallsWindow () const {
+ QQuickWindow *window = m_engine.rootContext()->contextProperty("CallsWindow").value();
+ if (!window)
+ qFatal("Unable to get calls window.");
+
+ return window;
+}
+
bool App::hasFocus () const {
QQmlApplicationEngine &engine = const_cast(m_engine);
const QQuickWindow *root = qobject_cast(engine.rootObjects().at(0));
@@ -182,7 +190,6 @@ void App::addContextProperties () {
qInfo() << "Adding context properties...";
QQmlContext *context = m_engine.rootContext();
- // TODO: Avoid context properties. Use qmlRegister...
QQmlComponent component(&m_engine, QUrl(QML_VIEW_CALL_WINDOW));
if (component.isError()) {
qWarning() << component.errors();
diff --git a/tests/src/app/App.hpp b/tests/src/app/App.hpp
index 28a6fb6a2..e28dfddec 100644
--- a/tests/src/app/App.hpp
+++ b/tests/src/app/App.hpp
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include "../components/notifier/Notifier.hpp"
@@ -25,6 +26,8 @@ public:
return m_notifier;
}
+ QQuickWindow *getCallsWindow () const;
+
bool hasFocus () const;
Q_INVOKABLE QString locale () const {
diff --git a/tests/src/components/calls/CallsListModel.cpp b/tests/src/components/calls/CallsListModel.cpp
index 782b68138..62fe0b5f0 100644
--- a/tests/src/components/calls/CallsListModel.cpp
+++ b/tests/src/components/calls/CallsListModel.cpp
@@ -1,10 +1,14 @@
#include
+#include
#include "../../app/App.hpp"
#include "../core/CoreManager.hpp"
#include "CallsListModel.hpp"
+/* Delay before removing call in ms. */
+#define DELAY_BEFORE_REMOVE_CALL 3000
+
using namespace std;
// =============================================================================
@@ -16,17 +20,16 @@ CallsListModel::CallsListModel (QObject *parent) : QAbstractListModel(parent) {
this, [this](const shared_ptr &linphone_call, linphone::CallState state) {
switch (state) {
case linphone::CallStateIncomingReceived:
- addCall(linphone_call);
- break;
case linphone::CallStateOutgoingInit:
addCall(linphone_call);
break;
+
case linphone::CallStateEnd:
case linphone::CallStateError:
removeCall(linphone_call);
break;
- default:
+ default:
break;
}
}
@@ -80,11 +83,13 @@ bool CallsListModel::removeRows (int row, int count, const QModelIndex &parent)
// -----------------------------------------------------------------------------
void CallsListModel::addCall (const shared_ptr &linphone_call) {
+ App::getInstance()->getCallsWindow()->show();
+
CallModel *call = new CallModel(linphone_call);
App::getInstance()->getEngine()->setObjectOwnership(call, QQmlEngine::CppOwnership);
linphone_call->setData("call-model", *call);
- int row = rowCount();
+ int row = m_list.count();
beginInsertRows(QModelIndex(), row, row);
m_list << call;
@@ -92,12 +97,20 @@ void CallsListModel::addCall (const shared_ptr &linphone_call) {
}
void CallsListModel::removeCall (const shared_ptr &linphone_call) {
- CallModel &call = linphone_call->getData("call-model");
+ CallModel *call = &linphone_call->getData("call-model");
linphone_call->unsetData("call-model");
- qInfo() << "Removing call:" << &call;
+ // TODO: It will be (maybe) necessary to use a single scheduled function in the future.
+ QTimer::singleShot(
+ DELAY_BEFORE_REMOVE_CALL, this, [this, call]() {
+ qInfo() << "Removing call:" << call;
- int index = m_list.indexOf(&call);
- if (index == -1 || !removeRow(index))
- qWarning() << "Unable to remove call:" << &call;
+ int index = m_list.indexOf(call);
+ if (index == -1 || !removeRow(index))
+ qWarning() << "Unable to remove call:" << call;
+
+ if (m_list.empty())
+ App::getInstance()->getCallsWindow()->close();
+ }
+ );
}
diff --git a/tests/src/components/chat/ChatModel.cpp b/tests/src/components/chat/ChatModel.cpp
index 589977d35..66d578783 100644
--- a/tests/src/components/chat/ChatModel.cpp
+++ b/tests/src/components/chat/ChatModel.cpp
@@ -520,7 +520,7 @@ void ChatModel::removeEntry (ChatEntryData &pair) {
}
void ChatModel::insertMessageAtEnd (const shared_ptr &message) {
- int row = rowCount();
+ int row = m_entries.count();
beginInsertRows(QModelIndex(), row, row);
diff --git a/tests/src/components/contacts/ContactsListModel.cpp b/tests/src/components/contacts/ContactsListModel.cpp
index 1771ed0bd..a17efc9c7 100644
--- a/tests/src/components/contacts/ContactsListModel.cpp
+++ b/tests/src/components/contacts/ContactsListModel.cpp
@@ -92,7 +92,7 @@ ContactModel *ContactsListModel::addContact (VcardModel *vcard) {
return nullptr;
}
- int row = rowCount();
+ int row = m_list.count();
beginInsertRows(QModelIndex(), row, row);
addContact(contact);
diff --git a/tests/ui/modules/Common/BusyIndicator.qml b/tests/ui/modules/Common/BusyIndicator.qml
index 8eabd3052..86cb30e80 100644
--- a/tests/ui/modules/Common/BusyIndicator.qml
+++ b/tests/ui/modules/Common/BusyIndicator.qml
@@ -6,75 +6,75 @@ import Common.Styles 1.0
// =============================================================================
BusyIndicator {
- id: busyIndicator
+ id: busyIndicator
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- readonly property int _rotation: 360
- readonly property int _size: width < height ? width : height
+ readonly property int _rotation: 360
+ readonly property int _size: width < height ? width : height
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- contentItem: Item {
- x: parent.width / 2 - width / 2
- y: parent.height / 2 - height / 2
+ contentItem: Item {
+ x: parent.width / 2 - width / 2
+ y: parent.height / 2 - height / 2
- height: _size
- width: _size
+ height: _size
+ width: _size
- Item {
- id: item
+ Item {
+ id: item
- height: parent.height
- width: parent.width
+ height: parent.height
+ width: parent.width
- // -----------------------------------------------------------------------
- // Animation.
- // -----------------------------------------------------------------------
+ // -----------------------------------------------------------------------
+ // Animation.
+ // -----------------------------------------------------------------------
- RotationAnimator {
- duration: BusyIndicatorStyle.duration
- loops: Animation.Infinite
- running: busyIndicator.visible && busyIndicator.running
- target: item
+ RotationAnimator {
+ duration: BusyIndicatorStyle.duration
+ loops: Animation.Infinite
+ running: busyIndicator.visible && busyIndicator.running
+ target: item
- from: 0
- to: busyIndicator._rotation
- }
+ from: 0
+ to: busyIndicator._rotation
+ }
- // -----------------------------------------------------------------------
- // Items to draw.
- // -----------------------------------------------------------------------
+ // -----------------------------------------------------------------------
+ // Items to draw.
+ // -----------------------------------------------------------------------
- Repeater {
- id: repeater
+ Repeater {
+ id: repeater
- model: BusyIndicatorStyle.nSpheres
+ model: BusyIndicatorStyle.nSpheres
- Rectangle {
- x: item.width / 2 - width / 2
- y: item.height / 2 - height / 2
+ Rectangle {
+ x: item.width / 2 - width / 2
+ y: item.height / 2 - height / 2
- height: item.height / 3
- width: item.width / 3
+ height: item.height / 3
+ width: item.width / 3
- color: BusyIndicatorStyle.color
- radius: (width > height ? width : height) / 2
+ color: BusyIndicatorStyle.color
+ radius: (width > height ? width : height) / 2
- transform: [
- Translate {
- y: busyIndicator._size / 2
- },
- Rotation {
- angle: index / repeater.count * busyIndicator._rotation
- origin {
- x: width / 2
- y: height / 2
- }
- }
- ]
- }
- }
- }
- }
+ transform: [
+ Translate {
+ y: busyIndicator._size / 2
+ },
+ Rotation {
+ angle: index / repeater.count * busyIndicator._rotation
+ origin {
+ x: width / 2
+ y: height / 2
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
}
diff --git a/tests/ui/modules/Common/Styles/BusyIndicatorStyle.qml b/tests/ui/modules/Common/Styles/BusyIndicatorStyle.qml
index a76835e90..835c3c93a 100644
--- a/tests/ui/modules/Common/Styles/BusyIndicatorStyle.qml
+++ b/tests/ui/modules/Common/Styles/BusyIndicatorStyle.qml
@@ -6,7 +6,7 @@ import Common 1.0
// =============================================================================
QtObject {
- property color color: Colors.i
- property int duration: 1250
- property int nSpheres: 6
+ property color color: Colors.i
+ property int duration: 1250
+ property int nSpheres: 6
}
diff --git a/tests/ui/modules/Linphone/Calls/Calls.qml b/tests/ui/modules/Linphone/Calls/Calls.qml
index 9e056e528..faf53ad86 100644
--- a/tests/ui/modules/Linphone/Calls/Calls.qml
+++ b/tests/ui/modules/Linphone/Calls/Calls.qml
@@ -7,172 +7,207 @@ import Linphone.Styles 1.0
// =============================================================================
ListView {
- id: calls
+ id: calls
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- property var _mapStatusToParams
+ property var _mapStatusToParams
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
signal entrySelected (var entry)
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- function _getSignIcon (call) {
- if (call) {
- var string = _mapStatusToParams[call.status].string
- return string ? 'call_sign_' + string : ''
- }
+ function _getSignIcon (call) {
+ if (call) {
+ return 'call_sign_' + _mapStatusToParams[call.status].string
+ }
- return ''
- }
+ return ''
+ }
- function _getParams (call) {
- if (call) {
- return _mapStatusToParams[call.status]
- }
- }
+ function _getParams (call) {
+ if (call) {
+ return _mapStatusToParams[call.status]
+ }
+ }
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- boundsBehavior: Flickable.StopAtBounds
- clip: true
- spacing: 0
+ boundsBehavior: Flickable.StopAtBounds
+ clip: true
+ spacing: 0
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- Component.onCompleted: {
- _mapStatusToParams = {}
+ Component.onCompleted: {
+ _mapStatusToParams = {}
- _mapStatusToParams[CallModel.CallStatusConnected] = {
- actions: [{
- name: qsTr('resumeCall'),
- handler: (function (call) { call.pausedByUser = false })
- }, {
- name: qsTr('transferCall'),
- handler: (function (call) { call.transferCall() })
- }, {
- name: qsTr('terminateCall'),
- handler: (function (call) { call.terminateCall() })
- }],
- component: callActions,
- string: 'connected'
- }
+ _mapStatusToParams[CallModel.CallStatusConnected] = {
+ actions: [{
+ name: qsTr('resumeCall'),
+ handler: (function (call) { call.pausedByUser = false })
+ }, {
+ name: qsTr('transferCall'),
+ handler: (function (call) { call.transferCall() })
+ }, {
+ name: qsTr('terminateCall'),
+ handler: (function (call) { call.terminateCall() })
+ }],
+ component: callActions,
+ string: 'connected'
+ }
- _mapStatusToParams[CallModel.CallStatusEnded] = {}
+ _mapStatusToParams[CallModel.CallStatusEnded] = {
+ string: 'ended'
+ }
- _mapStatusToParams[CallModel.CallStatusIncoming] = {
- actions: [{
- name: qsTr('acceptAudioCall'),
- handler: (function (call) { call.acceptAudioCall() })
- }, {
- name: qsTr('acceptVideoCall'),
- handler: (function (call) { call.acceptVideoCall() })
- }, {
- name: qsTr('terminateCall'),
- handler: (function (call) { call.terminateCall() })
- }],
- component: callActions,
- string: 'incoming'
- }
+ _mapStatusToParams[CallModel.CallStatusIncoming] = {
+ actions: [{
+ name: qsTr('acceptAudioCall'),
+ handler: (function (call) { call.acceptAudioCall() })
+ }, {
+ name: qsTr('acceptVideoCall'),
+ handler: (function (call) { call.acceptVideoCall() })
+ }, {
+ name: qsTr('terminateCall'),
+ handler: (function (call) { call.terminateCall() })
+ }],
+ component: callActions,
+ string: 'incoming'
+ }
- _mapStatusToParams[CallModel.CallStatusOutgoing] = {
- component: callAction,
- handler: (function (call) { call.terminateCall() }),
- icon: 'hangup',
- string: 'outgoing'
- }
+ _mapStatusToParams[CallModel.CallStatusOutgoing] = {
+ component: callAction,
+ handler: (function (call) { call.terminateCall() }),
+ icon: 'hangup',
+ string: 'outgoing'
+ }
- _mapStatusToParams[CallModel.CallStatusPaused] = {
- actions: [{
- name: qsTr('pauseCall'),
- handler: (function (call) { call.pausedByUser = true })
- }, {
- name: qsTr('transferCall'),
- handler: (function (call) { call.transferCall() })
- }, {
- name: qsTr('terminateCall'),
- handler: (function (call) { call.terminateCall() })
- }],
- component: callActions,
- string: 'paused'
- }
- }
+ _mapStatusToParams[CallModel.CallStatusPaused] = {
+ actions: [{
+ name: qsTr('pauseCall'),
+ handler: (function (call) { call.pausedByUser = true })
+ }, {
+ name: qsTr('transferCall'),
+ handler: (function (call) { call.transferCall() })
+ }, {
+ name: qsTr('terminateCall'),
+ handler: (function (call) { call.terminateCall() })
+ }],
+ component: callActions,
+ string: 'paused'
+ }
+ }
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- Component {
- id: callAction
+ Component {
+ id: callAction
- ActionButton {
- icon: params.icon
- iconSize: CallsStyle.entry.iconActionSize
+ ActionButton {
+ icon: params.icon
+ iconSize: CallsStyle.entry.iconActionSize
- onClicked: params.handler(call)
- }
- }
+ onClicked: params.handler(call)
+ }
+ }
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- Component {
- id: callActions
+ Component {
+ id: callActions
- ActionButton {
- id: button
+ ActionButton {
+ id: button
- icon: 'burger_menu'
- iconSize: CallsStyle.entry.iconMenuSize
+ icon: calls.currentIndex === callId && call.status !== CallModel.CallStatusEnded
+ ? 'burger_menu_light'
+ : 'burger_menu'
+ iconSize: CallsStyle.entry.iconMenuSize
- onClicked: menu.showMenu()
+ onClicked: menu.showMenu()
- DropDownMenu {
- id: menu
+ DropDownMenu {
+ id: menu
- implicitWidth: actionMenu.width
- launcher: button
- relativeTo: callControls
- relativeX: callControls.width
+ implicitWidth: actionMenu.width
+ launcher: button
+ relativeTo: callControls
+ relativeX: callControls.width
- ActionMenu {
- id: actionMenu
+ ActionMenu {
+ id: actionMenu
- entryHeight: CallsStyle.entry.height
- entryWidth: CallsStyle.entry.width
+ entryHeight: CallsStyle.entry.height
+ entryWidth: CallsStyle.entry.width
- Repeater {
- model: params.actions
+ Repeater {
+ model: params.actions
- ActionMenuEntry {
- entryName: modelData.name
+ ActionMenuEntry {
+ entryName: modelData.name
- onClicked: {
- menu.hideMenu()
- params.actions[index].handler(call)
- }
- }
- }
- }
- }
- }
- }
+ onClicked: {
+ menu.hideMenu()
+ params.actions[index].handler(call)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
- // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
- delegate: CallControls {
- id: _callControls
+ delegate: CallControls {
+ id: _callControls
- signIcon: _getSignIcon($call)
- sipAddress: $call.sipAddress
- width: parent.width
+ function useColorStatus () {
+ return calls.currentIndex === index && $call.status !== CallModel.CallStatusEnded
+ }
- Loader {
- property var call: $call
- property var callControls: _callControls
- property var params: _getParams($call)
+ color: useColorStatus()
+ ? CallsStyle.entry.color.selected
+ : CallsStyle.entry.color.normal
+ sipAddressColor: useColorStatus()
+ ? CallsStyle.entry.sipAddressColor.selected
+ : CallsStyle.entry.sipAddressColor.normal
+ usernameColor: useColorStatus()
+ ? CallsStyle.entry.usernameColor.selected
+ : CallsStyle.entry.usernameColor.normal
- anchors.centerIn: parent
- sourceComponent: params.component
- }
- }
+ signIcon: _getSignIcon($call)
+ sipAddress: $call.sipAddress
+ width: parent.width
+
+ Loader {
+ property int callId: index
+ property var call: $call
+ property var callControls: _callControls
+ property var params: _getParams($call)
+
+ anchors.centerIn: parent
+ sourceComponent: params.component
+ }
+
+ SequentialAnimation on color {
+ loops: CallsStyle.entry.endCallAnimation.loops
+ running: $call.status === CallModel.CallStatusEnded
+
+ ColorAnimation {
+ duration: CallsStyle.entry.endCallAnimation.duration
+ from: CallsStyle.entry.color.normal
+ to: CallsStyle.entry.endCallAnimation.blinkColor
+ }
+
+ ColorAnimation {
+ duration: CallsStyle.entry.endCallAnimation.duration
+ from: CallsStyle.entry.endCallAnimation.blinkColor
+ to: CallsStyle.entry.color.normal
+ }
+ }
+ }
}
diff --git a/tests/ui/modules/Linphone/Styles/Calls/CallControlsStyle.qml b/tests/ui/modules/Linphone/Styles/Calls/CallControlsStyle.qml
index 60516875a..0151f6c15 100644
--- a/tests/ui/modules/Linphone/Styles/Calls/CallControlsStyle.qml
+++ b/tests/ui/modules/Linphone/Styles/Calls/CallControlsStyle.qml
@@ -6,10 +6,10 @@ import Common 1.0
// =============================================================================
QtObject {
- property color color: Colors.e
- property int height: 60
- property int leftMargin: 12
- property int rightMargin: 12
- property int signSize: 40
- property int width: 240
+ property color color: Colors.e
+ property int height: 60
+ property int leftMargin: 12
+ property int rightMargin: 12
+ property int signSize: 40
+ property int width: 240
}
diff --git a/tests/ui/modules/Linphone/Styles/Calls/CallsStyle.qml b/tests/ui/modules/Linphone/Styles/Calls/CallsStyle.qml
index 24b9115f4..9124edff4 100644
--- a/tests/ui/modules/Linphone/Styles/Calls/CallsStyle.qml
+++ b/tests/ui/modules/Linphone/Styles/Calls/CallsStyle.qml
@@ -6,10 +6,31 @@ import Common 1.0
// =============================================================================
QtObject {
- property QtObject entry: QtObject {
- property int iconActionSize: 30
- property int iconMenuSize: 17
- property int height: 30
- property int width: 200
- }
+ property QtObject entry: QtObject {
+ property int iconActionSize: 30
+ property int iconMenuSize: 17
+ property int height: 30
+ property int width: 200
+
+ property QtObject color: QtObject {
+ property color normal: Colors.e
+ property color selected: Colors.j
+ }
+
+ property QtObject endCallAnimation: QtObject {
+ property color blinkColor: Colors.i
+ property int duration: 300
+ property int loops: 3
+ }
+
+ property QtObject sipAddressColor: QtObject {
+ property color normal: Colors.w
+ property color selected: Colors.k
+ }
+
+ property QtObject usernameColor: QtObject {
+ property color normal: Colors.j
+ property color selected: Colors.k
+ }
+ }
}