Add button to view pinned messages in a room
BUG: 497427
This commit is contained in:
@@ -194,6 +194,8 @@ add_library(neochat STATIC
|
|||||||
models/messagemodel.h
|
models/messagemodel.h
|
||||||
models/messagecontentfiltermodel.cpp
|
models/messagecontentfiltermodel.cpp
|
||||||
models/messagecontentfiltermodel.h
|
models/messagecontentfiltermodel.h
|
||||||
|
models/pinnedmessagemodel.cpp
|
||||||
|
models/pinnedmessagemodel.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||||
@@ -249,6 +251,7 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
|||||||
qml/MessageSourceSheet.qml
|
qml/MessageSourceSheet.qml
|
||||||
qml/ConfirmEncryptionDialog.qml
|
qml/ConfirmEncryptionDialog.qml
|
||||||
qml/RoomSearchPage.qml
|
qml/RoomSearchPage.qml
|
||||||
|
qml/RoomPinnedMessagesPage.qml
|
||||||
qml/LocationChooser.qml
|
qml/LocationChooser.qml
|
||||||
qml/TimelineView.qml
|
qml/TimelineView.qml
|
||||||
qml/InvitationView.qml
|
qml/InvitationView.qml
|
||||||
@@ -534,6 +537,7 @@ if(ANDROID)
|
|||||||
"list-remove-symbolic"
|
"list-remove-symbolic"
|
||||||
"edit-delete"
|
"edit-delete"
|
||||||
"user-home-symbolic"
|
"user-home-symbolic"
|
||||||
|
"pin-symbolic"
|
||||||
)
|
)
|
||||||
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
|
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
|
||||||
else()
|
else()
|
||||||
|
|||||||
67
src/models/pinnedmessagemodel.cpp
Normal file
67
src/models/pinnedmessagemodel.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "pinnedmessagemodel.h"
|
||||||
|
|
||||||
|
#include "enums/delegatetype.h"
|
||||||
|
#include "eventhandler.h"
|
||||||
|
#include "models/messagecontentmodel.h"
|
||||||
|
#include "neochatroom.h"
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
using namespace Quotient;
|
||||||
|
|
||||||
|
PinnedMessageModel::PinnedMessageModel(QObject *parent)
|
||||||
|
: MessageModel(parent)
|
||||||
|
{
|
||||||
|
connect(this, &MessageModel::roomChanged, this, &PinnedMessageModel::fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PinnedMessageModel::loading() const
|
||||||
|
{
|
||||||
|
return m_loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PinnedMessageModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return m_pinnedEvents.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::reference_wrapper<const Quotient::RoomEvent>> PinnedMessageModel::getEventForIndex(const QModelIndex index) const
|
||||||
|
{
|
||||||
|
if (static_cast<size_t>(index.row()) >= m_pinnedEvents.size() || index.row() < 0) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return std::reference_wrapper{*m_pinnedEvents[index.row()].get()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedMessageModel::setLoading(bool loading)
|
||||||
|
{
|
||||||
|
m_loading = loading;
|
||||||
|
Q_EMIT loadingChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedMessageModel::fill()
|
||||||
|
{
|
||||||
|
if (!m_room) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto events = m_room->pinnedEventIds();
|
||||||
|
|
||||||
|
for (const auto &event : std::as_const(events)) {
|
||||||
|
auto job = m_room->connection()->callApi<GetOneRoomEventJob>(m_room->id(), event);
|
||||||
|
connect(job, &BaseJob::success, this, [this, job] {
|
||||||
|
beginInsertRows({}, m_pinnedEvents.size(), m_pinnedEvents.size());
|
||||||
|
m_pinnedEvents.push_back(std::move(fromJson<event_ptr_tt<RoomEvent>>(job->jsonData())));
|
||||||
|
Q_EMIT newEventAdded(m_pinnedEvents.back().get(), false);
|
||||||
|
endInsertRows();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_pinnedmessagemodel.cpp"
|
||||||
62
src/models/pinnedmessagemodel.h
Normal file
62
src/models/pinnedmessagemodel.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <Quotient/csapi/rooms.h>
|
||||||
|
|
||||||
|
#include "messagemodel.h"
|
||||||
|
#include "neochatroommember.h"
|
||||||
|
|
||||||
|
namespace Quotient
|
||||||
|
{
|
||||||
|
class Connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
class NeoChatRoom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PinnedMessageModel
|
||||||
|
*
|
||||||
|
* This class defines the model for visualising a room's pinned messages.
|
||||||
|
*/
|
||||||
|
class PinnedMessageModel : public MessageModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether the model is currently loading.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PinnedMessageModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of rows in the model.
|
||||||
|
*
|
||||||
|
* @sa QAbstractItemModel::rowCount
|
||||||
|
*/
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
bool loading() const;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void loadingChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::optional<std::reference_wrapper<const Quotient::RoomEvent>> getEventForIndex(QModelIndex index) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setLoading(bool loading);
|
||||||
|
void fill();
|
||||||
|
|
||||||
|
bool m_loading = false;
|
||||||
|
|
||||||
|
std::vector<Quotient::event_ptr_tt<Quotient::RoomEvent>> m_pinnedEvents;
|
||||||
|
};
|
||||||
@@ -130,6 +130,24 @@ QQC2.ScrollView {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Delegates.RoundedItemDelegate {
|
||||||
|
id: pinnedMessagesButton
|
||||||
|
visible: !root.room.isSpace
|
||||||
|
icon.name: "pin-symbolic"
|
||||||
|
text: i18nc("@action:button", "Pinned messages")
|
||||||
|
activeFocusOnTab: true
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomPinnedMessagesPage'), {
|
||||||
|
room: root.room
|
||||||
|
}, {
|
||||||
|
title: i18nc("@title", "Pinned Messages")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Delegates.RoundedItemDelegate {
|
Delegates.RoundedItemDelegate {
|
||||||
id: leaveButton
|
id: leaveButton
|
||||||
icon.name: "arrow-left-symbolic"
|
icon.name: "arrow-left-symbolic"
|
||||||
|
|||||||
64
src/qml/RoomPinnedMessagesPage.qml
Normal file
64
src/qml/RoomPinnedMessagesPage.qml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
|
import org.kde.neochat
|
||||||
|
import org.kde.neochat.timeline
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Component for showing the pinned messages in a room.
|
||||||
|
*/
|
||||||
|
Kirigami.ScrollablePage {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The room to show the pinned messages for.
|
||||||
|
*/
|
||||||
|
required property NeoChatRoom room
|
||||||
|
|
||||||
|
title: i18nc("@title", "Pinned Messages")
|
||||||
|
|
||||||
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||||
|
Kirigami.Theme.inherit: false
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: listView
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
model: PinnedMessageModel {
|
||||||
|
id: pinModel
|
||||||
|
room: root.room
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: EventDelegate {
|
||||||
|
room: root.room
|
||||||
|
}
|
||||||
|
|
||||||
|
section.property: "section"
|
||||||
|
|
||||||
|
Kirigami.PlaceholderMessage {
|
||||||
|
icon.name: "pin-symbolic"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: i18nc("@info:placeholder", "No Pinned Messages")
|
||||||
|
visible: listView.count === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.LoadingPlaceholder {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
visible: listView.count === 0 && pinModel.loading
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onUpPressed: {
|
||||||
|
if (listView.currentIndex > 0) {
|
||||||
|
listView.decrementCurrentIndex();
|
||||||
|
} else {
|
||||||
|
listView.currentIndex = -1; // This is so the list view doesn't appear to have two selected items
|
||||||
|
listView.headerItem.forceActiveFocus(Qt.TabFocusReason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user