diff --git a/src/timeline/CMakeLists.txt b/src/timeline/CMakeLists.txt index b3d43f7a0..2a8917302 100644 --- a/src/timeline/CMakeLists.txt +++ b/src/timeline/CMakeLists.txt @@ -13,6 +13,7 @@ ecm_add_qml_module(Timeline GENERATE_PLUGIN_SOURCE LoadingDelegate.qml PredecessorDelegate.qml ReadMarkerDelegate.qml + SpacerDelegate.qml StateDelegate.qml SuccessorDelegate.qml TimelineEndDelegate.qml diff --git a/src/timeline/EventDelegate.qml b/src/timeline/EventDelegate.qml index 8dd0ea802..595c69e95 100644 --- a/src/timeline/EventDelegate.qml +++ b/src/timeline/EventDelegate.qml @@ -62,6 +62,11 @@ DelegateChooser { } } + DelegateChoice { + roleValue: DelegateType.Spacer + delegate: SpacerDelegate {} + } + DelegateChoice { roleValue: DelegateType.Other delegate: NeoChatConfig.showAllEvents ? hiddenDelegate : emptyDelegate diff --git a/src/timeline/SpacerDelegate.qml b/src/timeline/SpacerDelegate.qml new file mode 100644 index 000000000..6c8c651c6 --- /dev/null +++ b/src/timeline/SpacerDelegate.qml @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2025 James Graham +// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + +import QtQuick + +import org.kde.kirigami as Kirigami + +Item { + width: parent?.width + height: Kirigami.Units.largeSpacing + Math.round(Kirigami.Theme.defaultFont.pointSize * 2) +} diff --git a/src/timeline/TimelineView.qml b/src/timeline/TimelineView.qml index ed782018d..71667ad1a 100644 --- a/src/timeline/TimelineView.qml +++ b/src/timeline/TimelineView.qml @@ -68,7 +68,6 @@ QQC2.ScrollView { verticalLayoutDirection: ListView.BottomToTop clip: true interactive: Kirigami.Settings.isMobile - bottomMargin: Kirigami.Units.largeSpacing + Math.round(Kirigami.Theme.defaultFont.pointSize * 2) model: root.messageFilterModel diff --git a/src/timeline/enums/delegatetype.h b/src/timeline/enums/delegatetype.h index 9425b0dde..7b0209831 100644 --- a/src/timeline/enums/delegatetype.h +++ b/src/timeline/enums/delegatetype.h @@ -42,6 +42,7 @@ public: TimelineEnd, /**< A delegate to inform that all messages are loaded. */ Predecessor, /**< A delegate to show a room predecessor. */ Successor, /**< A delegate to show a room successor. */ + Spacer, /**< A spacer because ListView.positionViewAtBeginning() is stupid and ignores white space. */ Other, /**< Anything that cannot be classified as another type. */ }; Q_ENUM(Type); diff --git a/src/timeline/models/timelinemodel.cpp b/src/timeline/models/timelinemodel.cpp index 90d2ff0e5..b16416c21 100644 --- a/src/timeline/models/timelinemodel.cpp +++ b/src/timeline/models/timelinemodel.cpp @@ -81,12 +81,14 @@ void TimelineBeginningModel::setRoom(NeoChatRoom *room) QVariant TimelineBeginningModel::data(const QModelIndex &idx, int role) const { - Q_UNUSED(idx) if (m_room == nullptr) { return {}; } if (role == DelegateTypeRole) { + if (idx.row() == 0) { + return DelegateType::Spacer; + } return DelegateType::Successor; } return {}; @@ -98,7 +100,7 @@ int TimelineBeginningModel::rowCount(const QModelIndex &parent) const if (m_room == nullptr) { return 1; } - return m_room->successorId().isEmpty() ? 0 : 1; + return m_room->successorId().isEmpty() ? 1 : 2; } QHash TimelineBeginningModel::roleNames() const