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/messagecontentfiltermodel.cpp
|
||||
models/messagecontentfiltermodel.h
|
||||
models/pinnedmessagemodel.cpp
|
||||
models/pinnedmessagemodel.h
|
||||
)
|
||||
|
||||
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/ConfirmEncryptionDialog.qml
|
||||
qml/RoomSearchPage.qml
|
||||
qml/RoomPinnedMessagesPage.qml
|
||||
qml/LocationChooser.qml
|
||||
qml/TimelineView.qml
|
||||
qml/InvitationView.qml
|
||||
@@ -534,6 +537,7 @@ if(ANDROID)
|
||||
"list-remove-symbolic"
|
||||
"edit-delete"
|
||||
"user-home-symbolic"
|
||||
"pin-symbolic"
|
||||
)
|
||||
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
id: leaveButton
|
||||
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