diff --git a/tests/imgs/hangup.svg b/tests/imgs/hangup.svg new file mode 100644 index 000000000..c0b080ec5 --- /dev/null +++ b/tests/imgs/hangup.svg @@ -0,0 +1,14 @@ + + + + call_hangup + Created with Sketch. + + + + + + + + + diff --git a/tests/imgs/incoming_call.svg b/tests/imgs/incoming_call.svg new file mode 100644 index 000000000..dfa63fe4b --- /dev/null +++ b/tests/imgs/incoming_call.svg @@ -0,0 +1,17 @@ + + + + call_incoming + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/imgs/lost_incoming_call.svg b/tests/imgs/lost_incoming_call.svg new file mode 100644 index 000000000..8ccea2c2b --- /dev/null +++ b/tests/imgs/lost_incoming_call.svg @@ -0,0 +1,18 @@ + + + + call_missed + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/imgs/lost_outgoing_call.svg b/tests/imgs/lost_outgoing_call.svg new file mode 100644 index 000000000..8ccea2c2b --- /dev/null +++ b/tests/imgs/lost_outgoing_call.svg @@ -0,0 +1,18 @@ + + + + call_missed + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/languages/en.ts b/tests/languages/en.ts index 5f0101707..466cc7d5b 100644 --- a/tests/languages/en.ts +++ b/tests/languages/en.ts @@ -19,6 +19,25 @@ Please choose one or many files + + Event + + incomingCall + Incoming call + + + hangup + End call + + + lostIncomingCall + Lost incoming call + + + lostOutgoingCall + Lost outgoing call + + SelectContact diff --git a/tests/languages/fr.ts b/tests/languages/fr.ts index 13f4eaae1..811a32ae7 100644 --- a/tests/languages/fr.ts +++ b/tests/languages/fr.ts @@ -19,6 +19,25 @@ Merci de choisir un ou plusieurs fichiers + + Event + + incomingCall + Appel entrant + + + hangup + Fin d'appel + + + lostIncomingCall + Appel entrant manqué + + + lostOutgoingCall + Appel sortant manqué + + SelectContact diff --git a/tests/resources.qrc b/tests/resources.qrc index 2164cbe29..a1c763d6e 100644 --- a/tests/resources.qrc +++ b/tests/resources.qrc @@ -5,11 +5,13 @@ ui/components/scrollBar/ForceScrollBar.qml ui/components/misc/MenuEntry.qml ui/components/timeline/Timeline.qml + ui/components/image/Icon.qml ui/components/select/SelectContact.qml ui/components/collapse/Collapse.qml ui/components/chat/IncomingMessage.qml ui/components/chat/Chat.qml ui/components/chat/OutgoingMessage.qml + ui/components/chat/Event.qml ui/components/chat/Message.qml ui/components/contact/Contact.qml ui/components/contact/ShortContactDescription.qml @@ -33,11 +35,15 @@ ui/views/mainWindow/contacts.qml ui/views/mainWindow/home.qml ui/views/mainWindow/conversation.qml + imgs/lost_outgoing_call.svg imgs/led_disconnected.svg imgs/valid.svg + imgs/incoming_call.svg imgs/led_do_not_disturb.svg + imgs/lost_incoming_call.svg imgs/conference.svg imgs/cam.svg + imgs/hangup.svg imgs/chat.svg imgs/chat_attachment.svg imgs/led_connected.svg diff --git a/tests/ui/components/chat/Chat.qml b/tests/ui/components/chat/Chat.qml index 67608af02..ca0c6869d 100644 --- a/tests/ui/components/chat/Chat.qml +++ b/tests/ui/components/chat/Chat.qml @@ -2,6 +2,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 +import 'qrc:/ui/components/form' +import 'qrc:/ui/components/image' import 'qrc:/ui/components/scrollBar' ListView { @@ -9,13 +11,52 @@ ListView { boundsBehavior: Flickable.StopAtBounds clip: true highlightRangeMode: ListView.ApplyRange - spacing: 10 + spacing: 0 model: ListModel { - ListElement { $timestamp: 1465389121; $type: 'message'; $message: 'This is it: fefe efzzzzzzzzzz aaaaaaaaa erfeezffeefzfzefzefzezfefez wfef efef e efeffefe fee efefefeefef fefefefefe eff fefefe fefeffww.linphone.org' } - ListElement { $type: 'message'; $message: 'Perfect!' } + ListElement { $dateSection: 1465389121000; $outgoing: true; $timestamp: 1465389121000; $type: 'message'; $content: 'This is it: fefe efzzzzzzzzzz aaaaaaaaa erfeezffeefzfzefzefzezfefez wfef efef e efeffefe fee efefefeefef fefefefefe eff fefefe fefeffww.linphone.org' } + ListElement { $dateSection: 1465389121000; $timestamp: 1465389121000; $type: 'event'; $content: 'incoming_call' } + ListElement { $dateSection: 1465389121000; $timestamp: 1465389421000; $type: 'message'; $content: 'Perfect!' } + ListElement { $dateSection: 1465389121000; $timestamp: 1465389121000; $type: 'event'; $content: 'hangup' } + ListElement { $dateSection: 1465994221000; $outgoing: true; $timestamp: 1465994221000; $type: 'message'; $content: 'You\'ve heard the expression, "Just believe it and it will come." Well, technically, that is true, however, \'believing\' is not just thinking that you can have it...' } + ListElement { $dateSection: 1465994221000; $timestamp: 1465994221000; $type: 'event'; $content: 'lost_incoming_call' } } + Component { + id: sectionHeading + + Item { + implicitHeight: text.height + + container.anchors.topMargin + + container.anchors.bottomMargin + width: parent.width + + Item { + anchors.bottomMargin: 10 + anchors.fill: parent + anchors.leftMargin: 18 + anchors.topMargin: 20 + id: container + + Text { + color: '#434343' + font.bold: true + id: text + + // Cast section to integer because Qt convert the + // $dateSection in string!!! + text: new Date(+section).toLocaleDateString( + Qt.locale() + ) + } + } + } + } + + section.criteria: ViewSection.FullString + section.delegate: sectionHeading + section.property: '$dateSection' + delegate: Rectangle { anchors.left: parent.left anchors.leftMargin: 18 @@ -24,28 +65,77 @@ ListView { // Unable to use `height` property. // The height is given by message height. - implicitHeight: layout.height + implicitHeight: layout.height + 10 width: parent.width + MouseArea { + anchors.fill: parent + hoverEnabled: true + onEntered: parent.state = 'hover' + onExited: parent.state = '' + } + RowLayout { id: layout + spacing: 0 // The height is computed with the message height. // Unable to use `height` and `implicitHeight` property. width: parent.width - Rectangle { + // Display time. + Text { Layout.alignment: Qt.AlignTop - Layout.preferredHeight: 15 - Layout.preferredWidth: 42 - color: 'blue' + Layout.preferredHeight: 30 + Layout.preferredWidth: 50 + color: '#898989' + font.bold: $type === 'event' + text: new Date($timestamp).toLocaleString( + Qt.locale(), + 'hh:mm' + ) + verticalAlignment: Text.AlignVCenter } + // Icons area. + Row { + Layout.alignment: Qt.AlignTop + Layout.preferredHeight: 30 + Layout.preferredWidth: 54 + spacing: 10 + + Icon { + anchors.verticalCenter: parent.verticalCenter + icon: ($type === 'event' && $content) || '' + iconSize: 16 + } + + ActionButton { + anchors.verticalCenter: parent.verticalCenter + icon: 'delete' + iconSize: 16 + id: removeAction + onClicked: console.log('remove item') + visible: false + } + } + + // Display content. Loader { Layout.fillWidth: true id: loader - source: 'qrc:/ui/components/chat/IncomingMessage.qml' + source: $type === 'message' + ? ( + 'qrc:/ui/components/chat/' + + ($outgoing ? 'Outgoing' : 'Incoming') + + 'Message.qml' + ) : 'qrc:/ui/components/chat/Event.qml' } } + + states: State { + name: 'hover' + PropertyChanges { target: removeAction; visible: true } + } } } diff --git a/tests/ui/components/chat/Event.qml b/tests/ui/components/chat/Event.qml new file mode 100644 index 000000000..5af08c610 --- /dev/null +++ b/tests/ui/components/chat/Event.qml @@ -0,0 +1,24 @@ +import QtQuick 2.7 + +import 'qrc:/ui/scripts/utils.js' as Utils + +// =================================================================== + +Text { + Component { + // Never created. + // Private data for `lupdate`. + Item { + property variant i18n: [ + QT_TR_NOOP('hangup'), + QT_TR_NOOP('incomingCall'), + QT_TR_NOOP('lostIncomingCall'), + QT_TR_NOOP('lostOutgoingCall') + ] + } + } + + color: '#898989' + font.bold: true + text: qsTr(Utils.snakeToCamel($content)) +} diff --git a/tests/ui/components/chat/IncomingMessage.qml b/tests/ui/components/chat/IncomingMessage.qml index 9b529e9f9..5ffbb4a83 100644 --- a/tests/ui/components/chat/IncomingMessage.qml +++ b/tests/ui/components/chat/IncomingMessage.qml @@ -3,7 +3,25 @@ import QtQuick.Layouts 1.3 import 'qrc:/ui/components/contact' -Message { - backgroundColor: '#BFBFBF' - Layout.fillWidth: true +// =================================================================== + +Item { + implicitHeight: message.height + + RowLayout { + anchors.fill: parent + spacing: 10 + + Avatar { + Layout.alignment: Qt.AlignTop + Layout.preferredHeight: 30 + Layout.preferredWidth: 30 + } + + Message { + Layout.fillWidth: true + backgroundColor: '#BFBFBF' + id: message + } + } } diff --git a/tests/ui/components/chat/Message.qml b/tests/ui/components/chat/Message.qml index 40336a23c..44c7ae40c 100644 --- a/tests/ui/components/chat/Message.qml +++ b/tests/ui/components/chat/Message.qml @@ -1,6 +1,9 @@ import QtQuick 2.7 +// =================================================================== + Item { + default property alias content: content.data property alias backgroundColor: rectangle.color id: container @@ -21,9 +24,17 @@ Item { Text { anchors.left: container.left anchors.right: container.right - padding: 8 id: text - text: $message + padding: 8 + text: $content wrapMode: Text.Wrap + + // Little fix. Text may disappear with scrolling. + renderType: Text.NativeRendering + } + + Item { + anchors.left: rectangle.right + id: content } } diff --git a/tests/ui/components/chat/OutgoingMessage.qml b/tests/ui/components/chat/OutgoingMessage.qml index f7a90bbd3..a7dfc4d59 100644 --- a/tests/ui/components/chat/OutgoingMessage.qml +++ b/tests/ui/components/chat/OutgoingMessage.qml @@ -1 +1,22 @@ import QtQuick 2.7 +import QtQuick.Layouts 1.3 + +import 'qrc:/ui/components/image' + +Message { + Layout.fillWidth: true + backgroundColor: '#E4E4E4' + id: message + + Item { + height: 30 + width: 30 + + // TODO: Success and re-send icon. + Icon { + anchors.centerIn: parent + icon: 'valid' + iconSize: 16 + } + } +} diff --git a/tests/ui/components/form/ActionButton.qml b/tests/ui/components/form/ActionButton.qml index fd9304f7c..9cfa49225 100644 --- a/tests/ui/components/form/ActionButton.qml +++ b/tests/ui/components/form/ActionButton.qml @@ -1,22 +1,23 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 +import 'qrc:/ui/components/image' + // =================================================================== // An animated small button with an image. // =================================================================== Button { property int iconSize - property string icon + property alias icon: icon.icon // Ugly hack, use current size, ActionBar size, // or other parent height. height: iconSize || parent.iconSize || parent.height width: iconSize || parent.iconSize || parent.height - Image { + Icon { anchors.fill: parent - fillMode: Image.PreserveAspectFit - source: 'qrc:/imgs/' + parent.icon + '.svg' + id: icon } } diff --git a/tests/ui/components/image/Icon.qml b/tests/ui/components/image/Icon.qml new file mode 100644 index 000000000..67dd33fc4 --- /dev/null +++ b/tests/ui/components/image/Icon.qml @@ -0,0 +1,14 @@ +import QtQuick 2.7 + +Image { + property int iconSize + property string icon + + height: iconSize + width: iconSize + + fillMode: Image.PreserveAspectFit + source: icon + ? 'qrc:/imgs/' + icon + '.svg' + : '' +} diff --git a/tests/ui/scripts/utils.js b/tests/ui/scripts/utils.js index 9c0027654..98d0c84ea 100644 --- a/tests/ui/scripts/utils.js +++ b/tests/ui/scripts/utils.js @@ -8,8 +8,7 @@ // // Supported options: isString, exitHandler. // -// If exitHandler is used, window must implement returnedValue -// signal. +// If exitHandler is used, window must implement exitStatus signal. function openWindow (window, parent, options) { var object @@ -69,3 +68,11 @@ function openConfirmDialog (parent, options) { } ) } + +// ------------------------------------------------------------------- + +function snakeToCamel (s) { + return s.replace(/(\_\w)/g, function (matches) { + return matches[1].toUpperCase() + }) +} diff --git a/tests/ui/views/mainWindow/contacts.qml b/tests/ui/views/mainWindow/contacts.qml index f7ea7af78..90644a199 100644 --- a/tests/ui/views/mainWindow/contacts.qml +++ b/tests/ui/views/mainWindow/contacts.qml @@ -248,7 +248,6 @@ ColumnLayout { } } - states: State { name: 'hover' PropertyChanges { target: contact; color: '#D1D1D1' }