From 421eae38a30c23b57a01b5bcc2c560b445c4e757 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 28 Sep 2016 17:31:09 +0200 Subject: [PATCH] feat(app): many changes: - InvertedMouseArea use a asynchronous call on pressed event - ListForm use an external style - ListForm supports outside click - ... --- tests/imgs/add_field.svg | 19 ++ tests/resources.qrc | 4 +- tests/src/main.cpp | 2 +- tests/ui/modules/Linphone/Chat/Event.qml | 2 +- .../modules/Linphone/{Form => }/DropZone.qml | 2 +- .../Linphone/Form/ExclusiveButtons.qml | 3 +- tests/ui/modules/Linphone/Form/ListForm.qml | 201 ++++++++++-------- .../ui/modules/Linphone/InvertedMouseArea.qml | 28 ++- tests/ui/modules/Linphone/Menu.qml | 2 +- .../modules/Linphone/Popup/DropDownMenu.qml | 16 +- .../Linphone/Styles/Form/ListFormStyle.qml | 44 ++++ tests/ui/modules/Linphone/Styles/qmldir | 1 + tests/ui/modules/Linphone/qmldir | 4 +- tests/ui/scripts/utils.js | 25 +++ tests/ui/views/MainWindow/Contact.qml | 15 ++ 15 files changed, 255 insertions(+), 113 deletions(-) create mode 100644 tests/imgs/add_field.svg rename tests/ui/modules/Linphone/{Form => }/DropZone.qml (97%) create mode 100644 tests/ui/modules/Linphone/Styles/Form/ListFormStyle.qml diff --git a/tests/imgs/add_field.svg b/tests/imgs/add_field.svg new file mode 100644 index 000000000..1b9cf9ac6 --- /dev/null +++ b/tests/imgs/add_field.svg @@ -0,0 +1,19 @@ + + + + add_field_over copy + Created with Sketch. + + + + + + + + + + + + + + diff --git a/tests/resources.qrc b/tests/resources.qrc index 5836abc61..6910477ef 100644 --- a/tests/resources.qrc +++ b/tests/resources.qrc @@ -1,5 +1,6 @@ + imgs/add_field.svg imgs/call.svg imgs/cam.svg imgs/chat_attachment.svg @@ -38,12 +39,12 @@ ui/modules/Linphone/Dialog/ConfirmDialog.qml ui/modules/Linphone/Dialog/DialogDescription.qml ui/modules/Linphone/Dialog/DialogPlus.qml + ui/modules/Linphone/DropZone.qml ui/modules/Linphone/ForceScrollBar.qml ui/modules/Linphone/Form/AbstractTextButton.qml ui/modules/Linphone/Form/ActionBar.qml ui/modules/Linphone/Form/ActionButton.qml ui/modules/Linphone/Form/CheckBoxText.qml - ui/modules/Linphone/Form/DropZone.qml ui/modules/Linphone/Form/ExclusiveButtons.qml ui/modules/Linphone/Form/ListForm.qml ui/modules/Linphone/Form/SmallButton.qml @@ -65,6 +66,7 @@ ui/modules/Linphone/Styles/Form/ActionBarStyle.qml ui/modules/Linphone/Styles/Form/CheckBoxTextStyle.qml ui/modules/Linphone/Styles/Form/ExclusiveButtonsStyle.qml + ui/modules/Linphone/Styles/Form/ListFormStyle.qml ui/modules/Linphone/Styles/Form/SmallButtonStyle.qml ui/modules/Linphone/Styles/Form/TextButtonAStyle.qml ui/modules/Linphone/Styles/Form/TextButtonBStyle.qml diff --git a/tests/src/main.cpp b/tests/src/main.cpp index a28401278..3af3c3257 100644 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include +#include #include #include #include diff --git a/tests/ui/modules/Linphone/Chat/Event.qml b/tests/ui/modules/Linphone/Chat/Event.qml index 5af08c610..14ccacd3b 100644 --- a/tests/ui/modules/Linphone/Chat/Event.qml +++ b/tests/ui/modules/Linphone/Chat/Event.qml @@ -9,7 +9,7 @@ Text { // Never created. // Private data for `lupdate`. Item { - property variant i18n: [ + property var i18n: [ QT_TR_NOOP('hangup'), QT_TR_NOOP('incomingCall'), QT_TR_NOOP('lostIncomingCall'), diff --git a/tests/ui/modules/Linphone/Form/DropZone.qml b/tests/ui/modules/Linphone/DropZone.qml similarity index 97% rename from tests/ui/modules/Linphone/Form/DropZone.qml rename to tests/ui/modules/Linphone/DropZone.qml index 0e8ef23bb..645c5ae56 100644 --- a/tests/ui/modules/Linphone/Form/DropZone.qml +++ b/tests/ui/modules/Linphone/DropZone.qml @@ -4,7 +4,7 @@ import QtQuick.Dialogs 1.2 // =================================================================== Rectangle { - signal dropped (variant files) + signal dropped (var files) color: '#DDDDDD' id: dropZone diff --git a/tests/ui/modules/Linphone/Form/ExclusiveButtons.qml b/tests/ui/modules/Linphone/Form/ExclusiveButtons.qml index b3269f44d..a8be70843 100644 --- a/tests/ui/modules/Linphone/Form/ExclusiveButtons.qml +++ b/tests/ui/modules/Linphone/Form/ExclusiveButtons.qml @@ -5,8 +5,9 @@ import Linphone.Styles 1.0 // =================================================================== Row { + property var texts + property int _selectedButton: 0 - property variant texts signal clicked (int button) diff --git a/tests/ui/modules/Linphone/Form/ListForm.qml b/tests/ui/modules/Linphone/Form/ListForm.qml index 1567c6863..f248830d4 100644 --- a/tests/ui/modules/Linphone/Form/ListForm.qml +++ b/tests/ui/modules/Linphone/Form/ListForm.qml @@ -1,106 +1,123 @@ import QtQuick 2.7 import QtQuick.Layouts 1.3 +import Linphone 1.0 +import Linphone.Styles 1.0 + +// =================================================================== + RowLayout { - readonly property int lineHeight: 30 + property alias model: values.model + property alias title: text.text - property alias title: text.text + function _addValue (value) { + if (model.count === 0 || + model.get(model.count - 1).$value.length !== 0) { + model.append({ $value: value }) + } + } - spacing: 0 + function _handleEditionFinished (index, text) { + if (text.length === 0) { + model.remove(index) + } else { + model.set(index, { $value: text }) + } + } - RowLayout { - Layout.alignment: Qt.AlignTop - Layout.preferredHeight: lineHeight - spacing: 20 + spacing: 0 - // Add item in list. - ActionButton { - Layout.preferredHeight: 16 - Layout.preferredWidth: 16 - onClicked: { - if (valuesModel.count === 0 || - valuesModel.get(valuesModel.count - 1).$value.length !== 0) { - valuesModel.append({ $value: '' }) - } - } - } + // Title area. + RowLayout { + Layout.alignment: Qt.AlignTop + Layout.preferredHeight: ListFormStyle.lineHeight + spacing: ListFormStyle.titleArea.spacing - // List title. - Text { - Layout.preferredWidth: 130 - id: text - } + // Button: Add item in list. + ActionButton { + Layout.preferredHeight: ListFormStyle.titleArea.iconSize + Layout.preferredWidth: ListFormStyle.titleArea.iconSize + icon: ListFormStyle.titleArea.icon + + onClicked: _addValue('') } - // Content list. - ListView { - Layout.fillWidth: true - Layout.preferredHeight: values.count * lineHeight - id: values - interactive: false + // Title text. + Text { + id: text - model: ListModel { - id: valuesModel - - ListElement { $value: 'toto' } - ListElement { $value: 'abc' } - ListElement { $value: 'machin' } - ListElement { $value: 'bidule' } - ListElement { $value: 'truc' } - } - - delegate: Item { - implicitHeight: textEdit.height - width: parent.width - - Rectangle { - color: textEdit.focus ? '#E6E6E6' : 'transparent' - id: background - implicitHeight: textEdit.height - implicitWidth: textEdit.contentWidth + - textEdit.padding * 2 - } - - Text { - anchors.fill: textEdit - color: '#5A585B' - font.italic: true - padding: textEdit.padding - text: textEdit.text.length === 0 && !textEdit.focus - ? qsTr('fillPlaceholder') - : '' - verticalAlignment: Text.AlignVCenter - } - - TextEdit { - color: focus ? '#000000' : '#5A585B' - font.bold: !focus - height: lineHeight - id: textEdit - padding: 10 - selectByMouse: true - text: $value - verticalAlignment: TextEdit.AlignVCenter - width: parent.width - - // To handle editingFinished, it's necessary to set - // focus on another component. - Keys.onReturnPressed: parent.forceActiveFocus() - - onEditingFinished: { - if (text.length === 0) { - valuesModel.remove(index) - } else { - // textEdit.text is not the same value than - // valuesModel.get(index) - valuesModel.set(index, { $value: text }) - } - - // Hack: The edition is finished but the focus - // can be set. - focus = false - } - } - } + Layout.preferredWidth: ListFormStyle.titleArea.text.width + color: ListFormStyle.titleArea.text.color + font.pointSize: ListFormStyle.titleArea.text.fontSize } + } + + // Values. + ListView { + id: values + + Layout.fillWidth: true + Layout.preferredHeight: count * ListFormStyle.lineHeight + interactive: false + + delegate: Item { + implicitHeight: textEdit.height + width: parent.width + + // Background. + Rectangle { + color: textEdit.activeFocus + ? ListFormStyle.value.backgroundColor.focused + : ListFormStyle.value.backgroundColor.normal + implicitHeight: textEdit.height + implicitWidth: textEdit.width + } + + // Placeholder. + Text { + anchors.fill: textEdit + color: ListFormStyle.value.placeholder.color + font.italic: true + font.pointSize: ListFormStyle.value.placeholder.fontSize + padding: textEdit.padding + text: textEdit.text.length === 0 && !textEdit.activeFocus + ? qsTr('fillPlaceholder') + : '' + verticalAlignment: Text.AlignVCenter + } + + // Input. + TextEdit { + id: textEdit + + color: activeFocus + ? ListFormStyle.value.text.color.focused + : ListFormStyle.value.text.color.normal + font.bold: !activeFocus + height: ListFormStyle.lineHeight + padding: ListFormStyle.value.text.padding + selectByMouse: true + text: $value + verticalAlignment: TextEdit.AlignVCenter + width: !activeFocus + ? parent.width + : contentWidth + padding * 2 + + Keys.onEscapePressed: focus = false + Keys.onReturnPressed: focus = false + + onEditingFinished: _handleEditionFinished(index, text) + } + + // Handle click outside `TextEdit` instance. + InvertedMouseArea { + enabled: textEdit.activeFocus + height: textEdit.height + parent: parent + width: textEdit.width + + onPressed: textEdit.focus = false + } + } + } } diff --git a/tests/ui/modules/Linphone/InvertedMouseArea.qml b/tests/ui/modules/Linphone/InvertedMouseArea.qml index 518a2f079..cc85fb54f 100644 --- a/tests/ui/modules/Linphone/InvertedMouseArea.qml +++ b/tests/ui/modules/Linphone/InvertedMouseArea.qml @@ -2,6 +2,8 @@ import QtQuick 2.7 import Linphone 1.0 +import 'qrc:/ui/scripts/utils.js' as Utils + // =================================================================== // Helper to handle button click outside a component. // =================================================================== @@ -39,9 +41,9 @@ Item { function _isInItem (point) { return ( point.x >= item.x && - point.y >= item.y && - point.x <= item.x + item.width && - point.y <= item.y + item.height + point.y >= item.y && + point.x <= item.x + item.width && + point.y <= item.y + item.height ) } @@ -49,7 +51,7 @@ Item { // See: http://doc.qt.io/qt-5/qml-qtqml-component.html#completed-signal // // The creation order of components in a view is undefined, - // so the mouse area must be created only when `enabled == true`. + // so the mouse area must be created only when `enabled === true`. // // In the first render, `enabled` must be equal to false. Component.onCompleted: enabled && _createMouseArea() @@ -67,6 +69,8 @@ Item { id: builder MouseArea { + property var _timeout + anchors.fill: parent propagateComposedEvents: true z: Constants.zMax @@ -75,11 +79,23 @@ Item { // Propagate event. mouse.accepted = false + // Click is outside or not. if (!_isInItem( mapToItem(item.parent, mouse.x, mouse.y) )) { - // Outside!!! - item.pressed() + if (_timeout != null) { + Utils.clearTimeout(_timeout) + } + + // Use a asynchronous call that is executed + // after the propagated event. + // + // It's useful to ensure the window's context is not + // modified with the mouse event before the `onPressed` + // function. + // + // The timeout is destroyed with the `MouseArea` component. + _timeout = Utils.setTimeout.call(this, 0, item.pressed.bind(this)) } } } diff --git a/tests/ui/modules/Linphone/Menu.qml b/tests/ui/modules/Linphone/Menu.qml index 2a95f590f..1f22a7ecb 100644 --- a/tests/ui/modules/Linphone/Menu.qml +++ b/tests/ui/modules/Linphone/Menu.qml @@ -12,7 +12,7 @@ ColumnLayout { property int entryHeight property int entryWidth - property variant entries + property var entries property int _selectedEntry: 0 diff --git a/tests/ui/modules/Linphone/Popup/DropDownMenu.qml b/tests/ui/modules/Linphone/Popup/DropDownMenu.qml index ce372db93..66a72c6fa 100644 --- a/tests/ui/modules/Linphone/Popup/DropDownMenu.qml +++ b/tests/ui/modules/Linphone/Popup/DropDownMenu.qml @@ -11,6 +11,14 @@ Rectangle { property int entryHeight property int maxMenuHeight + function show () { + visible = true + } + + function hide () { + visible = false + } + // Ugly. Just ugly. // `model` is a reference on a unknown component! // See usage with SearchBox. @@ -20,14 +28,6 @@ Rectangle { } visible: false - function show () { - visible = true - } - - function hide () { - visible = false - } - Rectangle { id: content diff --git a/tests/ui/modules/Linphone/Styles/Form/ListFormStyle.qml b/tests/ui/modules/Linphone/Styles/Form/ListFormStyle.qml new file mode 100644 index 000000000..f886b24d1 --- /dev/null +++ b/tests/ui/modules/Linphone/Styles/Form/ListFormStyle.qml @@ -0,0 +1,44 @@ +pragma Singleton +import QtQuick 2.7 + +import Linphone 1.0 + +QtObject { + property int lineHeight: 30 + + property QtObject value: QtObject { + property QtObject backgroundColor: QtObject { + property color focused: '#E6E6E6' + property color normal: 'transparent' + } + + property QtObject placeholder: QtObject { + property color color: '#5A585B' + + property int fontSize: 10 + } + + property QtObject text: QtObject { + property int padding: 10 + + property QtObject color: QtObject { + property color focused: '#000000' + property color normal: '#5A585B' + } + } + } + + property QtObject titleArea: QtObject { + property int spacing: 10 + property int iconSize: 16 + + property string icon: 'add_field' + + property QtObject text: QtObject { + property color color: '#000000' + + property int fontSize: 10 + property int width: 130 + } + } +} diff --git a/tests/ui/modules/Linphone/Styles/qmldir b/tests/ui/modules/Linphone/Styles/qmldir index 18f5cae28..4692f3405 100644 --- a/tests/ui/modules/Linphone/Styles/qmldir +++ b/tests/ui/modules/Linphone/Styles/qmldir @@ -15,6 +15,7 @@ singleton AbstractTextButtonStyle 1.0 Form/AbstractTextButtonStyle.qml singleton ActionBarStyle 1.0 Form/ActionBarStyle.qml singleton CheckBoxTextStyle 1.0 Form/CheckBoxTextStyle.qml singleton ExclusiveButtonsStyle 1.0 Form/ExclusiveButtonsStyle.qml +singleton ListFormStyle 1.0 Form/ListFormStyle.qml singleton SmallButtonStyle 1.0 Form/SmallButtonStyle.qml singleton TextButtonAStyle 1.0 Form/TextButtonAStyle.qml singleton TextButtonBStyle 1.0 Form/TextButtonBStyle.qml diff --git a/tests/ui/modules/Linphone/qmldir b/tests/ui/modules/Linphone/qmldir index ac275de6b..35670b58e 100644 --- a/tests/ui/modules/Linphone/qmldir +++ b/tests/ui/modules/Linphone/qmldir @@ -25,6 +25,9 @@ ContactDescription 1.0 Contact/ContactDescription.qml # Dialog DialogPlus 1.0 Dialog/DialogPlus.qml +# DropZone +DropZone 1.0 DropZone.qml + # ForceScrollBar ForceScrollBar 1.0 ForceScrollBar.qml @@ -32,7 +35,6 @@ ForceScrollBar 1.0 ForceScrollBar.qml ActionBar 1.0 Form/ActionBar.qml ActionButton 1.0 Form/ActionButton.qml CheckBoxText 1.0 Form/CheckBoxText.qml -DropZone 1.0 Form/DropZone.qml ExclusiveButtons 1.0 Form/ExclusiveButtons.qml LightButton 1.0 Form/LightButton.qml ListForm 1.0 Form/ListForm.qml diff --git a/tests/ui/scripts/utils.js b/tests/ui/scripts/utils.js index b64b996c6..18ca0acb0 100644 --- a/tests/ui/scripts/utils.js +++ b/tests/ui/scripts/utils.js @@ -76,3 +76,28 @@ function snakeToCamel (s) { return matches[1].toUpperCase() }) } + +// ------------------------------------------------------------------- + +function Timer (parent) { + return Qt.createQmlObject('import QtQuick 2.7; Timer { }', parent) +} + +// A copy of `Window.setTimeout` from js. +// Use setTimeout.call(parentContext, delayTime, cb) to use it. +// +// delay is in milliseconds. +function setTimeout (delay, cb) { + var timer = new Timer(this) + + timer.interval = delay + timer.repeat = false + timer.triggered.connect(cb) + timer.start() + + return timer +} + +function clearTimeout (timer) { + timer.destroy() // Not necessary: `timer.stop()` +} diff --git a/tests/ui/views/MainWindow/Contact.qml b/tests/ui/views/MainWindow/Contact.qml index dc465b965..89e0e0e3e 100644 --- a/tests/ui/views/MainWindow/Contact.qml +++ b/tests/ui/views/MainWindow/Contact.qml @@ -72,18 +72,33 @@ ColumnLayout { ListForm { title: qsTr('sipAccounts') + model: ListModel { + ListElement { $value: 'merinos@sip.linphone.org' } + ListElement { $value: 'elisabeth.pro@sip.linphone.org' } + } } ListForm { title: qsTr('address') + model: ListModel { + ListElement { $value: '312 East 10th Street - New York, NY 1009' } + } } ListForm { title: qsTr('emails') + model: ListModel { + ListElement { $value: 'e.meri@gmail.com' } + ListElement { $value: 'toto@truc.machin' } + } } ListForm { title: qsTr('webSites') + model: ListModel { + ListElement { $value: 'www.totogro.com' } + ListElement { $value: 'www.404.unknown' } + } } } }