kdeconnect-kde/smsapp/qml/ConversationDisplay.qml
Jiří Wolker 6abe790aa4 [SMS App] Make SMS character counter width only grow
SMS character counter was changing its width (both growing and
shrinking) so it also resized message field (and that caused text
reflow). This patch makes counter width only grow.

Type SMS that is long enough to make SMS character counter wider than
“Send” button. Remove the text (leave there 150 or 60 chars to keep it
visible). Character counter should keep its width.
2020-04-23 17:19:15 -07:00

271 lines
9.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.1
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import org.kde.people 1.0
import org.kde.kirigami 2.4 as Kirigami
import org.kde.kdeconnect.sms 1.0
import QtGraphicalEffects 1.0
Kirigami.ScrollablePage
{
id: page
property bool deviceConnected
property string deviceId
// property QtObject device
property string conversationId
property bool isMultitarget
property string initialMessage
property string otherParty
property string invalidId: "-1"
property bool isInitalized: false
property var conversationModel: ConversationModel {
deviceId: page.deviceId
threadId: page.conversationId
otherParty: page.otherParty
onLoadingFinished: {
page.isInitalized = true
}
}
property var addresses
title: conversationModel.getTitleForAddresses(addresses)
Component.onCompleted: {
if (initialMessage.length > 0) {
messageField.text = initialMessage;
initialMessage = ""
}
if (conversationId == invalidId) {
isInitalized = true
}
}
/**
* Build a chat message which is representative of all chat messages
*
* In other words, one which I can use to get a reasonable height guess
*/
ChatMessage {
id: genericMessage
name: "Generic Sender"
messageBody: "Generic Message Body"
dateTime: new Date('2000-0-0')
visible: false
enabled: false
}
ListView {
id: viewport
model: QSortFilterProxyModel {
id: model
sortOrder: Qt.AscendingOrder
sortRole: ConversationModel.DateRole
sourceModel: conversationModel
}
spacing: Kirigami.Units.largeSpacing
highlightMoveDuration: 0
BusyIndicator {
running: !isInitalized
}
onContentHeightChanged: {
if (viewport.contentHeight <= 0) {
return
}
if (!isInitalized) {
// If we aren't initialized, we need to request enough messages to fill the view
// In order to do that, request one more message until we have enough
if (viewport.contentHeight < viewport.height) {
console.debug("Requesting another message to fill the screen")
conversationModel.requestMoreMessages(1)
} else {
// Finish initializing: Scroll to the bottom of the view
// View the most-recent message
viewport.forceLayout()
Qt.callLater(viewport.positionViewAtEnd)
isInitalized = true
}
return
}
}
delegate: ChatMessage {
name: model.sender
messageBody: model.display
sentByMe: model.fromMe
dateTime: new Date(model.date)
ListView.onAdd: {
if (!isInitalized) {
return
}
if (index == viewport.count - 1) {
// This message is being inserted at the newest position
// We want to scroll to show it if the user is "almost" looking at it
// Define some fudge area. If the message is being drawn offscreen but within
// this distance, we move to show it anyway.
// Selected to be genericMessage.height because that value scales for different
// font sizes / DPI / etc. -- Better ideas are welcome!
// Double the value works nicely
var offscreenFudge = 2 * genericMessage.height
var viewportYBottom = viewport.contentY + viewport.height
if (y < viewportYBottom + genericMessage.height) {
viewport.highlightMoveDuration = -1
viewport.currentIndex = index
}
}
}
onMessageCopyRequested: {
conversationModel.copyToClipboard(message)
}
}
onMovementEnded: {
if (!isInitalized) {
return
}
// Unset the highlightRangeMode if it was set previously
highlightRangeMode = ListView.ApplyRange
// If we have scrolled to the last message currently in the view, request some more
if (atYBeginning) {
// "Lock" the view to the message currently at the beginning of the view
// This prevents the view from snapping to the top of the messages we are about to request
currentIndex = 0 // Index 0 is the beginning of the view
preferredHighlightBegin = visibleArea.yPosition
preferredHighlightEnd = preferredHighlightBegin + currentItem.height
highlightRangeMode = ListView.StrictlyEnforceRange
highlightMoveDuration = 0
// Get more messages
conversationModel.requestMoreMessages()
}
}
}
footer: Pane {
id: sendingArea
enabled: page.deviceConnected && !page.isMultitarget
layer.enabled: sendingArea.enabled
layer.effect: DropShadow {
verticalOffset: 1
color: Kirigami.Theme.disabledTextColor
samples: 20
spread: 0.3
}
Layout.fillWidth: true
padding: 0
wheelEnabled: true
background: Rectangle {
color: Kirigami.Theme.viewBackgroundColor
}
RowLayout {
anchors.fill: parent
TextArea {
id: messageField
Layout.fillWidth: true
placeholderText: page.isMultitarget ? i18nd("kdeconnect-sms", "Replying to multitarget messages is not supported") : i18nd("kdeconnect-sms", "Compose message")
wrapMode: TextArea.Wrap
topPadding: Kirigami.Units.gridUnit * 0.5
bottomPadding: topPadding
selectByMouse: true
background: Item {}
Keys.onReturnPressed: {
if (event.key === Qt.Key_Return) {
if (event.modifiers & Qt.ShiftModifier) {
messageField.append("")
} else {
sendButton.onClicked()
event.accepted = true
}
}
}
}
ColumnLayout {
ToolButton {
id: sendButton
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
padding: 0
Kirigami.Icon {
source: "document-send"
enabled: sendButton.enabled
isMask: true
smooth: true
anchors.centerIn: parent
width: Kirigami.Units.gridUnit * 1.5
height: width
}
onClicked: {
// don't send empty messages
if (!messageField.text.length) {
return
}
// disable the button to prevent sending
// the same message several times
sendButton.enabled = false
// send the message
if (page.conversationId == page.invalidId) {
conversationModel.sendMessageWithoutConversation(messageField.text, page.otherParty)
} else {
conversationModel.sendReplyToConversation(messageField.text)
}
messageField.text = ""
// re-enable the button
sendButton.enabled = true
}
}
Label {
id: "charCount"
text: conversationModel.getCharCountInfo(messageField.text)
visible: text.length > 0
Layout.minimumWidth: Math.max(Layout.minimumWidth, width) // Make this label only grow, never shrink
}
}
}
}
}