mirror of
https://invent.kde.org/network/kdeconnect-kde.git
synced 2025-12-12 20:35:55 +01:00
smsapp: Make messages in ConversationDisplay always stick to the bottom
This commit mostly reverses the direction of the ListView used by ConversationDisplay to make it bottom-to-top. This matches the way most chat apps work today (e.g. Discord), by leaving an empty space at the top when there are not enough messages to fill the screen. Testing it, it seems like a bunch of the custom logic for scrolling down when there are new messages and staying focused on the current message while loading new ones can now be transparently handled by the ListView, so this trims down the code quite a lot. While re-working the message loading, I also switched it to use a constant threshold rather than a proportional one, which fixes cases where scrolling down could load older messages. [Enregistrement d'écran_20250707_103723.webm](/uploads/99efd26958e73fed1ce6f0e04bae51f4/Enregistrement_d_%C3%A9cran_20250707_103723.webm) Overall, this makes the ConversationDisplay scrolling much smoother.
This commit is contained in:
@@ -237,4 +237,18 @@ void ConversationModel::requestAttachmentPath(const qint64 &partID, const QStrin
|
||||
m_conversationsInterface->requestAttachmentFile(partID, uniqueIdentifier);
|
||||
}
|
||||
|
||||
bool ConversationModel::canFetchMore(const QModelIndex & /* parent */) const
|
||||
{
|
||||
// TODO: Is there any way to know when we're at the end of the conversation and can't fetch more?
|
||||
// Would be neat to show an indication to the user in such a case (and stop fetching more data)
|
||||
// but would also likely require sending that information from the phone, as I don't see an
|
||||
// obvious way to know that using currently available information...
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConversationModel::fetchMore(const QModelIndex & /* parent */)
|
||||
{
|
||||
requestMoreMessages();
|
||||
}
|
||||
|
||||
#include "moc_conversationmodel.cpp"
|
||||
|
||||
@@ -61,6 +61,9 @@ public:
|
||||
|
||||
Q_INVOKABLE void requestAttachmentPath(const qint64 &partID, const QString &UniqueIdentifier);
|
||||
|
||||
bool canFetchMore(const QModelIndex &parent) const override;
|
||||
void fetchMore(const QModelIndex &parent) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void loadingFinished();
|
||||
void filePathReceived(QString filePath, QString fileName);
|
||||
|
||||
@@ -66,13 +66,14 @@ Kirigami.ScrollablePage
|
||||
id: viewport
|
||||
model: QSortFilterProxyModel {
|
||||
id: model
|
||||
sortOrder: Qt.AscendingOrder
|
||||
sortOrder: Qt.DescendingOrder
|
||||
sortRole: ConversationModel.DateRole
|
||||
sourceModel: conversationModel
|
||||
}
|
||||
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
highlightMoveDuration: 0
|
||||
verticalLayoutDirection: Qt.BottomToTop
|
||||
|
||||
Controls.BusyIndicator {
|
||||
running: !isInitalized
|
||||
@@ -117,69 +118,10 @@ Kirigami.ScrollablePage
|
||||
|
||||
width: viewport.width
|
||||
|
||||
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: {
|
||||
SmsHelper.copyToClipboard(message)
|
||||
}
|
||||
}
|
||||
|
||||
/// As the user scrolls, load more messages when they get to the top.
|
||||
/// This used to use the onMovementEnded signal, but at some point
|
||||
/// that signal stopped being emitted reliably when scrolling with
|
||||
/// the mouse. onContentYChanged is fine for our use, just a bit noisy.
|
||||
onContentYChanged: {
|
||||
if (!isInitalized) {
|
||||
return
|
||||
}
|
||||
|
||||
// If we have scrolled near to the top, request more messages
|
||||
// This threshold of visibleArea.yPosition has been chosen experimentally, but
|
||||
// should generally be OK because it is defined as a ratio of the content to the visible
|
||||
// area. As more messages get loaded into our view, this constant will start to be
|
||||
// less-sane, meaning we will request messages earlier as the user scrolls back in time.
|
||||
// This is probably a good thing, because it means that scrolling back further and further
|
||||
// quickly, will be more likely to be smooth.
|
||||
// Combined with `atYBeginning`, the view scrolls smoothly for me, long past the point where
|
||||
// the rest of the app is stable, and past the point where Android can fetch messages fast
|
||||
// enough.
|
||||
if (visibleArea.yPosition < 0.075 || 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: SendingArea {
|
||||
|
||||
Reference in New Issue
Block a user