summary refs log tree commit diff
path: root/src/timeline
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-04-24 14:35:21 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2021-04-24 14:35:21 +0200
commit8236f6ba72f677d3572be1eab7d5f71c0150fbf9 (patch)
tree1f29d71130b640b47dfe4b160ea4ef2801042698 /src/timeline
parentFix rendering issues with ) in links (diff)
parentfix macos build error (diff)
downloadnheko-8236f6ba72f677d3572be1eab7d5f71c0150fbf9.tar.xz
Merge branch 'forward_message_feature' of https://github.com/Jedi18/nheko into Jedi18-forward_message_feature
Diffstat (limited to 'src/timeline')
-rw-r--r--src/timeline/TimelineModel.cpp10
-rw-r--r--src/timeline/TimelineModel.h2
-rw-r--r--src/timeline/TimelineViewManager.cpp83
-rw-r--r--src/timeline/TimelineViewManager.h49
4 files changed, 142 insertions, 2 deletions
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index bfd95b0d..30ce176e 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -827,6 +827,16 @@ TimelineModel::viewRawMessage(QString id) const
 }
 
 void
+TimelineModel::forwardMessage(QString eventId, QString roomId)
+{
+        auto e = events.get(eventId.toStdString(), "");
+        if (!e)
+                return;
+
+        emit forwardToRoom(e, roomId);
+}
+
+void
 TimelineModel::viewDecryptedRawMessage(QString id) const
 {
         auto e = events.get(id.toStdString(), "");
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 06da95c6..fbe963d2 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -219,6 +219,7 @@ public:
         Q_INVOKABLE QString formatPowerLevelEvent(QString id);
 
         Q_INVOKABLE void viewRawMessage(QString id) const;
+        Q_INVOKABLE void forwardMessage(QString eventId, QString roomId);
         Q_INVOKABLE void viewDecryptedRawMessage(QString id) const;
         Q_INVOKABLE void openUserProfile(QString userid, bool global = false);
         Q_INVOKABLE void openRoomSettings();
@@ -322,6 +323,7 @@ signals:
         void roomNameChanged();
         void roomTopicChanged();
         void roomAvatarUrlChanged();
+        void forwardToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
 
 private:
         template<typename T>
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index e9986c7e..518ccaf1 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -31,8 +31,6 @@
 #include "ui/NhekoCursorShape.h"
 #include "ui/NhekoDropArea.h"
 
-#include <iostream> //only for debugging
-
 Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
 Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
 
@@ -329,6 +327,10 @@ TimelineViewManager::addRoom(const QString &room_id)
                         &TimelineModel::newEncryptedImage,
                         imgProvider,
                         &MxcImageProvider::addEncryptionInfo);
+                connect(newRoom.data(),
+                        &TimelineModel::forwardToRoom,
+                        this,
+                        &TimelineViewManager::forwardMessageToRoom);
                 models.insert(room_id, std::move(newRoom));
         }
 }
@@ -616,3 +618,80 @@ TimelineViewManager::focusTimeline()
 {
         getWidget()->setFocus();
 }
