Display edits correctly

This commit is contained in:
Nicolas Werner 2021-01-31 22:41:43 +01:00
parent faeaf9dc6b
commit 00fd4eecec
8 changed files with 99 additions and 12 deletions

View file

@ -356,7 +356,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare(
MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG 70fa15de3ec84cf0c0ab6250f2e5e62f34a6d05b
GIT_TAG 31e300546eb63ea25b0b879fb255beee6022da03
)
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")

View file

@ -220,7 +220,7 @@
"name": "mtxclient",
"sources": [
{
"commit": "70fa15de3ec84cf0c0ab6250f2e5e62f34a6d05b",
"commit": "31e300546eb63ea25b0b879fb255beee6022da03",
"type": "git",
"url": "https://github.com/Nheko-Reborn/mtxclient.git"
}

View file

@ -85,6 +85,20 @@ Item {
width: 16
}
ImageButton {
id: editButton
visible: (Settings.buttonsInTimeline && model.isEditable) || model.isEdited
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.preferredHeight: 16
width: 16
hoverEnabled: true
image: ":/icons/icons/ui/edit.png"
ToolTip.visible: hovered
ToolTip.text: model.isEditable ? qsTr("Edit") : qsTr("Edited")
onClicked: if (model.isEditable) chat.model.editAction(model.id)
}
EmojiButton {
id: reactButton

View file

@ -34,6 +34,20 @@ struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
template<template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
struct IsStateEvent
{
template<class T>
bool operator()(const mtx::events::StateEvent<T> &)
{
return true;
}
template<class T>
bool operator()(const mtx::events::Event<T> &)
{
return false;
}
};
struct EventMsgType
{
template<class E>
@ -476,3 +490,9 @@ mtx::accessors::serialize_event(const mtx::events::collections::TimelineEvents &
{
return std::visit([](const auto &e) { return nlohmann::json(e); }, event);
}
bool
mtx::accessors::is_state_event(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(IsStateEvent{}, event);
}

View file

@ -17,6 +17,9 @@ room_id(const mtx::events::collections::TimelineEvents &event);
std::string
sender(const mtx::events::collections::TimelineEvents &event);
bool
is_state_event(const mtx::events::collections::TimelineEvents &event);
QDateTime
origin_server_ts(const mtx::events::collections::TimelineEvents &event);

View file

@ -774,15 +774,17 @@ EventStore::get(std::string_view id, std::string_view related_to, bool decrypt,
if (id.empty())
return nullptr;
std::string id_ = std::string(id);
IdIndex index{room_id_, std::string(id)};
if (resolve_edits) {
auto edits_ = edits(id_);
if (!edits_.empty())
id_ = mtx::accessors::event_id(edits_.back());
auto edits_ = edits(index.id);
if (!edits_.empty()) {
index.id = mtx::accessors::event_id(edits_.back());
auto event_ptr =
new mtx::events::collections::TimelineEvents(std::move(edits_.back()));
events_by_id_.insert(index, event_ptr);
}
}
IdIndex index{room_id_, id_};
auto event_ptr = events_by_id_.object(index);
if (!event_ptr) {
auto event = cache::client()->getEvent(room_id_, index.id);

View file

@ -288,6 +288,8 @@ TimelineModel::roleNames() const
{ProportionalHeight, "proportionalHeight"},
{Id, "id"},
{State, "state"},
{IsEdited, "isEdited"},
{IsEditable, "isEditable"},
{IsEncrypted, "isEncrypted"},
{IsRoomEncrypted, "isRoomEncrypted"},
{ReplyTo, "replyTo"},
@ -409,8 +411,12 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
return QVariant(prop > 0 ? prop : 1.);
}
case Id:
return QVariant(QString::fromStdString(event_id(event)));
case Id: {
if (auto replaces = relations(event).replaces())
return QVariant(QString::fromStdString(replaces.value()));
else
return QVariant(QString::fromStdString(event_id(event)));
}
case State: {
auto id = QString::fromStdString(event_id(event));
auto containsOthers = [](const auto &vec) {
@ -430,6 +436,11 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
else
return qml_mtx_events::Received;
}
case IsEdited:
return QVariant(relations(event).replaces().has_value());
case IsEditable:
return QVariant(!is_state_event(event) && mtx::accessors::sender(event) ==
http::client()->user_id().to_string());
case IsEncrypted: {
auto id = event_id(event);
auto encrypted_event = events.get(id, id, false);
@ -444,7 +455,7 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
case ReplyTo:
return QVariant(QString::fromStdString(relations(event).reply_to().value_or("")));
case Reactions: {
auto id = event_id(event);
auto id = relations(event).replaces().value_or(event_id(event));
return QVariant::fromValue(events.reactions(id));
}
case RoomId:
@ -813,6 +824,12 @@ TimelineModel::replyAction(QString id)
setReply(id);
}
void
TimelineModel::editAction(QString id)
{
setEdit(id);
}
RelatedInfo
TimelineModel::relatedInfo(QString id)
{
@ -1501,6 +1518,22 @@ TimelineModel::formatMemberEvent(QString id)
return rendered;
}
void
TimelineModel::setEdit(QString newEdit)
{
if (edit_ != newEdit) {
edit_ = newEdit;
emit editChanged(edit_);
auto ev = events.get(newEdit.toStdString(), "");
if (ev) {
setReply(QString::fromStdString(
mtx::accessors::relations(*ev).reply_to().value_or("")));
// input()->setText(mtx::accessors::body(*ev));
}
}
}
QString
TimelineModel::roomName() const
{

View file

@ -145,6 +145,7 @@ class TimelineModel : public QAbstractListModel
Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY
typingUsersChanged)
Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply)
Q_PROPERTY(QString edit READ edit WRITE setEdit NOTIFY editChanged RESET resetEdit)
Q_PROPERTY(
bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged)
Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
@ -181,6 +182,8 @@ public:
ProportionalHeight,
Id,
State,
IsEdited,
IsEditable,
IsEncrypted,
IsRoomEncrypted,
ReplyTo,
@ -213,6 +216,7 @@ public:
Q_INVOKABLE void viewRawMessage(QString id) const;
Q_INVOKABLE void viewDecryptedRawMessage(QString id) const;
Q_INVOKABLE void openUserProfile(QString userid, bool global = false);
Q_INVOKABLE void editAction(QString id);
Q_INVOKABLE void replyAction(QString id);
Q_INVOKABLE void readReceiptsAction(QString id) const;
Q_INVOKABLE void redactEvent(QString id);
@ -268,6 +272,16 @@ public slots:
emit replyChanged(reply_);
}
}
QString edit() const { return edit_; }
void setEdit(QString newEdit);
void resetEdit()
{
if (!edit_.isEmpty()) {
edit_ = "";
emit editChanged(edit_);
resetReply();
}
}
void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; }
void clearTimeline() { events.clearTimeline(); }
void receivedSessionKey(const std::string &session_key)
@ -292,6 +306,7 @@ signals:
void newEncryptedImage(mtx::crypto::EncryptedFile encryptionInfo);
void typingUsersChanged(std::vector<QString> users);
void replyChanged(QString reply);
void editChanged(QString reply);
void paginationInProgressChanged(const bool);
void newCallEvent(const mtx::events::collections::TimelineEvents &event);
@ -322,7 +337,7 @@ private:
bool m_paginationInProgress = false;
QString currentId;
QString reply_;
QString reply_, edit_;
std::vector<QString> typingUsers_;
TimelineViewManager *manager_;