From c569ab24bc1a59149d7f2c79ef25f510837feab5 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Sun, 24 Jan 2021 01:29:30 +0100 Subject: [PATCH] Add "open in external program" action --- resources/qml/TimelineView.qml | 6 ++++++ src/timeline/TimelineModel.cpp | 39 +++++++++++++++++++++++++++------- src/timeline/TimelineModel.h | 2 ++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 38e3a928..f3584b47 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -124,6 +124,12 @@ Page { text: qsTr("Save as") onTriggered: TimelineManager.timeline.saveMedia(messageContextMenu.eventId) } + MenuItem { + visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker + height: visible ? implicitHeight : 0 + text: qsTr("Open in external program") + onTriggered: TimelineManager.timeline.openMedia(messageContextMenu.eventId) + } } diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 80ccabea..4346b0b2 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -1073,6 +1074,14 @@ TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event) std::visit(SendMessageVisitor{this}, event); } +void +TimelineModel::openMedia(QString eventId) +{ + cacheMedia(eventId, [](QString filename) { + QDesktopServices::openUrl(QUrl::fromLocalFile(filename)); + }); +} + bool TimelineModel::saveMedia(QString eventId) const { @@ -1149,7 +1158,7 @@ TimelineModel::saveMedia(QString eventId) const } void -TimelineModel::cacheMedia(QString eventId) +TimelineModel::cacheMedia(QString eventId, std::function callback) { mtx::events::collections::TimelineEvents *event = events.get(eventId.toStdString(), ""); if (!event) @@ -1169,12 +1178,13 @@ TimelineModel::cacheMedia(QString eventId) QString suffix = QMimeDatabase().mimeTypeForName(mimeType).preferredSuffix(); - const auto url = mxcUrl.toStdString(); + const auto url = mxcUrl.toStdString(); + const auto name = QString(mxcUrl).remove("mxc://"); QFileInfo filename(QString("%1/media_cache/%2.%3") .arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) - .arg(QString(mxcUrl).remove("mxc://")) + .arg(name) .arg(suffix)); - if (QDir::cleanPath(filename.path()) != filename.path()) { + if (QDir::cleanPath(name) != name) { nhlog::net()->warn("mxcUrl '{}' is not safe, not downloading file", url); return; } @@ -1183,15 +1193,18 @@ TimelineModel::cacheMedia(QString eventId) if (filename.isReadable()) { emit mediaCached(mxcUrl, filename.filePath()); + if (callback) { + callback(filename.filePath()); + } return; } http::client()->download( url, - [this, mxcUrl, filename, url, encryptionInfo](const std::string &data, - const std::string &, - const std::string &, - mtx::http::RequestErr err) { + [this, callback, mxcUrl, filename, url, encryptionInfo](const std::string &data, + const std::string &, + const std::string &, + mtx::http::RequestErr err) { if (err) { nhlog::net()->warn("failed to retrieve image {}: {} {}", url, @@ -1213,6 +1226,10 @@ TimelineModel::cacheMedia(QString eventId) file.write(QByteArray(temp.data(), (int)temp.size())); file.close(); + + if (callback) { + callback(filename.filePath()); + } } catch (const std::exception &e) { nhlog::ui()->warn("Error while saving file to: {}", e.what()); } @@ -1221,6 +1238,12 @@ TimelineModel::cacheMedia(QString eventId) }); } +void +TimelineModel::cacheMedia(QString eventId) +{ + cacheMedia(eventId, NULL); +} + QString TimelineModel::formatTypingUsers(const std::vector &users, QColor bg) { diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index b6b3b5ae..35e62eb4 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -218,8 +218,10 @@ public: Q_INVOKABLE void redactEvent(QString id); Q_INVOKABLE int idToIndex(QString id) const; Q_INVOKABLE QString indexToId(int index) const; + Q_INVOKABLE void openMedia(QString eventId); Q_INVOKABLE void cacheMedia(QString eventId); Q_INVOKABLE bool saveMedia(QString eventId) const; + void cacheMedia(QString eventId, std::function callback); std::vector<::Reaction> reactions(const std::string &event_id) {