Warning, /network/kdeconnect-kde/smsapp/qml/ConversationDisplay.qml is written in an unsupported language. File is not indexed.
0001 /** 0002 * SPDX-FileCopyrightText: 2018 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 * SPDX-FileCopyrightText: 2018 Nicolas Fella <nicolas.fella@gmx.de> 0004 * SPDX-FileCopyrightText: 2018 Simon Redman <simon@ergotech.com> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0007 */ 0008 0009 import QtQuick 0010 import QtQuick.Controls as Controls 0011 import QtQuick.Layouts 0012 import org.kde.people 0013 import org.kde.kirigami as Kirigami 0014 import org.kde.kdeconnect.sms 0015 import Qt5Compat.GraphicalEffects 0016 0017 Kirigami.ScrollablePage 0018 { 0019 id: page 0020 0021 property bool deviceConnected 0022 property string conversationId 0023 property bool isMultitarget 0024 property string initialMessage 0025 property string invalidId: "-1" 0026 0027 property bool isInitalized: false 0028 0029 property var conversationModel: ConversationModel { 0030 deviceId: AppData.deviceId 0031 threadId: page.conversationId 0032 addressList: page.addresses 0033 0034 onLoadingFinished: { 0035 page.isInitalized = true 0036 } 0037 } 0038 0039 property var addresses 0040 title: SmsHelper.getTitleForAddresses(addresses) 0041 0042 Component.onCompleted: { 0043 if (initialMessage.length > 0) { 0044 sendingArea.text = initialMessage; 0045 initialMessage = "" 0046 } 0047 if (conversationId == invalidId) { 0048 isInitalized = true 0049 } 0050 } 0051 0052 /** 0053 * Build a chat message which is representative of all chat messages 0054 * 0055 * In other words, one which I can use to get a reasonable height guess 0056 */ 0057 ChatMessage { 0058 id: genericMessage 0059 name: "Generic Sender" 0060 messageBody: "Generic Message Body" 0061 dateTime: new Date('2000-0-0') 0062 visible: false 0063 enabled: false 0064 } 0065 0066 ListView { 0067 id: viewport 0068 model: QSortFilterProxyModel { 0069 id: model 0070 sortOrder: Qt.AscendingOrder 0071 sortRole: ConversationModel.DateRole 0072 sourceModel: conversationModel 0073 } 0074 0075 spacing: Kirigami.Units.largeSpacing 0076 highlightMoveDuration: 0 0077 0078 Controls.BusyIndicator { 0079 running: !isInitalized 0080 anchors.centerIn: parent 0081 } 0082 0083 header: Item { 0084 height: Kirigami.Units.largeSpacing * 2 0085 } 0086 headerPositioning: ListView.InlineHeader 0087 0088 onContentHeightChanged: { 0089 if (viewport.contentHeight <= 0) { 0090 return 0091 } 0092 0093 if (!isInitalized) { 0094 // If we aren't initialized, we need to request enough messages to fill the view 0095 // In order to do that, request one more message until we have enough 0096 if (viewport.contentHeight < viewport.height) { 0097 console.debug("Requesting another message to fill the screen") 0098 conversationModel.requestMoreMessages(1) 0099 } else { 0100 // Finish initializing: Scroll to the bottom of the view 0101 0102 // View the most-recent message 0103 viewport.forceLayout() 0104 Qt.callLater(viewport.positionViewAtEnd) 0105 isInitalized = true 0106 } 0107 return 0108 } 0109 } 0110 0111 delegate: ChatMessage { 0112 name: model.sender 0113 messageBody: model.display 0114 sentByMe: model.fromMe 0115 dateTime: new Date(model.date) 0116 multiTarget: isMultitarget 0117 attachmentList: model.attachments 0118 0119 width: viewport.width 0120 0121 ListView.onAdd: { 0122 if (!isInitalized) { 0123 return 0124 } 0125 0126 if (index == viewport.count - 1) { 0127 // This message is being inserted at the newest position 0128 // We want to scroll to show it if the user is "almost" looking at it 0129 0130 // Define some fudge area. If the message is being drawn offscreen but within 0131 // this distance, we move to show it anyway. 0132 // Selected to be genericMessage.height because that value scales for different 0133 // font sizes / DPI / etc. -- Better ideas are welcome! 0134 // Double the value works nicely 0135 var offscreenFudge = 2 * genericMessage.height 0136 0137 var viewportYBottom = viewport.contentY + viewport.height 0138 0139 if (y < viewportYBottom + genericMessage.height) { 0140 viewport.highlightMoveDuration = -1 0141 viewport.currentIndex = index 0142 } 0143 } 0144 } 0145 0146 onMessageCopyRequested: { 0147 SmsHelper.copyToClipboard(message) 0148 } 0149 } 0150 0151 /// As the user scrolls, load more messages when they get to the top. 0152 /// This used to use the onMovementEnded signal, but at some point 0153 /// that signal stopped being emitted reliably when scrolling with 0154 /// the mouse. onContentYChanged is fine for our use, just a bit noisy. 0155 onContentYChanged: { 0156 if (!isInitalized) { 0157 return 0158 } 0159 0160 // If we have scrolled near to the top, request more messages 0161 // This threshold of visibleArea.yPosition has been chosen experimentally, but 0162 // should generally be OK because it is defined as a ratio of the content to the visible 0163 // area. As more messages get loaded into our view, this constant will start to be 0164 // less-sane, meaning we will request messages earlier as the user scrolls back in time. 0165 // This is probably a good thing, because it means that scrolling back further and further 0166 // quickly, will be more likely to be smooth. 0167 // Combined with `atYBeginning`, the view scrolls smoothly for me, long past the point where 0168 // the rest of the app is stable, and past the point where Android can fetch messages fast 0169 // enough. 0170 if (visibleArea.yPosition < 0.075 || atYBeginning) { 0171 // "Lock" the view to the message currently at the beginning of the view 0172 // This prevents the view from snapping to the top of the messages we are about to request 0173 currentIndex = 0 // Index 0 is the beginning of the view 0174 preferredHighlightBegin = visibleArea.yPosition 0175 preferredHighlightEnd = preferredHighlightBegin + currentItem.height 0176 highlightRangeMode = ListView.StrictlyEnforceRange 0177 0178 highlightMoveDuration = 0 0179 0180 // Get more messages 0181 conversationModel.requestMoreMessages() 0182 } 0183 } 0184 } 0185 0186 footer: SendingArea { 0187 id: sendingArea 0188 0189 width: parent.width 0190 addresses: page.addresses 0191 } 0192 }