diff --git a/.gitignore b/.gitignore index 23b84039..0f61a911 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,9 @@ ui_*.h *.qmlproject.user *.qmlproject.user.* +# Vim +*.swp + #####=== CMake ===##### CMakeCache.txt diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 3d4c1147..7ff51362 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -1,4 +1,6 @@ -import QtQuick 2.1 +import QtQuick 2.5 +import QtQuick.Controls 2.5 +import QtQuick.Layouts 1.5 Rectangle { anchors.fill: parent @@ -17,9 +19,89 @@ Rectangle { id: chat model: timelineManager.timeline - delegate: Text { - height: contentHeight - text: model.userId + delegate: RowLayout { + width: chat.width + Text { + Layout.fillWidth: true + height: contentHeight + text: model.userName + } + + Button { + Layout.alignment: Qt.AlignRight + id: replyButton + flat: true + height: replyButtonImg.contentHeight + width: replyButtonImg.contentWidth + ToolTip.visible: hovered + ToolTip.text: qsTr("Reply") + Image { + id: replyButtonImg + // Workaround, can't get icon.source working for now... + anchors.fill: parent + source: "qrc:/icons/icons/ui/mail-reply.png" + } + } + Button { + Layout.alignment: Qt.AlignRight + id: optionsButton + flat: true + height: optionsButtonImg.contentHeight + width: optionsButtonImg.contentWidth + ToolTip.visible: hovered + ToolTip.text: qsTr("Options") + Image { + id: optionsButtonImg + // Workaround, can't get icon.source working for now... + anchors.fill: parent + source: "qrc:/icons/icons/ui/vertical-ellipsis.png" + } + + onClicked: contextMenu.open() + + Menu { + y: optionsButton.height + id: contextMenu + + MenuItem { + text: "Read receipts" + } + MenuItem { + text: "Mark as read" + } + MenuItem { + text: "View raw message" + } + MenuItem { + text: "Redact message" + } + } + } + + Text { + Layout.alignment: Qt.AlignRight + text: model.timestamp.toLocaleTimeString("HH:mm") + } + } + + section { + property: "section" + delegate: Column { + width: parent.width + Label { + anchors.horizontalCenter: parent.horizontalCenter + visible: section.includes(" ") + text: Qt.formatDate(new Date(Number(section.split(" ")[1]))) + height: contentHeight * 1.2 + width: contentWidth * 1.2 + horizontalAlignment: Text.AlignHCenter + background: Rectangle { + radius: parent.height / 2 + color: "black" + } + } + Text { text: section.split(" ")[0] } + } } } } diff --git a/src/timeline/.TimelineItem.cpp.swp b/src/timeline/.TimelineItem.cpp.swp deleted file mode 100644 index 75e03aeb..00000000 Binary files a/src/timeline/.TimelineItem.cpp.swp and /dev/null differ diff --git a/src/timeline2/TimelineModel.cpp b/src/timeline2/TimelineModel.cpp index 10a5d3bf..8a74edaf 100644 --- a/src/timeline2/TimelineModel.cpp +++ b/src/timeline2/TimelineModel.cpp @@ -22,6 +22,13 @@ senderId(const T &event) { return QString::fromStdString(event.sender); } + +template +QDateTime +eventTimestamp(const T &event) +{ + return QDateTime::fromMSecsSinceEpoch(event.origin_server_ts); +} } TimelineModel::TimelineModel(QString room_id, QObject *parent) @@ -36,6 +43,7 @@ QHash TimelineModel::roleNames() const { return { + {Section, "section"}, {Type, "type"}, {Body, "body"}, {FormattedBody, "formattedBody"}, @@ -55,16 +63,49 @@ TimelineModel::rowCount(const QModelIndex &parent) const QVariant TimelineModel::data(const QModelIndex &index, int role) const { - nhlog::ui()->info("data"); if (index.row() < 0 && index.row() >= (int)eventOrder.size()) return QVariant(); QString id = eventOrder[index.row()]; switch (role) { + case Section: { + QDateTime date = boost::apply_visitor( + [](const auto &e) -> QDateTime { return eventTimestamp(e); }, events.value(id)); + date.setTime(QTime()); + + QString userId = boost::apply_visitor( + [](const auto &e) -> QString { return senderId(e); }, events.value(id)); + + for (int r = index.row() - 1; r > 0; r--) { + QDateTime prevDate = boost::apply_visitor( + [](const auto &e) -> QDateTime { return eventTimestamp(e); }, + events.value(eventOrder[r])); + prevDate.setTime(QTime()); + if (prevDate != date) + return QString("%2 %1").arg(date.toMSecsSinceEpoch()).arg(userId); + + QString prevUserId = + boost::apply_visitor([](const auto &e) -> QString { return senderId(e); }, + events.value(eventOrder[r])); + if (userId != prevUserId) + break; + } + + return QString("%1").arg(userId); + } case UserId: return QVariant(boost::apply_visitor( [](const auto &e) -> QString { return senderId(e); }, events.value(id))); + case UserName: + return QVariant(Cache::displayName( + room_id_, + boost::apply_visitor([](const auto &e) -> QString { return senderId(e); }, + events.value(id)))); + + case Timestamp: + return QVariant(boost::apply_visitor( + [](const auto &e) -> QDateTime { return eventTimestamp(e); }, events.value(id))); default: return QVariant(); } diff --git a/src/timeline2/TimelineModel.h b/src/timeline2/TimelineModel.h index a4224538..41a25f61 100644 --- a/src/timeline2/TimelineModel.h +++ b/src/timeline2/TimelineModel.h @@ -15,6 +15,7 @@ public: enum Roles { + Section, Type, Body, FormattedBody, diff --git a/src/timeline2/TimelineViewManager.h b/src/timeline2/TimelineViewManager.h index 7f760eac..ff976aad 100644 --- a/src/timeline2/TimelineViewManager.h +++ b/src/timeline2/TimelineViewManager.h @@ -34,7 +34,6 @@ public: Q_INVOKABLE TimelineModel *activeTimeline() const { - nhlog::ui()->info("aaaa"); return timeline_; }