summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-04-23 20:55:28 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2023-04-23 20:55:28 +0200
commit6a03615413ef90e378df80fa1e3bc4ef031d5ea6 (patch)
treec577c21e1c3cda9f7c50a9545c7a57720de762b9 /src
parentTranslated using Weblate (Ukrainian) (diff)
downloadnheko-6a03615413ef90e378df80fa1e3bc4ef031d5ea6.tar.xz
Copy image to clipboard
Fixes #599
Diffstat (limited to 'src')
-rw-r--r--src/timeline/InputBar.cpp1
-rw-r--r--src/timeline/TimelineModel.cpp55
-rw-r--r--src/timeline/TimelineModel.h1
-rw-r--r--src/timeline/TimelineViewManager.cpp35
-rw-r--r--src/timeline/TimelineViewManager.h1
5 files changed, 91 insertions, 2 deletions
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index 879ec7cc..3a626a3c 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -148,6 +148,7 @@ InputBar::insertMimeData(const QMimeData *md)
 
     nhlog::ui()->debug("Got mime formats: {}",
                        md->formats().join(QStringLiteral(", ")).toStdString());
+    nhlog::ui()->debug("Has image: {}", md->hasImage());
     const auto formats = md->formats().filter(QStringLiteral("/"));
     const auto image   = formats.filter(QStringLiteral("image/"), Qt::CaseInsensitive);
     const auto audio   = formats.filter(QStringLiteral("audio/"), Qt::CaseInsensitive);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index f80f2ee9..5996bea8 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -12,6 +12,7 @@
 #include <QDesktopServices>
 #include <QFileDialog>
 #include <QGuiApplication>
+#include <QMimeData>
 #include <QMimeDatabase>
 #include <QRegularExpression>
 #include <QStandardPaths>
@@ -1860,6 +1861,60 @@ TimelineModel::saveMedia(const QString &eventId) const
     return true;
 }
 
+bool
+TimelineModel::copyMedia(const QString &eventId) const
+{
+    auto event = events.get(eventId.toStdString(), "");
+    if (!event)
+        return false;
+
+    QString mxcUrl                      = QString::fromStdString(mtx::accessors::url(*event));
+    QString mimeType                    = QString::fromStdString(mtx::accessors::mimetype(*event));
+    qml_mtx_events::EventType eventType = toRoomEventType(*event);
+
+    auto encryptionInfo = mtx::accessors::file(*event);
+
+    const auto url = mxcUrl.toStdString();
+
+    http::client()->download(
+      url,
+      [url, mimeType, eventType, encryptionInfo](const std::string &data,
+                                                 const std::string &,
+                                                 const std::string &,
+                                                 mtx::http::RequestErr err) {
+          if (err) {
+              nhlog::net()->warn("failed to retrieve media {}: {} {}",
+                                 url,
+                                 err->matrix_error.error,
+                                 static_cast<int>(err->status_code));
+              return;
+          }
+
+          try {
+              auto temp = data;
+              if (encryptionInfo)
+                  temp =
+                    mtx::crypto::to_string(mtx::crypto::decrypt_file(temp, encryptionInfo.value()));
+
+              auto by                 = QByteArray(temp.data(), (qsizetype)temp.size());
+              QMimeData *clipContents = new QMimeData();
+              clipContents->setData(mimeType, by);
+
+              if (eventType == qml_mtx_events::EventType::ImageMessage) {
+                  auto img = utils::readImage(QByteArray(data.data(), (qsizetype)data.size()));
+                  clipContents->setImageData(img);
+              }
+
+              QGuiApplication::clipboard()->setMimeData(clipContents);
+
+              return;
+          } catch (const std::exception &e) {
+              nhlog::ui()->warn("Error while copying file to clipboard: {}", e.what());
+          }
+      });
+    return true;
+}
+
 void
 TimelineModel::cacheMedia(const QString &eventId,
                           const std::function<void(const QString)> &callback)
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 0244c1b1..b0d81441 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -320,6 +320,7 @@ public:
     Q_INVOKABLE void openMedia(const QString &eventId);
     Q_INVOKABLE void cacheMedia(const QString &eventId);
     Q_INVOKABLE bool saveMedia(const QString &eventId) const;
+    Q_INVOKABLE bool copyMedia(const QString &eventId) const;
     Q_INVOKABLE void showEvent(QString eventId);
     Q_INVOKABLE void copyLinkToEvent(const QString &eventId) const;
 
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index b949e4c3..44f288c6 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -5,7 +5,9 @@
 #include "TimelineViewManager.h"
 
 #include <QApplication>
+#include <QClipboard>
 #include <QFileDialog>
+#include <QMimeData>
 #include <QStandardPaths>
 #include <QString>
 
@@ -29,8 +31,6 @@
 #include "voip/CallManager.h"
 #include "voip/WebRTCSession.h"
 
-namespace msgs = mtx::events::msg;
-
 namespace {
 template<template<class...> class Op, class... Args>
 using is_detected = typename nheko::detail::detector<nheko::nonesuch, void, Op, Args...>::value_t;
@@ -319,6 +319,37 @@ TimelineViewManager::saveMedia(QString mxcUrl)
 }
 
 void
+TimelineViewManager::copyImage(const QString &mxcUrl) const
+{
+    const auto url = mxcUrl.toStdString();
+    QString mimeType;
+
+    http::client()->download(
+      url,
+      [url, mimeType](const std::string &data,
+                      const std::string &,
+                      const std::string &,
+                      mtx::http::RequestErr err) {
+          if (err) {
+              nhlog::net()->warn("failed to retrieve media {}: {} {}",
+                                 url,
+                                 err->matrix_error.error,
+                                 static_cast<int>(err->status_code));
+              return;
+          }
+
+          try {
+              auto img = utils::readImage(QByteArray(data.data(), (qsizetype)data.size()));
+              QGuiApplication::clipboard()->setImage(img);
+
+              return;
+          } catch (const std::exception &e) {
+              nhlog::ui()->warn("Error while copying file to clipboard: {}", e.what());
+          }
+      });
+}
+
+void
 TimelineViewManager::updateReadReceipts(const QString &room_id,
                                         const std::vector<QString> &event_ids)
 {
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index ee5cf031..e3279e21 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -56,6 +56,7 @@ public:
                                       double proportionalHeight);
     Q_INVOKABLE void openImagePackSettings(QString roomid);
     Q_INVOKABLE void saveMedia(QString mxcUrl);
+    Q_INVOKABLE void copyImage(const QString &mxcUrl) const;
     Q_INVOKABLE QColor userColor(QString id, QColor background);
     Q_INVOKABLE QString escapeEmoji(QString str) const;
     Q_INVOKABLE QString htmlEscape(QString str) const { return str.toHtmlEscaped(); }