summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2022-01-02 21:46:29 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2022-01-02 21:46:29 +0100
commit66520eae195ad252021ebb5c6bfe2a1efc5f8adf (patch)
treeb747d2ca17a3fc4a7bc116cd309d52861e2b3c0b /src
parentFix fade out of ripple (diff)
downloadnheko-66520eae195ad252021ebb5c6bfe2a1efc5f8adf.tar.xz
Port image overlay to qml
Allows you to zoom and pan now.

relates to #647
Diffstat (limited to 'src')
-rw-r--r--src/dialogs/ImageOverlay.cpp102
-rw-r--r--src/dialogs/ImageOverlay.h39
-rw-r--r--src/timeline/TimelineViewManager.cpp73
-rw-r--r--src/timeline/TimelineViewManager.h8
-rw-r--r--src/ui/MxcAnimatedImage.cpp21
-rw-r--r--src/ui/MxcAnimatedImage.h1
6 files changed, 62 insertions, 182 deletions
diff --git a/src/dialogs/ImageOverlay.cpp b/src/dialogs/ImageOverlay.cpp
deleted file mode 100644

index d9f0a993..00000000 --- a/src/dialogs/ImageOverlay.cpp +++ /dev/null
@@ -1,102 +0,0 @@ -// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr> -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// SPDX-FileCopyrightText: 2022 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include <QApplication> -#include <QGuiApplication> -#include <QPainter> -#include <QScreen> - -#include "dialogs/ImageOverlay.h" - -#include "Utils.h" - -using namespace dialogs; - -ImageOverlay::ImageOverlay(const QPixmap &image, QWidget *parent) - : QWidget{parent} - , originalImage_{image} -{ - setMouseTracking(true); - setParent(nullptr); - - setWindowFlags(windowFlags() | Qt::FramelessWindowHint); - setWindowRole(QStringLiteral("imageoverlay")); - - setAttribute(Qt::WA_NoSystemBackground, true); - setAttribute(Qt::WA_TranslucentBackground, true); - setAttribute(Qt::WA_DeleteOnClose, true); - setWindowState(Qt::WindowFullScreen); - close_shortcut_ = new QShortcut(QKeySequence(Qt::Key_Escape), this); - - connect(close_shortcut_, &QShortcut::activated, this, &ImageOverlay::closing); - connect(this, &ImageOverlay::closing, this, &ImageOverlay::close); - - raise(); -} - -void -ImageOverlay::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event); - - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - - // Full screen overlay. - painter.fillRect(QRect(0, 0, width(), height()), QColor(55, 55, 55, 170)); - - // Left and Right margins - int outer_margin = width() * 0.12; - int buttonSize = 36; - int margin = outer_margin * 0.1; - - int max_width = width() - 2 * outer_margin; - int max_height = height(); - - image_ = utils::scaleDown(max_width, max_height, originalImage_); - - int diff_x = max_width - image_.width(); - int diff_y = max_height - image_.height(); - - content_ = QRect(outer_margin + diff_x / 2, diff_y / 2, image_.width(), image_.height()); - close_button_ = QRect(width() - margin - buttonSize, margin, buttonSize, buttonSize); - save_button_ = QRect(width() - (2 * margin) - (2 * buttonSize), margin, buttonSize, buttonSize); - - // Draw main content_. - painter.drawPixmap(content_, image_); - - // Draw top right corner X. - QPen pen; - pen.setCapStyle(Qt::RoundCap); - pen.setWidthF(5); - pen.setColor("gray"); - - auto center = close_button_.center(); - - painter.setPen(pen); - painter.drawLine(center - QPointF(15, 15), center + QPointF(15, 15)); - painter.drawLine(center + QPointF(15, -15), center - QPointF(15, -15)); - - // Draw download button - center = save_button_.center(); - painter.drawLine(center - QPointF(0, 15), center + QPointF(0, 15)); - painter.drawLine(center - QPointF(15, 0), center + QPointF(0, 15)); - painter.drawLine(center + QPointF(0, 15), center + QPointF(15, 0)); -} - -void -ImageOverlay::mousePressEvent(QMouseEvent *event) -{ - if (event->button() != Qt::LeftButton) - return; - - if (close_button_.contains(event->pos())) - emit closing(); - else if (save_button_.contains(event->pos())) - emit saving(); - else if (!content_.contains(event->pos())) - emit closing(); -} diff --git a/src/dialogs/ImageOverlay.h b/src/dialogs/ImageOverlay.h deleted file mode 100644
index 9ce2fb09..00000000 --- a/src/dialogs/ImageOverlay.h +++ /dev/null
@@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr> -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// SPDX-FileCopyrightText: 2022 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include <QDialog> -#include <QMouseEvent> -#include <QPixmap> -#include <QShortcut> - -namespace dialogs { - -class ImageOverlay : public QWidget -{ - Q_OBJECT -public: - ImageOverlay(const QPixmap &image, QWidget *parent = nullptr); - -protected: - void mousePressEvent(QMouseEvent *event) override; - void paintEvent(QPaintEvent *event) override; - -signals: - void closing(); - void saving(); - -private: - QPixmap originalImage_; - QPixmap image_; - - QRect content_; - QRect close_button_; - QRect save_button_; - QShortcut *close_shortcut_; -}; -} // dialogs diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 6195c24a..7234caa9 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp
@@ -6,10 +6,12 @@ #include "TimelineViewManager.h" #include <QDropEvent> +#include <QFileDialog> #include <QMetaType> #include <QPalette> #include <QQmlContext> #include <QQmlEngine> +#include <QStandardPaths> #include <QString> #include "BlurhashProvider.h" @@ -32,7 +34,6 @@ #include "SingleImagePackModel.h" #include "UserSettingsPage.h" #include "UsersModel.h" -#include "dialogs/ImageOverlay.h" #include "emoji/EmojiModel.h" #include "emoji/Provider.h" #include "encryption/DeviceVerificationFlow.h" @@ -331,11 +332,6 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par isInitialSync_ = true; emit initialSyncChanged(true); }); - - connect(this, - &TimelineViewManager::openImageOverlayInternalCb, - this, - &TimelineViewManager::openImageOverlayInternal); } void @@ -416,23 +412,13 @@ TimelineViewManager::escapeEmoji(QString str) const } void -TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId) +TimelineViewManager::openImageOverlay(TimelineModel *room, QString mxcUrl, QString eventId) { if (mxcUrl.isEmpty()) { return; } - MxcImageProvider::download(mxcUrl.remove(QStringLiteral("mxc://")), - QSize(), - [this, eventId](QString, QSize, QImage img, QString) { - if (img.isNull()) { - nhlog::ui()->error( - "Error when retrieving image for overlay."); - return; - } - - emit openImageOverlayInternalCb(eventId, std::move(img)); - }); + emit showImageOverlay(room, eventId, mxcUrl); } void @@ -443,25 +429,46 @@ TimelineViewManager::openImagePackSettings(QString roomid) } void -TimelineViewManager::openImageOverlayInternal(QString eventId, QImage img) +TimelineViewManager::saveMedia(QString mxcUrl) { - auto pixmap = QPixmap::fromImage(img); + const QString downloadsFolder = + QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + const QString openLocation = downloadsFolder + "/" + mxcUrl.splitRef(u'/').constLast(); - auto imgDialog = new dialogs::ImageOverlay(pixmap); - imgDialog->showFullScreen(); + const QString filename = QFileDialog::getSaveFileName(getWidget(), {}, openLocation); - auto room = rooms_->currentRoom(); - connect(imgDialog, &dialogs::ImageOverlay::saving, room, [eventId, imgDialog, room]() { - // hide the overlay while presenting the save dialog for better - // cross platform support. - imgDialog->hide(); + if (filename.isEmpty()) + return; - if (!room->saveMedia(eventId)) { - imgDialog->show(); - } else { - imgDialog->close(); - } - }); + 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(), (int)data.size())); + file.close(); + + return; + } catch (const std::exception &e) { + nhlog::ui()->warn("Error while saving file to: {}", e.what()); + } + }); } void diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 47a72412..455702f4 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h
@@ -60,8 +60,9 @@ public: Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; } bool isWindowFocused() const { return isWindowFocused_; } - Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId); + Q_INVOKABLE void openImageOverlay(TimelineModel *room, QString mxcUrl, QString eventId); Q_INVOKABLE void openImagePackSettings(QString roomid); + Q_INVOKABLE void saveMedia(QString mxcUrl); 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(); } @@ -85,13 +86,13 @@ signals: void narrowViewChanged(); void focusChanged(); void focusInput(); - void openImageOverlayInternalCb(QString eventId, QImage img); void openRoomMembersDialog(MemberList *members, TimelineModel *room); void openRoomSettingsDialog(RoomSettings *settings); void openInviteUsersDialog(InviteesModel *invitees); void openProfile(UserProfile *profile); void showImagePackSettings(TimelineModel *room, ImagePackListModel *packlist); void openLeaveRoomDialog(QString roomid); + void showImageOverlay(TimelineModel *room, QString eventId, QString url); public slots: void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids); @@ -120,9 +121,6 @@ public slots: RoomlistModel *rooms() { return rooms_; } -private slots: - void openImageOverlayInternal(QString eventId, QImage img); - private: #ifdef USE_QUICK_VIEW QQuickView *view; diff --git a/src/ui/MxcAnimatedImage.cpp b/src/ui/MxcAnimatedImage.cpp
index 36e028e3..83787fff 100644 --- a/src/ui/MxcAnimatedImage.cpp +++ b/src/ui/MxcAnimatedImage.cpp
@@ -20,10 +20,12 @@ void MxcAnimatedImage::startDownload() { + nhlog::ui()->debug("START DOWNLOAD!!!"); if (!room_) return; if (eventId_.isEmpty()) return; + nhlog::ui()->debug("START DOWNLOAD2!!!"); auto event = room_->eventById(eventId_); if (!event) { @@ -92,7 +94,9 @@ MxcAnimatedImage::startDownload() "Playing movie with size: {}, {}", buffer.bytesAvailable(), buffer.isOpen()); movie.setFormat(mimeType); movie.setDevice(&buffer); - movie.setScaledSize(this->size().toSize()); + + if (height() != 0 && width() != 0) + movie.setScaledSize(this->size().toSize()); if (buffer.bytesAvailable() < 4LL * 1024 * 1024 * 1024) // cache images smaller than 4MB in RAM movie.setCacheMode(QMovie::CacheAll); @@ -145,6 +149,17 @@ MxcAnimatedImage::startDownload() }); } +void +MxcAnimatedImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + QQuickItem::geometryChanged(newGeometry, oldGeometry); + + if (newGeometry.size() != oldGeometry.size()) { + if (height() != 0 && width() != 0) + movie.setScaledSize(newGeometry.size().toSize()); + } +} + QSGNode * MxcAnimatedImage::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) { @@ -171,8 +186,8 @@ MxcAnimatedImage::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeD return nullptr; } - n->setRect(QRect(0, 0, width(), height())); - n->setFiltering(QSGTexture::Nearest); + n->setRect(0, 0, width(), height()); + n->setFiltering(QSGTexture::Linear); n->setMipmapFiltering(QSGTexture::None); return n; diff --git a/src/ui/MxcAnimatedImage.h b/src/ui/MxcAnimatedImage.h
index 1afe6a19..8891e57e 100644 --- a/src/ui/MxcAnimatedImage.h +++ b/src/ui/MxcAnimatedImage.h
@@ -60,6 +60,7 @@ public: } } + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;