directly upload old file object and reuse old message

pull/552/head
targetakhil 4 years ago
parent 9934004702
commit eb13f7c169
  1. 15
      src/timeline/InputBar.h
  2. 128
      src/timeline/TimelineViewManager.cpp
  3. 45
      src/timeline/TimelineViewManager.h

@ -41,14 +41,6 @@ public:
connect(&typingTimeout_, &QTimer::timeout, this, &InputBar::stopTyping); connect(&typingTimeout_, &QTimer::timeout, this, &InputBar::stopTyping);
} }
void image(const QString &filename,
const std::optional<mtx::crypto::EncryptedFile> &file,
const QString &url,
const QString &mime,
uint64_t dsize,
const QSize &dimensions,
const QString &blurhash);
public slots: public slots:
QString text() const; QString text() const;
QString previousText(); QString previousText();
@ -78,6 +70,13 @@ private:
void emote(QString body, bool rainbowify); void emote(QString body, bool rainbowify);
void notice(QString body, bool rainbowify); void notice(QString body, bool rainbowify);
void command(QString name, QString args); void command(QString name, QString args);
void image(const QString &filename,
const std::optional<mtx::crypto::EncryptedFile> &file,
const QString &url,
const QString &mime,
uint64_t dsize,
const QSize &dimensions,
const QString &blurhash);
void file(const QString &filename, void file(const QString &filename,
const std::optional<mtx::crypto::EncryptedFile> &encryptedFile, const std::optional<mtx::crypto::EncryptedFile> &encryptedFile,
const QString &url, const QString &url,

@ -627,86 +627,72 @@ TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEven
auto elem = *e; auto elem = *e;
auto room = models.find(roomId); auto room = models.find(roomId);
auto messageType = mtx::accessors::msg_type(elem); auto messageType = mtx::accessors::msg_type(elem);
auto content = mtx::accessors::url(elem);
if (sentFromEncrypted) {
std::optional<mtx::crypto::EncryptedFile> encryptionInfo =
mtx::accessors::file(elem);
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;
}
if (sentFromEncrypted && messageType == mtx::events::MessageType::Image) { assert(encryptionInfo);
auto body = mtx::accessors::body(elem);
auto mimetype = mtx::accessors::mimetype(elem); auto data = mtx::crypto::to_string(
auto imageHeight = mtx::accessors::media_height(elem); mtx::crypto::decrypt_file(res, encryptionInfo.value()));
auto imageWidth = mtx::accessors::media_height(elem);
http::client()->upload(
QString mxcUrl = QString::fromStdString(mtx::accessors::url(elem)); data,
MxcImageProvider::download( content_type,
mxcUrl.remove("mxc://"), originalFilename,
QSize(imageWidth, imageHeight), [this, roomId, e](const mtx::responses::ContentURI &res,
[this, roomId, body, mimetype](QString, QSize, QImage image, QString) { mtx::http::RequestErr err) mutable {
QByteArray data = if (err) {
QByteArray::fromRawData((const char *)image.bits(), image.byteCount()); nhlog::net()->warn("failed to upload media: {} {} ({})",
err->matrix_error.error,
auto payload = std::string(data.data(), data.size()); to_string(err->matrix_error.errcode),
std::optional<mtx::crypto::EncryptedFile> encryptedFile; static_cast<int>(err->status_code));
return;
QSize dimensions;
QString blurhash;
auto mimeClass = QString::fromStdString(mimetype).split("/")[0];
dimensions = image.size();
if (image.height() > 200 && image.width() > 360)
image = image.scaled(360, 200, Qt::KeepAspectRatioByExpanding);
std::vector<unsigned char> data_;
for (int y = 0; y < image.height(); y++) {
for (int x = 0; x < image.width(); x++) {
auto p = image.pixel(x, y);
data_.push_back(static_cast<unsigned char>(qRed(p)));
data_.push_back(static_cast<unsigned char>(qGreen(p)));
data_.push_back(static_cast<unsigned char>(qBlue(p)));
} }
}
blurhash = QString::fromStdString( std::visit(
blurhash::encode(data_.data(), image.width(), image.height(), 4, 3)); [this, roomId, e, url = res.content_uri](auto ev) {
if constexpr (mtx::events::message_content_to_type<
http::client()->upload( decltype(ev.content)> ==
payload, mtx::events::EventType::RoomMessage) {
encryptedFile ? "application/octet-stream" : mimetype, if constexpr (messageWithFileAndUrl(ev)) {
body, ev.content.relations.relations.clear();
[this, ev.content.file.reset();
roomId, ev.content.url = url;
filename = body,
encryptedFile = std::move(encryptedFile), auto room = models.find(roomId);
mimeClass, room.value()->sendMessageEvent(
mimetype, ev.content,
size = payload.size(), mtx::events::EventType::RoomMessage);
dimensions, }
blurhash](const mtx::responses::ContentURI &res, }
mtx::http::RequestErr err) mutable { },
if (err) { *e);
nhlog::net()->warn("failed to upload media: {} {} ({})", });
err->matrix_error.error,
to_string(err->matrix_error.errcode), return;
static_cast<int>(err->status_code));
return;
}
auto url = QString::fromStdString(res.content_uri);
if (encryptedFile)
encryptedFile->url = res.content_uri;
auto r = models.find(roomId);
r.value()->input()->image(QString::fromStdString(filename),
encryptedFile,
url,
QString::fromStdString(mimetype),
size,
dimensions,
blurhash);
});
}); });
return; return;
}; }
std::visit( std::visit(
[room](auto e) { [room](auto e) {
if constexpr (mtx::events::message_content_to_type<decltype(e.content)> == if constexpr (mtx::events::message_content_to_type<decltype(e.content)> ==
mtx::events::EventType::RoomMessage) { mtx::events::EventType::RoomMessage) {
e.content.relations.relations.clear();
room.value()->sendMessageEvent(e.content, room.value()->sendMessageEvent(e.content,
mtx::events::EventType::RoomMessage); mtx::events::EventType::RoomMessage);
} }

@ -13,6 +13,7 @@
#include <mtx/common.hpp> #include <mtx/common.hpp>
#include <mtx/responses/messages.hpp> #include <mtx/responses/messages.hpp>
#include <mtx/responses/sync.hpp> #include <mtx/responses/sync.hpp>
#include <type_traits>
#include "Cache.h" #include "Cache.h"
#include "CallManager.h" #include "CallManager.h"
@ -31,6 +32,33 @@ class UserSettings;
class ChatPage; class ChatPage;
class DeviceVerificationFlow; class DeviceVerificationFlow;
struct nonesuch
{
~nonesuch() = delete;
nonesuch(nonesuch const &) = delete;
void operator=(nonesuch const &) = delete;
};
namespace detail {
template<class Default, class AlwaysVoid, template<class...> class Op, class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
template<class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
{
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
template<template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
class TimelineViewManager : public QObject class TimelineViewManager : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -154,6 +182,23 @@ public slots:
private slots: private slots:
void openImageOverlayInternal(QString eventId, QImage img); void openImageOverlayInternal(QString eventId, QImage img);
private:
template<class Content>
using f_t = decltype(Content::file);
template<class Content>
using u_t = decltype(Content::url);
template<typename T>
static constexpr bool messageWithFileAndUrl(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<f_t, T>::value && is_detected<u_t, T>::value) {
return true;
}
return false;
}
private: private:
#ifdef USE_QUICK_VIEW #ifdef USE_QUICK_VIEW
QQuickView *view; QQuickView *view;

Loading…
Cancel
Save