Port image overlay to qml
Allows you to zoom and pan now. relates to #647
This commit is contained in:
parent
c3e2e73175
commit
66520eae19
@ -310,7 +310,6 @@ set(SRC_FILES
|
|||||||
# Dialogs
|
# Dialogs
|
||||||
src/dialogs/CreateRoom.cpp
|
src/dialogs/CreateRoom.cpp
|
||||||
src/dialogs/FallbackAuth.cpp
|
src/dialogs/FallbackAuth.cpp
|
||||||
src/dialogs/ImageOverlay.cpp
|
|
||||||
src/dialogs/PreviewUploadOverlay.cpp
|
src/dialogs/PreviewUploadOverlay.cpp
|
||||||
src/dialogs/ReCaptcha.cpp
|
src/dialogs/ReCaptcha.cpp
|
||||||
|
|
||||||
@ -519,7 +518,6 @@ qt5_wrap_cpp(MOC_HEADERS
|
|||||||
# Dialogs
|
# Dialogs
|
||||||
src/dialogs/CreateRoom.h
|
src/dialogs/CreateRoom.h
|
||||||
src/dialogs/FallbackAuth.h
|
src/dialogs/FallbackAuth.h
|
||||||
src/dialogs/ImageOverlay.h
|
|
||||||
src/dialogs/PreviewUploadOverlay.h
|
src/dialogs/PreviewUploadOverlay.h
|
||||||
src/dialogs/ReCaptcha.h
|
src/dialogs/ReCaptcha.h
|
||||||
|
|
||||||
|
@ -136,6 +136,14 @@ Page {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: imageOverlay
|
||||||
|
|
||||||
|
ImageOverlay {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Ctrl+K"
|
sequence: "Ctrl+K"
|
||||||
onActivated: {
|
onActivated: {
|
||||||
@ -234,6 +242,15 @@ Page {
|
|||||||
dialog.open();
|
dialog.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onShowImageOverlay(room, eventId, url, proportionalHeight, originalWidth) {
|
||||||
|
var dialog = imageOverlay.createObject(timelineRoot, {
|
||||||
|
"room": room,
|
||||||
|
"eventId": eventId,
|
||||||
|
"url": url
|
||||||
|
});
|
||||||
|
dialog.showFullScreen();
|
||||||
|
}
|
||||||
|
|
||||||
target: TimelineManager
|
target: TimelineManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,10 +63,9 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
// TODO(Nico): Replace this with a qml thingy, that also can show animated images
|
//enabled: type == MtxEvent.ImageMessage && (img.status == Image.Ready || mxcimage.loaded)
|
||||||
enabled: type == MtxEvent.ImageMessage && (img.status == Image.Ready || mxcimage.loaded)
|
|
||||||
onSingleTapped: {
|
onSingleTapped: {
|
||||||
TimelineManager.openImageOverlay(url, room.data.eventId);
|
TimelineManager.openImageOverlay(room, url, eventId);
|
||||||
eventPoint.accepted = true;
|
eventPoint.accepted = true;
|
||||||
}
|
}
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
|
110
resources/qml/dialogs/ImageOverlay.qml
Normal file
110
resources/qml/dialogs/ImageOverlay.qml
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Window 2.15
|
||||||
|
|
||||||
|
import ".."
|
||||||
|
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
Window {
|
||||||
|
id: imageOverlay
|
||||||
|
|
||||||
|
required property string url
|
||||||
|
required property string eventId
|
||||||
|
required property Room room
|
||||||
|
|
||||||
|
flags: Qt.FramelessWindowHint
|
||||||
|
|
||||||
|
visibility: Window.FullScreen
|
||||||
|
color: Qt.rgba(0.2,0.2,0.2,0.66)
|
||||||
|
|
||||||
|
Shortcut {
|
||||||
|
sequence: StandardKey.Cancel
|
||||||
|
onActivated: imageOverlay.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: Math.min(parent.height, img.implicitHeight)
|
||||||
|
width: Math.min(parent.width, img.implicitWidth)
|
||||||
|
x: (parent.width - img.width)/2
|
||||||
|
y: (parent.height - img.height)/2
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: img
|
||||||
|
|
||||||
|
visible: !mxcimage.loaded
|
||||||
|
anchors.fill: parent
|
||||||
|
source: url.replace("mxc://", "image://MxcImage/")
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
smooth: true
|
||||||
|
mipmap: true
|
||||||
|
}
|
||||||
|
|
||||||
|
MxcAnimatedImage {
|
||||||
|
id: mxcimage
|
||||||
|
|
||||||
|
visible: loaded
|
||||||
|
anchors.fill: parent
|
||||||
|
roomm: imageOverlay.room
|
||||||
|
play: !Settings.animateImagesOnHover || mouseArea.hovered
|
||||||
|
eventId: imageOverlay.eventId
|
||||||
|
}
|
||||||
|
|
||||||
|
PinchHandler {
|
||||||
|
}
|
||||||
|
|
||||||
|
WheelHandler {
|
||||||
|
property: "scale"
|
||||||
|
}
|
||||||
|
|
||||||
|
DragHandler {
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: mouseArea
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: Nheko.paddingLarge
|
||||||
|
spacing: Nheko.paddingMedium
|
||||||
|
|
||||||
|
ImageButton {
|
||||||
|
height: 48
|
||||||
|
width: 48
|
||||||
|
hoverEnabled: true
|
||||||
|
image: ":/icons/icons/ui/download.svg"
|
||||||
|
//ToolTip.visible: hovered
|
||||||
|
//ToolTip.delay: Nheko.tooltipDelay
|
||||||
|
//ToolTip.text: qsTr("Download")
|
||||||
|
onClicked: {
|
||||||
|
if (room) {
|
||||||
|
room.saveMedia(eventId);
|
||||||
|
} else {
|
||||||
|
TimelineManager.saveMedia(url);
|
||||||
|
}
|
||||||
|
imageOverlay.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImageButton {
|
||||||
|
height: 48
|
||||||
|
width: 48
|
||||||
|
hoverEnabled: true
|
||||||
|
image: ":/icons/icons/ui/dismiss.svg"
|
||||||
|
//ToolTip.visible: hovered
|
||||||
|
//ToolTip.delay: Nheko.tooltipDelay
|
||||||
|
//ToolTip.text: qsTr("Close")
|
||||||
|
onClicked: imageOverlay.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -70,7 +70,7 @@ ApplicationWindow {
|
|||||||
displayName: profile.displayName
|
displayName: profile.displayName
|
||||||
userid: profile.userid
|
userid: profile.userid
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
onClicked: TimelineManager.openImageOverlay(profile.avatarUrl, "")
|
onClicked: TimelineManager.openImageOverlay(null, profile.avatarUrl, "")
|
||||||
|
|
||||||
ImageButton {
|
ImageButton {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
@ -37,7 +37,7 @@ Rectangle {
|
|||||||
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
userid: CallManager.callParty
|
userid: CallManager.callParty
|
||||||
displayName: CallManager.callPartyDisplayName
|
displayName: CallManager.callPartyDisplayName
|
||||||
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
onClicked: TimelineManager.openImageOverlay(room, room.avatarUrl(userid), room.data.eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@ -44,7 +44,7 @@ Rectangle {
|
|||||||
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
userid: CallManager.callParty
|
userid: CallManager.callParty
|
||||||
displayName: CallManager.callPartyDisplayName
|
displayName: CallManager.callPartyDisplayName
|
||||||
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
onClicked: TimelineManager.openImageOverlay(room, room.avatarUrl(userid), room.data.eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@ -81,7 +81,7 @@ Popup {
|
|||||||
url: room.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: room.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: room.roomName
|
displayName: room.roomName
|
||||||
roomid: room.roomid
|
roomid: room.roomid
|
||||||
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
onClicked: TimelineManager.openImageOverlay(room, room.avatarUrl(userid), room.data.eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -133,6 +133,7 @@
|
|||||||
<file>qml/device-verification/NewVerificationRequest.qml</file>
|
<file>qml/device-verification/NewVerificationRequest.qml</file>
|
||||||
<file>qml/device-verification/Success.qml</file>
|
<file>qml/device-verification/Success.qml</file>
|
||||||
<file>qml/device-verification/Waiting.qml</file>
|
<file>qml/device-verification/Waiting.qml</file>
|
||||||
|
<file>qml/dialogs/ImageOverlay.qml</file>
|
||||||
<file>qml/dialogs/ImagePackEditorDialog.qml</file>
|
<file>qml/dialogs/ImagePackEditorDialog.qml</file>
|
||||||
<file>qml/dialogs/ImagePackSettingsDialog.qml</file>
|
<file>qml/dialogs/ImagePackSettingsDialog.qml</file>
|
||||||
<file>qml/dialogs/PhoneNumberInputDialog.qml</file>
|
<file>qml/dialogs/PhoneNumberInputDialog.qml</file>
|
||||||
|
@ -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();
|
|
||||||
}
|
|
@ -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
|
|
@ -6,10 +6,12 @@
|
|||||||
#include "TimelineViewManager.h"
|
#include "TimelineViewManager.h"
|
||||||
|
|
||||||
#include <QDropEvent>
|
#include <QDropEvent>
|
||||||
|
#include <QFileDialog>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
#include <QStandardPaths>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "BlurhashProvider.h"
|
#include "BlurhashProvider.h"
|
||||||
@ -32,7 +34,6 @@
|
|||||||
#include "SingleImagePackModel.h"
|
#include "SingleImagePackModel.h"
|
||||||
#include "UserSettingsPage.h"
|
#include "UserSettingsPage.h"
|
||||||
#include "UsersModel.h"
|
#include "UsersModel.h"
|
||||||
#include "dialogs/ImageOverlay.h"
|
|
||||||
#include "emoji/EmojiModel.h"
|
#include "emoji/EmojiModel.h"
|
||||||
#include "emoji/Provider.h"
|
#include "emoji/Provider.h"
|
||||||
#include "encryption/DeviceVerificationFlow.h"
|
#include "encryption/DeviceVerificationFlow.h"
|
||||||
@ -331,11 +332,6 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||||||
isInitialSync_ = true;
|
isInitialSync_ = true;
|
||||||
emit initialSyncChanged(true);
|
emit initialSyncChanged(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(this,
|
|
||||||
&TimelineViewManager::openImageOverlayInternalCb,
|
|
||||||
this,
|
|
||||||
&TimelineViewManager::openImageOverlayInternal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -416,23 +412,13 @@ TimelineViewManager::escapeEmoji(QString str) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId)
|
TimelineViewManager::openImageOverlay(TimelineModel *room, QString mxcUrl, QString eventId)
|
||||||
{
|
{
|
||||||
if (mxcUrl.isEmpty()) {
|
if (mxcUrl.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MxcImageProvider::download(mxcUrl.remove(QStringLiteral("mxc://")),
|
emit showImageOverlay(room, eventId, mxcUrl);
|
||||||
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));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -443,25 +429,46 @@ TimelineViewManager::openImagePackSettings(QString roomid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
const QString filename = QFileDialog::getSaveFileName(getWidget(), {}, openLocation);
|
||||||
imgDialog->showFullScreen();
|
|
||||||
|
|
||||||
auto room = rooms_->currentRoom();
|
if (filename.isEmpty())
|
||||||
connect(imgDialog, &dialogs::ImageOverlay::saving, room, [eventId, imgDialog, room]() {
|
return;
|
||||||
// hide the overlay while presenting the save dialog for better
|
|
||||||
// cross platform support.
|
|
||||||
imgDialog->hide();
|
|
||||||
|
|
||||||
if (!room->saveMedia(eventId)) {
|
const auto url = mxcUrl.toStdString();
|
||||||
imgDialog->show();
|
|
||||||
} else {
|
http::client()->download(url,
|
||||||
imgDialog->close();
|
[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
|
void
|
||||||
|
@ -60,8 +60,9 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
|
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
|
||||||
bool isWindowFocused() const { return isWindowFocused_; }
|
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 openImagePackSettings(QString roomid);
|
||||||
|
Q_INVOKABLE void saveMedia(QString mxcUrl);
|
||||||
Q_INVOKABLE QColor userColor(QString id, QColor background);
|
Q_INVOKABLE QColor userColor(QString id, QColor background);
|
||||||
Q_INVOKABLE QString escapeEmoji(QString str) const;
|
Q_INVOKABLE QString escapeEmoji(QString str) const;
|
||||||
Q_INVOKABLE QString htmlEscape(QString str) const { return str.toHtmlEscaped(); }
|
Q_INVOKABLE QString htmlEscape(QString str) const { return str.toHtmlEscaped(); }
|
||||||
@ -85,13 +86,13 @@ signals:
|
|||||||
void narrowViewChanged();
|
void narrowViewChanged();
|
||||||
void focusChanged();
|
void focusChanged();
|
||||||
void focusInput();
|
void focusInput();
|
||||||
void openImageOverlayInternalCb(QString eventId, QImage img);
|
|
||||||
void openRoomMembersDialog(MemberList *members, TimelineModel *room);
|
void openRoomMembersDialog(MemberList *members, TimelineModel *room);
|
||||||
void openRoomSettingsDialog(RoomSettings *settings);
|
void openRoomSettingsDialog(RoomSettings *settings);
|
||||||
void openInviteUsersDialog(InviteesModel *invitees);
|
void openInviteUsersDialog(InviteesModel *invitees);
|
||||||
void openProfile(UserProfile *profile);
|
void openProfile(UserProfile *profile);
|
||||||
void showImagePackSettings(TimelineModel *room, ImagePackListModel *packlist);
|
void showImagePackSettings(TimelineModel *room, ImagePackListModel *packlist);
|
||||||
void openLeaveRoomDialog(QString roomid);
|
void openLeaveRoomDialog(QString roomid);
|
||||||
|
void showImageOverlay(TimelineModel *room, QString eventId, QString url);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
||||||
@ -120,9 +121,6 @@ public slots:
|
|||||||
|
|
||||||
RoomlistModel *rooms() { return rooms_; }
|
RoomlistModel *rooms() { return rooms_; }
|
||||||
|
|
||||||
private slots:
|
|
||||||
void openImageOverlayInternal(QString eventId, QImage img);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef USE_QUICK_VIEW
|
#ifdef USE_QUICK_VIEW
|
||||||
QQuickView *view;
|
QQuickView *view;
|
||||||
|
@ -20,10 +20,12 @@
|
|||||||
void
|
void
|
||||||
MxcAnimatedImage::startDownload()
|
MxcAnimatedImage::startDownload()
|
||||||
{
|
{
|
||||||
|
nhlog::ui()->debug("START DOWNLOAD!!!");
|
||||||
if (!room_)
|
if (!room_)
|
||||||
return;
|
return;
|
||||||
if (eventId_.isEmpty())
|
if (eventId_.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
nhlog::ui()->debug("START DOWNLOAD2!!!");
|
||||||
|
|
||||||
auto event = room_->eventById(eventId_);
|
auto event = room_->eventById(eventId_);
|
||||||
if (!event) {
|
if (!event) {
|
||||||
@ -92,7 +94,9 @@ MxcAnimatedImage::startDownload()
|
|||||||
"Playing movie with size: {}, {}", buffer.bytesAvailable(), buffer.isOpen());
|
"Playing movie with size: {}, {}", buffer.bytesAvailable(), buffer.isOpen());
|
||||||
movie.setFormat(mimeType);
|
movie.setFormat(mimeType);
|
||||||
movie.setDevice(&buffer);
|
movie.setDevice(&buffer);
|
||||||
movie.setScaledSize(this->size().toSize());
|
|
||||||
|
if (height() != 0 && width() != 0)
|
||||||
|
movie.setScaledSize(this->size().toSize());
|
||||||
if (buffer.bytesAvailable() <
|
if (buffer.bytesAvailable() <
|
||||||
4LL * 1024 * 1024 * 1024) // cache images smaller than 4MB in RAM
|
4LL * 1024 * 1024 * 1024) // cache images smaller than 4MB in RAM
|
||||||
movie.setCacheMode(QMovie::CacheAll);
|
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 *
|
QSGNode *
|
||||||
MxcAnimatedImage::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
|
MxcAnimatedImage::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
|
||||||
{
|
{
|
||||||
@ -171,8 +186,8 @@ MxcAnimatedImage::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeD
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
n->setRect(QRect(0, 0, width(), height()));
|
n->setRect(0, 0, width(), height());
|
||||||
n->setFiltering(QSGTexture::Nearest);
|
n->setFiltering(QSGTexture::Linear);
|
||||||
n->setMipmapFiltering(QSGTexture::None);
|
n->setMipmapFiltering(QSGTexture::None);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
|
@ -60,6 +60,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
|
||||||
QSGNode *updatePaintNode(QSGNode *oldNode,
|
QSGNode *updatePaintNode(QSGNode *oldNode,
|
||||||
QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;
|
QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user