diff --git a/linphone-desktop/resources.qrc b/linphone-desktop/resources.qrc
index ceaaa203f..324a7aa96 100644
--- a/linphone-desktop/resources.qrc
+++ b/linphone-desktop/resources.qrc
@@ -325,13 +325,14 @@
ui/modules/Linphone/Styles/Notifications/NotificationReceivedFileMessageStyle.qml
ui/modules/Linphone/Styles/Notifications/NotificationReceivedMessageStyle.qml
ui/modules/Linphone/Styles/qmldir
- ui/modules/Linphone/Styles/SmartSearchBar/SmartSearchBarStyle.qml
ui/modules/Linphone/Styles/TelKeypad/TelKeypadStyle.qml
ui/modules/Linphone/Styles/Timeline/TimelineStyle.qml
+ ui/modules/Linphone/Styles/View/SipAddressesViewStyle.qml
ui/modules/Linphone/TelKeypad/TelKeypadButton.qml
ui/modules/Linphone/TelKeypad/TelKeypad.qml
ui/modules/Linphone/Timeline/Timeline.js
ui/modules/Linphone/Timeline/Timeline.qml
+ ui/modules/Linphone/View/SipAddressesView.qml
ui/scripts/LinphoneUtils/linphone-utils.js
ui/scripts/LinphoneUtils/qmldir
ui/scripts/Utils/port-tools.js
diff --git a/linphone-desktop/ui/modules/Common/Form/+linux/SearchBox.qml b/linphone-desktop/ui/modules/Common/Form/+linux/SearchBox.qml
index b88615528..2066328b1 100644
--- a/linphone-desktop/ui/modules/Common/Form/+linux/SearchBox.qml
+++ b/linphone-desktop/ui/modules/Common/Form/+linux/SearchBox.qml
@@ -14,14 +14,14 @@ Item {
readonly property alias filter: searchField.text
- property alias delegate: list.delegate
- property alias header: list.header
property alias entryHeight: menu.entryHeight
property alias maxMenuHeight: menu.maxMenuHeight
-
- property alias model: list.model
property alias placeholderText: searchField.placeholderText
+ default property alias _content: menu._content
+
+ readonly property var view: _content[0]
+
property bool _isOpen: false
// ---------------------------------------------------------------------------
@@ -50,6 +50,7 @@ Item {
}
function _filter (text) {
+ var model = searchBox.view.model
Utils.assert(model.setFilter != null, '`model.setFilter` must be defined.')
model.setFilter(text)
}
@@ -97,13 +98,18 @@ Item {
Keys.forwardTo: searchField
onClosed: searchBox.closeMenu()
+ }
- ScrollableListView {
- id: list
+ Binding {
+ target: searchBox.view
+ property: 'width'
+ value: searchField.width
+ }
- headerPositioning: header ? ListView.OverlayHeader : ListView.InlineFooter
- width: searchField.width
- }
+ Binding {
+ target: searchBox.view
+ property: 'headerPositioning'
+ value: searchBox.view.header ? ListView.OverlayHeader : ListView.InlineFooter
}
}
diff --git a/linphone-desktop/ui/modules/Common/Menus/DropDownDynamicMenu.qml b/linphone-desktop/ui/modules/Common/Menus/DropDownDynamicMenu.qml
index 7d9b333a1..952bcd009 100644
--- a/linphone-desktop/ui/modules/Common/Menus/DropDownDynamicMenu.qml
+++ b/linphone-desktop/ui/modules/Common/Menus/DropDownDynamicMenu.qml
@@ -42,10 +42,6 @@ Item {
var list = _content[0]
Utils.assert(list != null, 'No list found.')
- Utils.assert(
- Utils.qmlTypeof(list, 'QQuickListView') || Utils.qmlTypeof(list, 'ScrollableListView'),
- 'No list view parameter.'
- )
var height = list.count * entryHeight
diff --git a/linphone-desktop/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml b/linphone-desktop/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml
index b259968bc..c0acb55a7 100644
--- a/linphone-desktop/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml
+++ b/linphone-desktop/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml
@@ -1,8 +1,6 @@
-import QtQuick 2.7
-import QtQuick.Layouts 1.3
-
import Common 1.0
import Linphone 1.0
+
import Linphone.Styles 1.0
// =============================================================================
@@ -12,10 +10,6 @@ SearchBox {
// ---------------------------------------------------------------------------
- readonly property string interpretableSipAddress: SipAddressesModel.interpretUrl(
- searchBox.filter
- )
-
readonly property alias isOpen: searchBox._isOpen
// ---------------------------------------------------------------------------
@@ -29,256 +23,49 @@ SearchBox {
// ---------------------------------------------------------------------------
- onEnterPressed: interpretableSipAddress.length > 0 && searchBox.launchCall(interpretableSipAddress)
+ entryHeight: SipAddressesViewStyle.entry.height
- // ---------------------------------------------------------------------------
- // Header.
// ---------------------------------------------------------------------------
- header: MouseArea {
- height: {
- var height = SmartSearchBarStyle.header.addButtonHeight
- return defaultContact.visible ? height + searchBox.entryHeight : height
- }
- width: parent.width
-
- // Workaround to handle mouse.
- // Without it, the mouse can be given to items list when mouse is hover header.
- hoverEnabled: true
-
- Column {
- anchors.fill: parent
-
- spacing: 0
-
- // -----------------------------------------------------------------------
- // Default contact.
- // -----------------------------------------------------------------------
-
- Loader {
- id: defaultContact
-
- height: searchBox.entryHeight
- width: parent.width
-
- visible: interpretableSipAddress.length > 0
-
- sourceComponent: Rectangle {
- anchors.fill: parent
- color: SmartSearchBarStyle.entry.color.normal
-
- RowLayout {
- anchors {
- fill: parent
- rightMargin: SmartSearchBarStyle.entry.rightMargin
- }
- spacing: 0
-
- Contact {
- id: contact
-
- Layout.fillHeight: true
- Layout.fillWidth: true
-
- entry: ({
- sipAddress: interpretableSipAddress
- })
- }
-
- ActionBar {
- iconSize: SmartSearchBarStyle.entry.iconSize
-
- ActionButton {
- icon: 'video_call'
- onClicked: {
- searchBox.closeMenu()
- searchBox.launchVideoCall(interpretableSipAddress)
- }
- }
-
- ActionButton {
- icon: 'call'
- onClicked: {
- searchBox.closeMenu()
- searchBox.launchCall(interpretableSipAddress)
- }
- }
-
- ActionButton {
- icon: 'chat'
- onClicked: {
- searchBox.closeMenu()
- searchBox.launchChat(interpretableSipAddress)
- }
- }
- }
- }
- }
- }
-
- // -----------------------------------------------------------------------
- // Add contact button.
- // -----------------------------------------------------------------------
-
- MouseArea {
- id: addContactButton
-
- height: SmartSearchBarStyle.header.addButtonHeight
- width: parent.width
-
- onClicked: {
- searchBox.closeMenu()
- searchBox.addContact(interpretableSipAddress)
- }
-
- Rectangle {
- anchors.fill: parent
- color: parent.pressed
- ? SmartSearchBarStyle.header.color.pressed
- : SmartSearchBarStyle.header.color.normal
-
- Text {
- anchors {
- left: parent.left
- leftMargin: SmartSearchBarStyle.header.leftMargin
- verticalCenter: parent.verticalCenter
- }
- font {
- bold: true
- pointSize: SmartSearchBarStyle.header.text.fontSize
- }
- color: addContactButton.pressed
- ? SmartSearchBarStyle.header.text.color.pressed
- : SmartSearchBarStyle.header.text.color.normal
- text: qsTr('addContact')
- }
-
- Icon {
- anchors {
- right: parent.right
- rightMargin: SmartSearchBarStyle.header.rightMargin
- verticalCenter: parent.verticalCenter
- }
- icon: 'contact_add'
- iconSize: SmartSearchBarStyle.header.iconSize
- }
- }
- }
- }
- }
+ onEnterPressed: view.interpretableSipAddress.length > 0 && searchBox.launchCall(interpretableSipAddress)
- // ---------------------------------------------------------------------------
- // Entries.
// ---------------------------------------------------------------------------
- delegate: Rectangle {
- id: sipAddressEntry
+ SipAddressesView {
+ id: view
- color: SmartSearchBarStyle.entry.color.normal
- height: searchBox.entryHeight
- width: parent ? parent.width : 0
-
- Rectangle {
- id: indicator
-
- anchors.left: parent.left
- color: 'transparent'
- height: parent.height
- width: SmartSearchBarStyle.entry.indicator.width
- }
-
- MouseArea {
- id: mouseArea
-
- anchors.fill: parent
- hoverEnabled: true
-
- RowLayout {
- anchors {
- fill: parent
- rightMargin: SmartSearchBarStyle.entry.rightMargin
- }
- spacing: 0
-
- // -------------------------------------------------------------------
- // Contact or address info.
- // -------------------------------------------------------------------
-
- Contact {
- Layout.fillHeight: true
- Layout.fillWidth: true
- entry: $sipAddress
-
- MouseArea {
- anchors.fill: parent
-
- cursorShape: containsMouse
- ? Qt.PointingHandCursor
- : Qt.ArrowCursor
- hoverEnabled: true
-
- onClicked: {
- searchBox.closeMenu()
- searchBox.entryClicked($sipAddress)
- }
- }
- }
-
- // -------------------------------------------------------------------
- // Actions
- // -------------------------------------------------------------------
-
- ActionBar {
- iconSize: SmartSearchBarStyle.entry.iconSize
-
- ActionButton {
- icon: 'video_call'
- onClicked: {
- searchBox.closeMenu()
- searchBox.launchVideoCall($sipAddress.sipAddress)
- }
- }
-
- ActionButton {
- icon: 'call'
- onClicked: {
- searchBox.closeMenu()
- searchBox.launchCall($sipAddress.sipAddress)
- }
- }
-
- ActionButton {
- icon: 'chat'
- onClicked: {
- searchBox.closeMenu()
- searchBox.launchChat($sipAddress.sipAddress)
- }
- }
- }
+ actions: [{
+ icon: 'video_call',
+ handler: function (entry) {
+ searchBox.closeMenu()
+ searchBox.launchVideoCall(entry.sipAddress)
}
- }
-
- // Separator.
- Rectangle {
- color: SmartSearchBarStyle.entry.separator.color
- height: SmartSearchBarStyle.entry.separator.height
- width: parent.width
- }
-
- // -------------------------------------------------------------------------
-
- states: State {
- when: mouseArea.containsMouse
-
- PropertyChanges {
- color: SmartSearchBarStyle.entry.color.hovered
- target: sipAddressEntry
+ }, {
+ icon: 'call',
+ handler: function (entry) {
+ searchBox.closeMenu()
+ searchBox.launchCall(entry.sipAddress)
}
-
- PropertyChanges {
- color: SmartSearchBarStyle.entry.indicator.color
- target: indicator
+ }, {
+ icon: 'chat',
+ handler: function (entry) {
+ searchBox.closeMenu()
+ searchBox.launchChat(entry.sipAddress)
}
+ }]
+
+ headerButtonDescription: qsTr('addContact')
+ headerButtonIcon: 'contact_add'
+ headerButtonAction: (function (sipAddress) {
+ searchBox.closeMenu()
+ searchBox.addContact(sipAddress)
+ })
+
+ genSipAddress: searchBox.filter
+
+ onEntryClicked: {
+ searchBox.closeMenu()
+ searchBox.entryClicked(entry)
}
}
}
diff --git a/linphone-desktop/ui/modules/Linphone/Styles/SmartSearchBar/SmartSearchBarStyle.qml b/linphone-desktop/ui/modules/Linphone/Styles/View/SipAddressesViewStyle.qml
similarity index 91%
rename from linphone-desktop/ui/modules/Linphone/Styles/SmartSearchBar/SmartSearchBarStyle.qml
rename to linphone-desktop/ui/modules/Linphone/Styles/View/SipAddressesViewStyle.qml
index 9922f5435..d0387a077 100644
--- a/linphone-desktop/ui/modules/Linphone/Styles/SmartSearchBar/SmartSearchBarStyle.qml
+++ b/linphone-desktop/ui/modules/Linphone/Styles/View/SipAddressesViewStyle.qml
@@ -7,12 +7,13 @@ import Common 1.0
QtObject {
property QtObject entry: QtObject {
- property int rightMargin: 10
+ property int height: 50
property int iconSize: 36
+ property int rightMargin: 10
property QtObject color: QtObject {
- property color normal: Colors.k
property color hovered: Colors.y
+ property color normal: Colors.k
}
property QtObject indicator: QtObject {
@@ -27,11 +28,14 @@ QtObject {
}
property QtObject header: QtObject {
- property int addButtonHeight: 40
property int iconSize: 22
property int leftMargin: 20
property int rightMargin: 10
+ property QtObject button: QtObject {
+ property int height: 40
+ }
+
property QtObject color: QtObject {
property color normal: Colors.j
property color pressed: Colors.i
diff --git a/linphone-desktop/ui/modules/Linphone/Styles/qmldir b/linphone-desktop/ui/modules/Linphone/Styles/qmldir
index 69a04d187..3bbd06035 100644
--- a/linphone-desktop/ui/modules/Linphone/Styles/qmldir
+++ b/linphone-desktop/ui/modules/Linphone/Styles/qmldir
@@ -28,8 +28,8 @@ singleton NotificationReceivedCallStyle 1.0 Notifications/NotificationRec
singleton NotificationReceivedMessageStyle 1.0 Notifications/NotificationReceivedMessageStyle.qml
singleton NotificationReceivedFileMessageStyle 1.0 Notifications/NotificationReceivedFileMessageStyle.qml
-singleton SmartSearchBarStyle 1.0 SmartSearchBar/SmartSearchBarStyle.qml
-
singleton TelKeypadStyle 1.0 TelKeypad/TelKeypadStyle.qml
singleton TimelineStyle 1.0 Timeline/TimelineStyle.qml
+
+singleton SipAddressesViewStyle 1.0 View/SipAddressesViewStyle.qml
diff --git a/linphone-desktop/ui/modules/Linphone/View/SipAddressesView.qml b/linphone-desktop/ui/modules/Linphone/View/SipAddressesView.qml
new file mode 100644
index 000000000..4bf7f134b
--- /dev/null
+++ b/linphone-desktop/ui/modules/Linphone/View/SipAddressesView.qml
@@ -0,0 +1,269 @@
+import QtQuick 2.7
+import QtQuick.Layouts 1.3
+
+import Common 1.0
+import Linphone 1.0
+import Linphone.Styles 1.0
+
+// =============================================================================
+
+ScrollableListView {
+ id: sipAddressesView
+
+ // ---------------------------------------------------------------------------
+
+ // Contains a list of: {
+ // icon: 'string',
+ // handler: function () { ... }
+ // }
+ property var actions: []
+
+ property string genSipAddress
+
+ // Optional parameters.
+ property string headerButtonDescription
+ property string headerButtonIcon
+ property var headerButtonAction
+
+ readonly property string interpretableSipAddress: SipAddressesModel.interpretUrl(
+ genSipAddress
+ )
+
+ // ---------------------------------------------------------------------------
+
+ signal entryClicked (var entry)
+
+ // ---------------------------------------------------------------------------
+ // Header.
+ // ---------------------------------------------------------------------------
+
+ header: MouseArea {
+ height: {
+ var height = headerButton.visible ? SipAddressesViewStyle.header.button.height : 0
+ if (defaultContact.visible) {
+ height += SipAddressesViewStyle.entry.height
+ }
+ return height
+ }
+ width: parent.width
+
+ // Workaround to handle mouse.
+ // Without it, the mouse can be given to items list when mouse is hover header.
+ hoverEnabled: true
+
+ Column {
+ anchors.fill: parent
+
+ spacing: 0
+
+ // -----------------------------------------------------------------------
+ // Default contact.
+ // -----------------------------------------------------------------------
+
+ Loader {
+ id: defaultContact
+
+ height: SipAddressesViewStyle.entry.height
+ width: parent.width
+
+ visible: sipAddressesView.interpretableSipAddress.length > 0
+
+ sourceComponent: Rectangle {
+ anchors.fill: parent
+ color: SipAddressesViewStyle.entry.color.normal
+
+ RowLayout {
+ anchors {
+ fill: parent
+ rightMargin: SipAddressesViewStyle.entry.rightMargin
+ }
+ spacing: 0
+
+ Contact {
+ id: contact
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ entry: ({
+ sipAddress: sipAddressesView.interpretableSipAddress
+ })
+ }
+
+ ActionBar {
+ iconSize: SipAddressesViewStyle.entry.iconSize
+
+ Repeater {
+ model: sipAddressesView.actions
+
+ ActionButton {
+ icon: modelData.icon
+ onClicked: sipAddressesView.actions[index].handler({
+ sipAddress: sipAddressesView.interpretableSipAddress
+ })
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // -----------------------------------------------------------------------
+ // Header button.
+ // -----------------------------------------------------------------------
+
+ MouseArea {
+ id: headerButton
+
+ height: SipAddressesViewStyle.header.button.height
+ width: parent.width
+
+ visible: !!sipAddressesView.headerButtonAction
+
+ onClicked: sipAddressesView.headerButtonAction(sipAddressesView.interpretableSipAddress)
+
+ Rectangle {
+ anchors.fill: parent
+ color: parent.pressed
+ ? SipAddressesViewStyle.header.color.pressed
+ : SipAddressesViewStyle.header.color.normal
+
+ Text {
+ anchors {
+ left: parent.left
+ leftMargin: SipAddressesViewStyle.header.leftMargin
+ verticalCenter: parent.verticalCenter
+ }
+
+ font {
+ bold: true
+ pointSize: SipAddressesViewStyle.header.text.fontSize
+ }
+
+ color: headerButton.pressed
+ ? SipAddressesViewStyle.header.text.color.pressed
+ : SipAddressesViewStyle.header.text.color.normal
+ text: sipAddressesView.headerButtonDescription
+ }
+
+ Icon {
+ anchors {
+ right: parent.right
+ rightMargin: SipAddressesViewStyle.header.rightMargin
+ verticalCenter: parent.verticalCenter
+ }
+
+ icon: sipAddressesView.headerButtonIcon
+ iconSize: SipAddressesViewStyle.header.iconSize
+
+ visible: icon.length > 0
+ }
+ }
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Entries.
+ // ---------------------------------------------------------------------------
+
+ delegate: Rectangle {
+ id: sipAddressEntry
+
+ color: SipAddressesViewStyle.entry.color.normal
+ height: SipAddressesViewStyle.entry.height
+ width: parent ? parent.width : 0
+
+ Rectangle {
+ id: indicator
+
+ anchors.left: parent.left
+ color: 'transparent'
+ height: parent.height
+ width: SipAddressesViewStyle.entry.indicator.width
+ }
+
+ MouseArea {
+ id: mouseArea
+
+ anchors.fill: parent
+ hoverEnabled: true
+
+ RowLayout {
+ anchors {
+ fill: parent
+ rightMargin: SipAddressesViewStyle.entry.rightMargin
+ }
+ spacing: 0
+
+ // ---------------------------------------------------------------------
+ // Contact or address info.
+ // ---------------------------------------------------------------------
+
+ Contact {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ entry: $sipAddress
+
+ MouseArea {
+ anchors.fill: parent
+
+ cursorShape: containsMouse
+ ? Qt.PointingHandCursor
+ : Qt.ArrowCursor
+ hoverEnabled: true
+
+ onClicked: sipAddressesView.entryClicked($sipAddress)
+ }
+ }
+
+ // ---------------------------------------------------------------------
+ // Actions
+ // ---------------------------------------------------------------------
+
+ ActionBar {
+ iconSize: SipAddressesViewStyle.entry.iconSize
+
+ Repeater {
+ model: sipAddressesView.actions
+
+ ActionButton {
+ icon: modelData.icon
+ onClicked: sipAddressesView.actions[index].handler($sipAddress)
+ }
+ }
+ }
+ }
+ }
+
+ // Separator.
+ Rectangle {
+ color: SipAddressesViewStyle.entry.separator.color
+ height: SipAddressesViewStyle.entry.separator.height
+ width: parent.width
+ }
+
+ // -------------------------------------------------------------------------
+
+ states: State {
+ when: mouseArea.containsMouse
+
+ PropertyChanges {
+ color: SipAddressesViewStyle.entry.color.hovered
+ target: sipAddressEntry
+ }
+
+ PropertyChanges {
+ color: SipAddressesViewStyle.entry.indicator.color
+ target: indicator
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Model.
+ // ---------------------------------------------------------------------------
+
+ model: SipAddressesProxyModel {}
+}
diff --git a/linphone-desktop/ui/views/App/Main/MainWindow.qml b/linphone-desktop/ui/views/App/Main/MainWindow.qml
index 8c6f4f5cb..79bbcc899 100644
--- a/linphone-desktop/ui/views/App/Main/MainWindow.qml
+++ b/linphone-desktop/ui/views/App/Main/MainWindow.qml
@@ -150,12 +150,9 @@ ApplicationWindow {
Layout.fillWidth: true
- entryHeight: MainWindowStyle.searchBox.entryHeight
maxMenuHeight: MainWindowStyle.searchBox.maxHeight
placeholderText: qsTr('mainSearchBarPlaceholder')
- model: SipAddressesProxyModel {}
-
onAddContact: window.setView('ContactEdit', {
sipAddress: sipAddress
})
@@ -210,7 +207,7 @@ ApplicationWindow {
ApplicationMenu {
id: menu
- entryHeight: MainWindowStyle.menu.entryHeight
+ entryHeight: MainWindowStyle.menu.height
entryWidth: MainWindowStyle.menu.width
entries: [{
diff --git a/linphone-desktop/ui/views/App/Styles/Main/MainWindowStyle.qml b/linphone-desktop/ui/views/App/Styles/Main/MainWindowStyle.qml
index 53cf92df9..3e1e1fc22 100644
--- a/linphone-desktop/ui/views/App/Styles/Main/MainWindowStyle.qml
+++ b/linphone-desktop/ui/views/App/Styles/Main/MainWindowStyle.qml
@@ -28,12 +28,11 @@ QtObject {
}
property QtObject menu: QtObject {
- property int entryHeight: 50
+ property int height: 50
property int width: 250
}
property QtObject searchBox: QtObject {
- property int entryHeight: 50 + SmartSearchBarStyle.entry.separator.height
property int maxHeight: 300 // See Hick's law for good choice.
}
diff --git a/submodules/linphone b/submodules/linphone
index 5e077c08b..2a3a23563 160000
--- a/submodules/linphone
+++ b/submodules/linphone
@@ -1 +1 @@
-Subproject commit 5e077c08b4c243e19d1432f89b2a69eebb69d5ee
+Subproject commit 2a3a235634ce9fa7015a7ec6807679a361873ee6