kdeconnect-kde/smsapp/qml/ConversationList.qml
Aniket Kumar f211d7e401 Add feature to start new conversation with existing contacts
## Summary

Start a conversation with contacts having no previous conversation with.

It is currently only possible to use the messaging app to send a message to a conversation which already exists.

This patch implements this feature by integrating all contacts having no prior conversation with the recent conversations in the recent conversation list and at the bottom in a sorted manner, something like this,

The contacts are stored in the recent conversation list model as a conversation but with INVALID conversation ID and INVALID conversation DATE.

## Testing

Testing just needs kdeconnect daemon to be recompiled and executed.
2020-03-21 22:57:28 +00:00

245 lines
8.5 KiB
QML

/**
* Copyright (C) 2018 Aleix Pol Gonzalez <aleixpol@kde.org>
* Copyright (C) 2018 Nicolas Fella <nicolas.fella@gmx.de>
* Copyright (C) 2018 Simon Redman <simon@ergotech.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import org.kde.people 1.0
import org.kde.kirigami 2.6 as Kirigami
import org.kde.kdeconnect 1.0
import org.kde.kdeconnect.sms 1.0
Kirigami.ScrollablePage
{
id: page
ToolTip {
id: noDevicesWarning
visible: !page.deviceConnected
timeout: -1
text: "⚠️ " + i18nd("kdeconnect-sms", "No devices available") + " ⚠️"
MouseArea {
// Detect mouseover and show another tooltip with more information
anchors.fill: parent
hoverEnabled: true
ToolTip.visible: containsMouse
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
// TODO: Wrap text if line is too long for the screen
ToolTip.text: i18nd("kdeconnect-sms", "No new messages can be sent or received, but you can browse cached content")
}
}
contextualActions: [
Kirigami.Action {
text: i18nd("kdeconnect-sms", "Refresh")
icon.name: "view-refresh"
enabled: devicesCombo.count > 0
onTriggered: {
conversationListModel.refresh()
}
}
]
ColumnLayout {
id: loadingMessage
visible: deviceConnected && view.count == 0
anchors.centerIn: parent
BusyIndicator {
running: loadingMessage.visible
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
Label {
text: "Loading conversations from device. If this takes a long time, please wake up your device and then click refresh."
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.preferredWidth: page.width / 2
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
}
Label {
text: "Tip: If you plug in your device, it should not go into doze mode and should load quickly."
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.preferredWidth: page.width / 2
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
}
}
property string initialMessage
property string initialDevice
header: Kirigami.InlineMessage {
Layout.fillWidth: true
visible: page.initialMessage.length > 0
text: i18nd("kdeconnect-sms", "Choose recipient")
actions: [
Kirigami.Action {
iconName: "dialog-cancel"
text: i18nd("kdeconnect-sms", "Cancel")
onTriggered: initialMessage = ""
}
]
}
footer: ComboBox {
id: devicesCombo
enabled: count > 0
displayText: !enabled ? i18nd("kdeconnect-sms", "No devices available") : undefined
model: DevicesSortProxyModel {
id: devicesModel
//TODO: make it possible to filter if they can do sms
sourceModel: DevicesModel { displayFilter: DevicesModel.Paired | DevicesModel.Reachable }
onRowsInserted: if (devicesCombo.currentIndex < 0) {
if (page.initialDevice)
devicesCombo.currentIndex = devicesModel.rowForDevice(page.initialDevice);
else
devicesCombo.currentIndex = 0
}
}
textRole: "display"
}
readonly property bool deviceConnected: devicesCombo.enabled
readonly property QtObject device: devicesCombo.currentIndex >= 0 ? devicesModel.data(devicesModel.index(devicesCombo.currentIndex, 0), DevicesModel.DeviceRole) : null
readonly property alias lastDeviceId: conversationListModel.deviceId
Component {
id: chatView
ConversationDisplay {
deviceId: page.lastDeviceId
deviceConnected: page.deviceConnected
}
}
ListView {
id: view
currentIndex: 0
model: QSortFilterProxyModel {
sortOrder: Qt.DescendingOrder
filterCaseSensitivity: Qt.CaseInsensitive
sourceModel: ConversationListModel {
id: conversationListModel
deviceId: device ? device.id() : ""
}
}
header: TextField {
/**
* Used as the filter of the list of messages
*/
id: filter
placeholderText: i18nd("kdeconnect-sms", "Filter...")
width: parent.width
z: 10
onTextChanged: {
if (filter.text != "") {
view.model.setOurFilterRole(Qt.DisplayRole)
} else {
view.model.setOurFilterRole(ConversationListModel.ConversationIdRole)
}
view.model.setFilterFixedString(filter.text)
view.currentIndex = 0
}
onAccepted: {
view.currentItem.startChat()
}
Keys.onReturnPressed: {
event.accepted = true
filter.onAccepted()
}
Keys.onEscapePressed: {
event.accepted = filter.text != ""
filter.text = ""
}
Shortcut {
sequence: "Ctrl+F"
onActivated: filter.forceActiveFocus()
}
}
headerPositioning: ListView.OverlayHeader
Keys.forwardTo: [headerItem]
delegate: Kirigami.AbstractListItem
{
id: listItem
contentItem: RowLayout {
Kirigami.Icon {
id: iconItem
source: decoration
readonly property int size: Kirigami.Units.iconSizes.smallMedium
Layout.minimumHeight: size
Layout.maximumHeight: size
Layout.minimumWidth: size
selected: listItem.highlighted || listItem.checked || (listItem.pressed && listItem.supportsMouseEvents)
}
ColumnLayout {
Label {
Layout.fillWidth: true
font.weight: Font.Bold
text: display
maximumLineCount: 1
elide: Text.ElideRight
textFormat: Text.PlainText
}
Label {
Layout.fillWidth: true
text: toolTip
maximumLineCount: 1
elide: Text.ElideRight
textFormat: Text.PlainText
}
}
}
function startChat() {
applicationWindow().pageStack.push(chatView, {
addresses: addresses,
conversationId: model.conversationId,
isMultitarget: isMultitarget,
initialMessage: page.initialMessage,
device: device,
otherParty: sender})
initialMessage = ""
}
onClicked: {
startChat();
view.currentIndex = index
}
// Keep the currently-open chat highlighted even if this element is not focused
highlighted: chatView.conversationId == model.conversationId
}
Component.onCompleted: {
currentIndex = -1
focus = true
}
}
}