diff --git a/src/app/qml/RoomPage.qml b/src/app/qml/RoomPage.qml index 76dfa47bb..883e6df21 100644 --- a/src/app/qml/RoomPage.qml +++ b/src/app/qml/RoomPage.qml @@ -7,6 +7,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Controls as QQC2 import QtQuick.Window +import QtQuick.Layouts import org.kde.kirigami as Kirigami @@ -98,24 +99,87 @@ Kirigami.Page { } } - header: Kirigami.InlineMessage { - id: banner + header: ColumnLayout { + id: headerLayout - // Used to keep track of messages so we can hide the right one at the right time - property string messageId + spacing: 0 - showCloseButton: true - visible: false - position: Kirigami.InlineMessage.Position.Header + readonly property bool shouldShowPins: root.currentRoom.pinnedMessage.length > 0 && !Kirigami.Settings.isMobile - function show(msgid: string): void { - messageId = msgid; - visible = true; + QQC2.Control { + id: pinControl + + visible: headerLayout.shouldShowPins + + Layout.fillWidth: true + + background: Rectangle { + color: Kirigami.Theme.backgroundColor + + Kirigami.Theme.colorSet: Kirigami.Theme.View + Kirigami.Theme.inherit: false + } + + contentItem: RowLayout { + spacing: Kirigami.Units.smallSpacing + + Kirigami.Icon { + source: "pin-symbolic" + + Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium + Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium + } + + QQC2.Label { + text: root.currentRoom.pinnedMessage + maximumLineCount: 1 + elide: Text.ElideRight + + onLinkActivated: link => UrlHelper.openUrl(link) + onHoveredLinkChanged: if (hoveredLink.length > 0 && hoveredLink !== "1") { + (QQC2.ApplicationWindow.window as Main).hoverLinkIndicator.text = hoveredLink; + } else { + (QQC2.ApplicationWindow.window as Main).hoverLinkIndicator.text = ""; + } + + Layout.fillWidth: true + } + } + + TapHandler { + onTapped: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomPinnedMessagesPage'), { + room: root.currentRoom + }, { + title: i18nc("@title", "Pinned Messages") + }); + } } - function hideIf(msgid: string): void { - if (messageId == msgid) { - visible = false; + Kirigami.Separator { + visible: headerLayout.shouldShowPins + + Layout.fillWidth: true + } + + Kirigami.InlineMessage { + id: banner + + // Used to keep track of messages so we can hide the right one at the right time + property string messageId + + showCloseButton: true + visible: false + position: Kirigami.InlineMessage.Position.Header + + function show(msgid: string): void { + messageId = msgid; + visible = true; + } + + function hideIf(msgid: string): void { + if (messageId == msgid) { + visible = false; + } } } } diff --git a/src/libneochat/neochatroom.cpp b/src/libneochat/neochatroom.cpp index 11841c1a9..9f36f81f2 100644 --- a/src/libneochat/neochatroom.cpp +++ b/src/libneochat/neochatroom.cpp @@ -44,6 +44,7 @@ #include "chatbarcache.h" #include "clipboard.h" +#include "eventhandler.h" #include "events/pollevent.h" #include "filetransferpseudojob.h" #include "neochatconnection.h" @@ -55,6 +56,7 @@ #include #include #endif + #include #include @@ -130,11 +132,13 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS this, [this]() { updatePushNotificationState(u"m.push_rules"_s); + loadPinnedMessage(); Q_EMIT canEncryptRoomChanged(); Q_EMIT inviteTimestampChanged(); }, Qt::SingleShotConnection); + connect(this, &Room::pinnedEventsChanged, this, &NeoChatRoom::loadPinnedMessage); connect(this, &Room::changed, this, [this] { Q_EMIT canEncryptRoomChanged(); Q_EMIT parentIdsChanged(); @@ -1170,6 +1174,19 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state) Q_EMIT pushNotificationStateChanged(m_currentPushNotificationState); } +void NeoChatRoom::loadPinnedMessage() +{ + const auto events = pinnedEventIds(); + if (!events.isEmpty()) { + const QString &mostRecentEventId = events.last(); + connection()->callApi(id(), mostRecentEventId).then([this](const auto &job) { + auto event = fromJson>(job->jsonData()); + m_pinnedMessage = EventHandler::richBody(this, event.get()); + Q_EMIT pinnedMessageChanged(); + }); + } +} + void NeoChatRoom::updatePushNotificationState(QString type) { if (type != "m.push_rules"_L1 || m_pushNotificationStateUpdating) { @@ -1810,4 +1827,9 @@ bool NeoChatRoom::isCreator(const QString &userId) const && (createEvent->senderId() == userId || createEvent->contentPart(u"additional_creators"_s).contains(userId)); } +QString NeoChatRoom::pinnedMessage() const +{ + return m_pinnedMessage; +} + #include "moc_neochatroom.cpp" diff --git a/src/libneochat/neochatroom.h b/src/libneochat/neochatroom.h index a69e9dfae..56ec51a0b 100644 --- a/src/libneochat/neochatroom.h +++ b/src/libneochat/neochatroom.h @@ -203,6 +203,11 @@ class NeoChatRoom : public Quotient::Room */ Q_PROPERTY(QString invitingUserId READ invitingUserId NOTIFY baseStateLoaded) + /** + * @brief The most recently pinned message in the room. + */ + Q_PROPERTY(QString pinnedMessage READ pinnedMessage NOTIFY pinnedMessageChanged) + public: explicit NeoChatRoom(Quotient::Connection *connection, QString roomId, Quotient::JoinState joinState = {}); @@ -612,6 +617,11 @@ public: */ bool isCreator(const QString &userId) const; + /** + * @return The most recent pinned message in the room. + */ + QString pinnedMessage() const; + private: bool m_visible = false; @@ -644,6 +654,8 @@ private: std::unordered_map> m_memberObjects; static std::function m_hiddenFilter; + QString m_pinnedMessage; + void loadPinnedMessage(); private Q_SLOTS: void updatePushNotificationState(QString type); @@ -674,6 +686,7 @@ Q_SIGNALS: void extraEventLoaded(const QString &eventId); void extraEventNotFound(const QString &eventId); void inviteTimestampChanged(); + void pinnedMessageChanged(); /** * @brief Request a message be shown to the user of the given type.