directly upload old file object and reuse old message
This commit is contained in:
parent
9934004702
commit
eb13f7c169
@ -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 && messageType == mtx::events::MessageType::Image) {
|
if (sentFromEncrypted) {
|
||||||
auto body = mtx::accessors::body(elem);
|
std::optional<mtx::crypto::EncryptedFile> encryptionInfo =
|
||||||
auto mimetype = mtx::accessors::mimetype(elem);
|
mtx::accessors::file(elem);
|
||||||
auto imageHeight = mtx::accessors::media_height(elem);
|
|
||||||
auto imageWidth = mtx::accessors::media_height(elem);
|
|
||||||
|
|
||||||
QString mxcUrl = QString::fromStdString(mtx::accessors::url(elem));
|
http::client()->download(
|
||||||
MxcImageProvider::download(
|
content,
|
||||||
mxcUrl.remove("mxc://"),
|
[this, roomId, e, encryptionInfo](const std::string &res,
|
||||||
QSize(imageWidth, imageHeight),
|
const std::string &content_type,
|
||||||
[this, roomId, body, mimetype](QString, QSize, QImage image, QString) {
|
const std::string &originalFilename,
|
||||||
QByteArray data =
|
mtx::http::RequestErr err) {
|
||||||
QByteArray::fromRawData((const char *)image.bits(), image.byteCount());
|
if (err) {
|
||||||
|
return;
|
||||||
auto payload = std::string(data.data(), data.size());
|
|
||||||
std::optional<mtx::crypto::EncryptedFile> encryptedFile;
|
|
||||||
|
|
||||||
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(
|
|
||||||
blurhash::encode(data_.data(), image.width(), image.height(), 4, 3));
|
|
||||||
|
|
||||||
http::client()->upload(
|
assert(encryptionInfo);
|
||||||
payload,
|
|
||||||
encryptedFile ? "application/octet-stream" : mimetype,
|
|
||||||
body,
|
|
||||||
[this,
|
|
||||||
roomId,
|
|
||||||
filename = body,
|
|
||||||
encryptedFile = std::move(encryptedFile),
|
|
||||||
mimeClass,
|
|
||||||
mimetype,
|
|
||||||
size = payload.size(),
|
|
||||||
dimensions,
|
|
||||||
blurhash](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;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto url = QString::fromStdString(res.content_uri);
|
auto data = mtx::crypto::to_string(
|
||||||
if (encryptedFile)
|
mtx::crypto::decrypt_file(res, encryptionInfo.value()));
|
||||||
encryptedFile->url = res.content_uri;
|
|
||||||
|
|
||||||
auto r = models.find(roomId);
|
http::client()->upload(
|
||||||
r.value()->input()->image(QString::fromStdString(filename),
|
data,
|
||||||
encryptedFile,
|
content_type,
|
||||||
url,
|
originalFilename,
|
||||||
QString::fromStdString(mimetype),
|
[this, roomId, e](const mtx::responses::ContentURI &res,
|
||||||
size,
|
mtx::http::RequestErr err) mutable {
|
||||||
dimensions,
|
if (err) {
|
||||||
blurhash);
|
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, e, 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);
|
||||||
|
room.value()->sendMessageEvent(
|
||||||
|
ev.content,
|
||||||
|
mtx::events::EventType::RoomMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
*e);
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
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…
Reference in New Issue
Block a user