diff options
author | Nicolas Werner <nicolas.werner@hotmail.de> | 2019-09-29 10:45:35 +0200 |
---|---|---|
committer | Nicolas Werner <nicolas.werner@hotmail.de> | 2019-11-23 20:06:14 +0100 |
commit | e2d733a01a1c936d22ec6c67b2f3b57ac0afdabb (patch) | |
tree | 75964b03556235d25e25d90b25a7c1bedad402c0 /src | |
parent | Reenable ImageOverlay (diff) | |
download | nheko-e2d733a01a1c936d22ec6c67b2f3b57ac0afdabb.tar.xz |
Restore saving of media
Diffstat (limited to 'src')
-rw-r--r-- | src/MatrixClient.h | 10 | ||||
-rw-r--r-- | src/timeline2/TimelineModel.cpp | 55 | ||||
-rw-r--r-- | src/timeline2/TimelineModel.h | 2 | ||||
-rw-r--r-- | src/timeline2/TimelineViewManager.cpp | 98 | ||||
-rw-r--r-- | src/timeline2/TimelineViewManager.h | 25 |
5 files changed, 163 insertions, 27 deletions
diff --git a/src/MatrixClient.h b/src/MatrixClient.h index 2af57267..c77b1183 100644 --- a/src/MatrixClient.h +++ b/src/MatrixClient.h @@ -20,16 +20,6 @@ Q_DECLARE_METATYPE(nlohmann::json) Q_DECLARE_METATYPE(std::vector<std::string>) Q_DECLARE_METATYPE(std::vector<QString>) -class MediaProxy : public QObject -{ - Q_OBJECT - -signals: - void imageDownloaded(const QPixmap &); - void imageSaved(const QString &, const QByteArray &); - void fileDownloaded(const QByteArray &); -}; - namespace http { mtx::http::Client * client(); diff --git a/src/timeline2/TimelineModel.cpp b/src/timeline2/TimelineModel.cpp index 36b768ba..b702686e 100644 --- a/src/timeline2/TimelineModel.cpp +++ b/src/timeline2/TimelineModel.cpp @@ -105,6 +105,53 @@ eventUrl(const mtx::events::RoomEvent<T> &e) } template<class T> +QString +eventFilename(const T &) +{ + return ""; +} +QString +eventFilename(const mtx::events::RoomEvent<mtx::events::msg::Audio> &e) +{ + // body may be the original filename + return QString::fromStdString(e.content.body); +} +QString +eventFilename(const mtx::events::RoomEvent<mtx::events::msg::Video> &e) +{ + // body may be the original filename + return QString::fromStdString(e.content.body); +} +QString +eventFilename(const mtx::events::RoomEvent<mtx::events::msg::Image> &e) +{ + // body may be the original filename + return QString::fromStdString(e.content.body); +} +QString +eventFilename(const mtx::events::RoomEvent<mtx::events::msg::File> &e) +{ + // body may be the original filename + if (!e.content.filename.empty()) + return QString::fromStdString(e.content.filename); + return QString::fromStdString(e.content.body); +} + +template<class T> +QString +eventMimeType(const T &) +{ + return QString(); +} +template<class T> +auto +eventMimeType(const mtx::events::RoomEvent<T> &e) + -> std::enable_if_t<std::is_same<decltype(e.content.info.mimetype), std::string>::value, QString> +{ + return QString::fromStdString(e.content.info.mimetype); +} + +template<class T> qml_mtx_events::EventType toRoomEventType(const mtx::events::Event<T> &e) { @@ -288,6 +335,8 @@ TimelineModel::roleNames() const {UserName, "userName"}, {Timestamp, "timestamp"}, {Url, "url"}, + {Filename, "filename"}, + {MimeType, "mimetype"}, {Height, "height"}, {Width, "width"}, {ProportionalHeight, "proportionalHeight"}, @@ -366,6 +415,12 @@ TimelineModel::data(const QModelIndex &index, int role) const case Url: return QVariant(boost::apply_visitor( [](const auto &e) -> QString { return eventUrl(e); }, event)); + case Filename: + return QVariant(boost::apply_visitor( + [](const auto &e) -> QString { return eventFilename(e); }, event)); + case MimeType: + return QVariant(boost::apply_visitor( + [](const auto &e) -> QString { return eventMimeType(e); }, event)); case Height: return QVariant(boost::apply_visitor( [](const auto &e) -> qulonglong { return eventHeight(e); }, event)); diff --git a/src/timeline2/TimelineModel.h b/src/timeline2/TimelineModel.h index 3d55f206..e10a0b6e 100644 --- a/src/timeline2/TimelineModel.h +++ b/src/timeline2/TimelineModel.h @@ -127,6 +127,8 @@ public: UserName, Timestamp, Url, + Filename, + MimeType, Height, Width, ProportionalHeight, diff --git a/src/timeline2/TimelineViewManager.cpp b/src/timeline2/TimelineViewManager.cpp index bf09ef5a..eed0682d 100644 --- a/src/timeline2/TimelineViewManager.cpp +++ b/src/timeline2/TimelineViewManager.cpp @@ -1,6 +1,8 @@ #include "TimelineViewManager.h" +#include <QFileDialog> #include <QMetaType> +#include <QMimeDatabase> #include <QQmlContext> #include "Logging.h" @@ -55,24 +57,88 @@ TimelineViewManager::setHistoryView(const QString &room_id) } void -TimelineViewManager::openImageOverlay(QString url) const +TimelineViewManager::openImageOverlay(QString mxcUrl, + QString originalFilename, + QString mimeType, + qml_mtx_events::EventType eventType) const { QQuickImageResponse *imgResponse = - imgProvider->requestImageResponse(url.remove("image://mxcimage/"), QSize()); - connect(imgResponse, &QQuickImageResponse::finished, this, [imgResponse]() { - if (!imgResponse->errorString().isEmpty()) { - nhlog::ui()->error("Error when retrieving image for overlay: {}", - imgResponse->errorString().toStdString()); - return; - } - auto pixmap = QPixmap::fromImage(imgResponse->textureFactory()->image()); - - auto imgDialog = new dialogs::ImageOverlay(pixmap); - imgDialog->show(); - // connect(imgDialog, &dialogs::ImageOverlay::saving, this, - // &ImageItem::saveAs); - Q_UNUSED(imgDialog); - }); + imgProvider->requestImageResponse(mxcUrl.remove("mxc://"), QSize()); + connect(imgResponse, + &QQuickImageResponse::finished, + this, + [this, mxcUrl, originalFilename, mimeType, eventType, imgResponse]() { + if (!imgResponse->errorString().isEmpty()) { + nhlog::ui()->error("Error when retrieving image for overlay: {}", + imgResponse->errorString().toStdString()); + return; + } + auto pixmap = QPixmap::fromImage(imgResponse->textureFactory()->image()); + + auto imgDialog = new dialogs::ImageOverlay(pixmap); + imgDialog->show(); + connect(imgDialog, + &dialogs::ImageOverlay::saving, + this, + [this, mxcUrl, originalFilename, mimeType, eventType]() { + saveMedia(mxcUrl, originalFilename, mimeType, eventType); + }); + }); +} + +void +TimelineViewManager::saveMedia(QString mxcUrl, + QString originalFilename, + QString mimeType, + qml_mtx_events::EventType eventType) const +{ + QString dialogTitle; + if (eventType == qml_mtx_events::EventType::ImageMessage) { + dialogTitle = tr("Save image"); + } else if (eventType == qml_mtx_events::EventType::VideoMessage) { + dialogTitle = tr("Save video"); + } else if (eventType == qml_mtx_events::EventType::AudioMessage) { + dialogTitle = tr("Save audio"); + } else { + dialogTitle = tr("Save file"); + } + + QString filterString = QMimeDatabase().mimeTypeForName(mimeType).filterString(); + + auto filename = + QFileDialog::getSaveFileName(container, dialogTitle, originalFilename, filterString); + + if (filename.isEmpty()) + return; + + const auto url = mxcUrl.toStdString(); + + http::client()->download( + url, + [filename, url](const std::string &data, + const std::string &, + const std::string &, + mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("failed to retrieve image {}: {} {}", + url, + err->matrix_error.error, + static_cast<int>(err->status_code)); + return; + } + + try { + QFile file(filename); + + if (!file.open(QIODevice::WriteOnly)) + return; + + file.write(QByteArray(data.data(), data.size())); + file.close(); + } catch (const std::exception &e) { + nhlog::ui()->warn("Error while saving file to: {}", e.what()); + } + }); } void diff --git a/src/timeline2/TimelineViewManager.h b/src/timeline2/TimelineViewManager.h index 68f6ddb0..687ae24e 100644 --- a/src/timeline2/TimelineViewManager.h +++ b/src/timeline2/TimelineViewManager.h @@ -35,7 +35,30 @@ public: void clearAll() { models.clear(); } Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; } - Q_INVOKABLE void openImageOverlay(QString url) const; + void openImageOverlay(QString mxcUrl, + QString originalFilename, + QString mimeType, + qml_mtx_events::EventType eventType) const; + void saveMedia(QString mxcUrl, + QString originalFilename, + QString mimeType, + qml_mtx_events::EventType eventType) const; + // Qml can only pass enum as int + Q_INVOKABLE void openImageOverlay(QString mxcUrl, + QString originalFilename, + QString mimeType, + int eventType) const + { + openImageOverlay( + mxcUrl, originalFilename, mimeType, (qml_mtx_events::EventType)eventType); + } + Q_INVOKABLE void saveMedia(QString mxcUrl, + QString originalFilename, + QString mimeType, + int eventType) const + { + saveMedia(mxcUrl, originalFilename, mimeType, (qml_mtx_events::EventType)eventType); + } signals: void clearRoomMessageCount(QString roomid); |