diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index bab1d932..f0f73ec9 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -1,7 +1,9 @@ -import QtQuick 2.5 +import QtQuick 2.6 import QtQuick.Controls 2.5 import QtQuick.Layouts 1.5 +import com.github.nheko 1.0 + Rectangle { anchors.fill: parent @@ -26,20 +28,43 @@ Rectangle { } model: timelineManager.timeline + spacing: 4 delegate: RowLayout { anchors.leftMargin: 52 anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: scrollbar.width - Text { + Loader { + id: loader Layout.fillWidth: true - height: contentHeight - text: "Event content" + height: item.height + Layout.alignment: Qt.AlignTop + + source: switch(model.type) { + case MtxEvent.Aliases: return "delegates/Aliases.qml" + case MtxEvent.Avatar: return "delegates/Avatar.qml" + case MtxEvent.CanonicalAlias: return "delegates/CanonicalAlias.qml" + case MtxEvent.Create: return "delegates/Create.qml" + case MtxEvent.GuestAccess: return "delegates/GuestAccess.qml" + case MtxEvent.HistoryVisibility: return "delegates/HistoryVisibility.qml" + case MtxEvent.JoinRules: return "delegates/JoinRules.qml" + case MtxEvent.Member: return "delegates/Member.qml" + case MtxEvent.Name: return "delegates/Name.qml" + case MtxEvent.PowerLevels: return "delegates/PowerLevels.qml" + case MtxEvent.Topic: return "delegates/Topic.qml" + case MtxEvent.NoticeMessage: return "delegates/NoticeMessage.qml" + case MtxEvent.TextMessage: return "delegates/TextMessage.qml" + case MtxEvent.ImageMessage: return "delegates/ImageMessage.qml" + case MtxEvent.VideoMessage: return "delegates/VideoMessage.qml" + default: return "delegates/placeholder.qml" + } + property variant eventData: model } + Button { - Layout.alignment: Qt.AlignRight + Layout.alignment: Qt.AlignRight | Qt.AlignTop id: replyButton flat: true height: replyButtonImg.contentHeight @@ -54,7 +79,7 @@ Rectangle { } } Button { - Layout.alignment: Qt.AlignRight + Layout.alignment: Qt.AlignRight | Qt.AlignTop id: optionsButton flat: true height: optionsButtonImg.contentHeight @@ -90,7 +115,7 @@ Rectangle { } Text { - Layout.alignment: Qt.AlignRight + Layout.alignment: Qt.AlignRight | Qt.AlignTop text: model.timestamp.toLocaleTimeString("HH:mm") } } @@ -98,13 +123,18 @@ Rectangle { section { property: "section" delegate: Column { + topPadding: 4 + bottomPadding: 4 + spacing: 8 + width: parent.width - height: dateBubble.visible ? dateBubble.height + userName.height : userName.height + Label { id: dateBubble anchors.horizontalCenter: parent.horizontalCenter visible: section.includes(" ") text: chat.model.formatDateSeparator(new Date(Number(section.split(" ")[1]))) + height: contentHeight * 1.2 width: contentWidth * 1.2 horizontalAlignment: Text.AlignHCenter @@ -114,6 +144,7 @@ Rectangle { } } Row { + height: userName.height spacing: 4 Rectangle { width: 48 diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml new file mode 100644 index 00000000..5f4b33fa --- /dev/null +++ b/resources/qml/delegates/TextMessage.qml @@ -0,0 +1,10 @@ +import QtQuick 2.5 + +TextEdit { + text: eventData.formattedBody + textFormat: TextEdit.RichText + readOnly: true + wrapMode: Text.Wrap + width: parent.width + selectByMouse: true +} diff --git a/resources/res.qrc b/resources/res.qrc index 65770c8c..b2f27814 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -116,5 +116,6 @@ qml/TimelineView.qml + qml/delegates/TextMessage.qml diff --git a/src/timeline2/TimelineModel.cpp b/src/timeline2/TimelineModel.cpp index 6f212833..112b2752 100644 --- a/src/timeline2/TimelineModel.cpp +++ b/src/timeline2/TimelineModel.cpp @@ -1,5 +1,7 @@ #include "TimelineModel.h" +#include + #include #include "Logging.h" @@ -31,6 +33,119 @@ eventTimestamp(const T &event) { return QDateTime::fromMSecsSinceEpoch(event.origin_server_ts); } + +template +QString +eventFormattedBody(const mtx::events::Event &) +{ + return QString(""); +} +template +auto +eventFormattedBody(const mtx::events::RoomEvent &e) + -> std::enable_if_t::value, QString> +{ + auto temp = e.content.formatted_body; + if (!temp.empty()) { + auto pos = temp.find(""); + if (pos != std::string::npos) + temp.erase(pos, std::string("").size()); + pos = temp.find(""); + if (pos != std::string::npos) + temp.erase(pos, std::string("").size()); + return QString::fromStdString(temp); + } else + return QString::fromStdString(e.content.body); +} + +template +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &e) +{ + using mtx::events::EventType; + switch (e.type) { + case EventType::RoomKeyRequest: + return qml_mtx_events::EventType::KeyRequest; + case EventType::RoomAliases: + return qml_mtx_events::EventType::Aliases; + case EventType::RoomAvatar: + return qml_mtx_events::EventType::Avatar; + case EventType::RoomCanonicalAlias: + return qml_mtx_events::EventType::CanonicalAlias; + case EventType::RoomCreate: + return qml_mtx_events::EventType::Create; + case EventType::RoomEncrypted: + return qml_mtx_events::EventType::Encrypted; + case EventType::RoomEncryption: + return qml_mtx_events::EventType::Encryption; + case EventType::RoomGuestAccess: + return qml_mtx_events::EventType::GuestAccess; + case EventType::RoomHistoryVisibility: + return qml_mtx_events::EventType::HistoryVisibility; + case EventType::RoomJoinRules: + return qml_mtx_events::EventType::JoinRules; + case EventType::RoomMember: + return qml_mtx_events::EventType::Member; + case EventType::RoomMessage: + return qml_mtx_events::EventType::UnknownMessage; + case EventType::RoomName: + return qml_mtx_events::EventType::Name; + case EventType::RoomPowerLevels: + return qml_mtx_events::EventType::PowerLevels; + case EventType::RoomTopic: + return qml_mtx_events::EventType::Topic; + case EventType::RoomTombstone: + return qml_mtx_events::EventType::Tombstone; + case EventType::RoomRedaction: + return qml_mtx_events::EventType::Redaction; + case EventType::RoomPinnedEvents: + return qml_mtx_events::EventType::PinnedEvents; + case EventType::Sticker: + return qml_mtx_events::EventType::Sticker; + case EventType::Tag: + return qml_mtx_events::EventType::Tag; + case EventType::Unsupported: + default: + return qml_mtx_events::EventType::Unsupported; + } +} +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &) +{ + return qml_mtx_events::EventType::AudioMessage; +} +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &) +{ + return qml_mtx_events::EventType::EmoteMessage; +} +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &) +{ + return qml_mtx_events::EventType::FileMessage; +} +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &) +{ + return qml_mtx_events::EventType::ImageMessage; +} +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &) +{ + return qml_mtx_events::EventType::NoticeMessage; +} +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &) +{ + return qml_mtx_events::EventType::TextMessage; +} +qml_mtx_events::EventType +toRoomEventType(const mtx::events::Event &) +{ + return qml_mtx_events::EventType::VideoMessage; +} +// ::EventType::Type toRoomEventType(const Event &e) { return +// ::EventType::LocationMessage; } } TimelineModel::TimelineModel(QString room_id, QObject *parent) @@ -105,6 +220,14 @@ TimelineModel::data(const QModelIndex &index, int role) const case Timestamp: return QVariant(boost::apply_visitor( [](const auto &e) -> QDateTime { return eventTimestamp(e); }, events.value(id))); + case Type: + return QVariant(boost::apply_visitor( + [](const auto &e) -> qml_mtx_events::EventType { return toRoomEventType(e); }, + events.value(id))); + case FormattedBody: + return QVariant(utils::replaceEmoji(boost::apply_visitor( + [](const auto &e) -> QString { return eventFormattedBody(e); }, + events.value(id)))); default: return QVariant(); } diff --git a/src/timeline2/TimelineModel.h b/src/timeline2/TimelineModel.h index e2c7b73a..3af94643 100644 --- a/src/timeline2/TimelineModel.h +++ b/src/timeline2/TimelineModel.h @@ -7,6 +7,65 @@ #include +namespace qml_mtx_events { +Q_NAMESPACE + +enum EventType +{ + // Unsupported event + Unsupported, + /// m.room_key_request + KeyRequest, + /// m.room.aliases + Aliases, + /// m.room.avatar + Avatar, + /// m.room.canonical_alias + CanonicalAlias, + /// m.room.create + Create, + /// m.room.encrypted. + Encrypted, + /// m.room.encryption. + Encryption, + /// m.room.guest_access + GuestAccess, + /// m.room.history_visibility + HistoryVisibility, + /// m.room.join_rules + JoinRules, + /// m.room.member + Member, + /// m.room.name + Name, + /// m.room.power_levels + PowerLevels, + /// m.room.tombstone + Tombstone, + /// m.room.topic + Topic, + /// m.room.redaction + Redaction, + /// m.room.pinned_events + PinnedEvents, + // m.sticker + Sticker, + // m.tag + Tag, + /// m.room.message + AudioMessage, + EmoteMessage, + FileMessage, + ImageMessage, + LocationMessage, + NoticeMessage, + TextMessage, + VideoMessage, + UnknownMessage, +}; +Q_ENUM_NS(EventType) +} + class TimelineModel : public QAbstractListModel { Q_OBJECT @@ -26,8 +85,8 @@ public: }; QHash roleNames() const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; Q_INVOKABLE QColor userColor(QString id, QColor background); Q_INVOKABLE QString displayName(QString id) const; @@ -40,6 +99,7 @@ public slots: private slots: // Add old events at the top of the timeline. + void addBackwardsEvents(const mtx::responses::Messages &msgs); signals: @@ -57,4 +117,4 @@ private: QHash userColors; }; - + diff --git a/src/timeline2/TimelineViewManager.cpp b/src/timeline2/TimelineViewManager.cpp index 32321fd2..df9a2270 100644 --- a/src/timeline2/TimelineViewManager.cpp +++ b/src/timeline2/TimelineViewManager.cpp @@ -7,6 +7,13 @@ TimelineViewManager::TimelineViewManager(QWidget *parent) { + qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject, + "com.github.nheko", + 1, + 0, + "MtxEvent", + "Can't instantiate enum!"); + view = new QQuickView(); container = QWidget::createWindowContainer(view, parent); container->setMinimumSize(200, 200);