+
+void
+TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEvents *e,
+                                          QString roomId)
+{
+        auto room                                                = models.find(roomId);
+        auto content                                             = mtx::accessors::url(*e);
+        std::optional<mtx::crypto::EncryptedFile> encryptionInfo = mtx::accessors::file(*e);
+
+        if (encryptionInfo) {
+                http::client()->download(
+                  content,
+                  [this, roomId, e, encryptionInfo](const std::string &res,
+                                                    const std::string &content_type,
+                                                    const std::string &originalFilename,
+                                                    mtx::http::RequestErr err) {
+                          if (err)
+                                  return;
+
+                          auto data = mtx::crypto::to_string(
+                            mtx::crypto::decrypt_file(res, encryptionInfo.value()));
+
+                          http::client()->upload(
+                            data,
+                            content_type,
+                            originalFilename,
+                            [this, roomId, e](const mtx::responses::ContentURI &res,
+                                              mtx::http::RequestErr err) mutable {
+                                    if (err) {
+                                            nhlog::net()->warn("failed to upload media: {} {} ({})",
+                                                               err->matrix_error.error,
+                                                               to_string(err->matrix_error.errcode),
+                                                               static_cast<int>(err->status_code));
+                                            return;
+                                    }
+
+                                    std::visit(
+                                      [this, roomId, url = res.content_uri](auto ev) {
+                                              if constexpr (mtx::events::message_content_to_type<
+                                                              decltype(ev.content)> ==
+                                                            mtx::events::EventType::RoomMessage) {
+                                                      if constexpr (messageWithFileAndUrl(ev)) {
+                                                              ev.content.relations.relations
+                                                                .clear();
+                                                              ev.content.file.reset();
+                                                              ev.content.url = url;
+                                                      }
+
+                                                      auto room = models.find(roomId);
+                                                      removeReplyFallback(ev);
+                                                      ev.content.relations.relations.clear();
+                                                      room.value()->sendMessageEvent(
+                                                        ev.content,
+                                                        mtx::events::EventType::RoomMessage);
+                                              }
+                                      },
+                                      *e);
+                            });
+
+                          return;
+                  });
+
+                return;
+        }
+
+        std::visit(
+          [room](auto e) {
+                  if constexpr (mtx::events::message_content_to_type<decltype(e.content)> ==
+                                mtx::events::EventType::RoomMessage) {
+                          e.content.relations.relations.clear();
+                          removeReplyFallback(e);
+                          room.value()->sendMessageEvent(e.content,
+                                                         mtx::events::EventType::RoomMessage);
+                  }
+          },
+          *e);
+}
\ No newline at end of file
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 3b405142..809b286e 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -16,6 +16,7 @@
 
 #include "Cache.h"
 #include "CallManager.h"
+#include "EventAccessors.h"
 #include "Logging.h"
 #include "TimelineModel.h"
 #include "Utils.h"
@@ -146,11 +147,59 @@ public slots:
 
         void backToRooms() { emit showRoomList(); }
         QObject *completerFor(QString completerName, QString roomId = "");
+        void forwardMessageToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
 
 private slots:
         void openImageOverlayInternal(QString eventId, QImage img);
 
 private:
+        template<template<class...> class Op, class... Args>
+        using is_detected =
+          typename nheko::detail::detector<nheko::nonesuch, void, Op, Args...>::value_t;
+
+        template<class Content>
+        using file_t = decltype(Content::file);
+
+        template<class Content>
+        using url_t = decltype(Content::url);
+
+        template<class Content>
+        using body_t = decltype(Content::body);
+
+        template<class Content>
+        using formatted_body_t = decltype(Content::formatted_body);
+
+        template<typename T>
+        static constexpr bool messageWithFileAndUrl(const mtx::events::Event<T> &)
+        {
+                return is_detected<file_t, T>::value && is_detected<url_t, T>::value;
+        }
+
+        template<typename T>
+        static constexpr void removeReplyFallback(mtx::events::Event<T> &e)
+        {
+                if constexpr (is_detected<body_t, T>::value) {
+                        if constexpr (std::is_same_v<std::optional<std::string>,
+                                                     std::remove_cv_t<decltype(e.content.body)>>) {
+                                if (e.content.body) {
+                                        e.content.body = utils::stripReplyFromBody(e.content.body);
+                                }
+                        } else if constexpr (std::is_same_v<
+                                               std::string,
+                                               std::remove_cv_t<decltype(e.content.body)>>) {
+                                e.content.body = utils::stripReplyFromBody(e.content.body);
+                        }
+                }
+
+                if constexpr (is_detected<formatted_body_t, T>::value) {
+                        if (e.content.format == "org.matrix.custom.html") {
+                                e.content.formatted_body =
+                                  utils::stripReplyFromFormattedBody(e.content.formatted_body);
+                        }
+                }
+        }
+
+private:
 #ifdef USE_QUICK_VIEW
         QQuickView *view;
 #else