summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2019-09-07 22:22:07 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2019-11-23 20:06:14 +0100
commitebeb1eb7721f357b016f6e914509918b6bee5356 (patch)
tree57ab5d3588cf6d01b497cba762056ea132044cf6 /src
parentFix new messages not arriving in qml timeline (diff)
downloadnheko-ebeb1eb7721f357b016f6e914509918b6bee5356.tar.xz
Implement avatars in qml timeline
Diffstat (limited to 'src')
-rw-r--r--src/MxcImageProvider.cpp79
-rw-r--r--src/MxcImageProvider.h48
-rw-r--r--src/RoomInfoListItem.cpp2
-rw-r--r--src/UserSettingsPage.cpp6
-rw-r--r--src/timeline2/TimelineModel.cpp6
-rw-r--r--src/timeline2/TimelineModel.h1
-rw-r--r--src/timeline2/TimelineViewManager.cpp2
-rw-r--r--src/ui/Avatar.cpp2
8 files changed, 140 insertions, 6 deletions
diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp
new file mode 100644

index 00000000..305439fc --- /dev/null +++ b/src/MxcImageProvider.cpp
@@ -0,0 +1,79 @@ +#include "MxcImageProvider.h" + +#include "Cache.h" + +void +MxcImageResponse::run() +{ + if (m_requestedSize.isValid()) { + QString fileName = QString("%1_%2x%3") + .arg(m_id) + .arg(m_requestedSize.width()) + .arg(m_requestedSize.height()); + + auto data = cache::client()->image(fileName); + if (!data.isNull() && m_image.loadFromData(data)) { + m_image = m_image.scaled(m_requestedSize, Qt::KeepAspectRatio); + m_image.setText("mxc url", "mxc://" + m_id); + emit finished(); + return; + } + + mtx::http::ThumbOpts opts; + opts.mxc_url = "mxc://" + m_id.toStdString(); + opts.width = m_requestedSize.width() > 0 ? m_requestedSize.width() : -1; + opts.height = m_requestedSize.height() > 0 ? m_requestedSize.height() : -1; + opts.method = "scale"; + http::client()->get_thumbnail( + opts, [this, fileName](const std::string &res, mtx::http::RequestErr err) { + if (err) { + nhlog::net()->error("Failed to download image {}", + m_id.toStdString()); + m_error = "Failed download"; + emit finished(); + + return; + } + + auto data = QByteArray(res.data(), res.size()); + cache::client()->saveImage(fileName, data); + m_image.loadFromData(data); + m_image = m_image.scaled(m_requestedSize, Qt::KeepAspectRatio); + m_image.setText("mxc url", "mxc://" + m_id); + + emit finished(); + }); + } else { + auto data = cache::client()->image(m_id); + if (!data.isNull() && m_image.loadFromData(data)) { + m_image.setText("mxc url", "mxc://" + m_id); + emit finished(); + return; + } + + http::client()->download( + "mxc://" + m_id.toStdString(), + [this](const std::string &res, + const std::string &, + const std::string &originalFilename, + mtx::http::RequestErr err) { + if (err) { + nhlog::net()->error("Failed to download image {}", + m_id.toStdString()); + m_error = "Failed download"; + emit finished(); + + return; + } + + auto data = QByteArray(res.data(), res.size()); + m_image.loadFromData(data); + m_image.setText("original filename", + QString::fromStdString(originalFilename)); + m_image.setText("mxc url", "mxc://" + m_id); + cache::client()->saveImage(m_id, data); + + emit finished(); + }); + } +} diff --git a/src/MxcImageProvider.h b/src/MxcImageProvider.h new file mode 100644
index 00000000..8710171c --- /dev/null +++ b/src/MxcImageProvider.h
@@ -0,0 +1,48 @@ +#pragma once + +#include <QQuickAsyncImageProvider> +#include <QQuickImageResponse> + +#include <QImage> +#include <QThreadPool> + +class MxcImageResponse + : public QQuickImageResponse + , public QRunnable +{ +public: + MxcImageResponse(const QString &id, const QSize &requestedSize) + : m_id(id) + , m_requestedSize(requestedSize) + { + setAutoDelete(false); + } + + QQuickTextureFactory *textureFactory() const override + { + return QQuickTextureFactory::textureFactoryForImage(m_image); + } + QString errorString() const override { return m_error; } + + void run() override; + + QString m_id, m_error; + QSize m_requestedSize; + QImage m_image; +}; + +class MxcImageProvider : public QQuickAsyncImageProvider +{ +public: + QQuickImageResponse *requestImageResponse(const QString &id, + const QSize &requestedSize) override + { + MxcImageResponse *response = new MxcImageResponse(id, requestedSize); + pool.start(response); + return response; + } + +private: + QThreadPool pool; +}; + diff --git a/src/RoomInfoListItem.cpp b/src/RoomInfoListItem.cpp
index 8aadbea2..f135451c 100644 --- a/src/RoomInfoListItem.cpp +++ b/src/RoomInfoListItem.cpp
@@ -142,7 +142,7 @@ RoomInfoListItem::resizeEvent(QResizeEvent *) void RoomInfoListItem::paintEvent(QPaintEvent *event) { - bool rounded = QSettings().value("user/avatar/circles", true).toBool(); + bool rounded = QSettings().value("user/avatar_circles", true).toBool(); Q_UNUSED(event); diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index 9fd033e9..1caea449 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp
@@ -53,7 +53,7 @@ UserSettings::load() isReadReceiptsEnabled_ = settings.value("user/read_receipts", true).toBool(); theme_ = settings.value("user/theme", defaultTheme_).toString(); font_ = settings.value("user/font_family", "default").toString(); - avatarCircles_ = settings.value("user/avatar/circles", true).toBool(); + avatarCircles_ = settings.value("user/avatar_circles", true).toBool(); emojiFont_ = settings.value("user/emoji_font_family", "default").toString(); baseFontSize_ = settings.value("user/font_size", QFont().pointSizeF()).toDouble(); @@ -119,9 +119,7 @@ UserSettings::save() settings.setValue("start_in_tray", isStartInTrayEnabled_); settings.endGroup(); - settings.beginGroup("avatar"); - settings.setValue("circles", avatarCircles_); - settings.endGroup(); + settings.setValue("avatar_circles", avatarCircles_); settings.setValue("font_size", baseFontSize_); settings.setValue("typing_notifications", isTypingNotificationsEnabled_); diff --git a/src/timeline2/TimelineModel.cpp b/src/timeline2/TimelineModel.cpp
index 28820205..310494b4 100644 --- a/src/timeline2/TimelineModel.cpp +++ b/src/timeline2/TimelineModel.cpp
@@ -326,6 +326,12 @@ TimelineModel::displayName(QString id) const } QString +TimelineModel::avatarUrl(QString id) const +{ + return Cache::avatarUrl(room_id_, id); +} + +QString TimelineModel::formatDateSeparator(QDate date) const { auto now = QDateTime::currentDateTime(); diff --git a/src/timeline2/TimelineModel.h b/src/timeline2/TimelineModel.h
index e37c6542..954da5eb 100644 --- a/src/timeline2/TimelineModel.h +++ b/src/timeline2/TimelineModel.h
@@ -90,6 +90,7 @@ public: Q_INVOKABLE QColor userColor(QString id, QColor background); Q_INVOKABLE QString displayName(QString id) const; + Q_INVOKABLE QString avatarUrl(QString id) const; Q_INVOKABLE QString formatDateSeparator(QDate date) const; Q_INVOKABLE QString escapeEmoji(QString str) const; diff --git a/src/timeline2/TimelineViewManager.cpp b/src/timeline2/TimelineViewManager.cpp
index 0e0e74e4..eb9bea54 100644 --- a/src/timeline2/TimelineViewManager.cpp +++ b/src/timeline2/TimelineViewManager.cpp
@@ -4,6 +4,7 @@ #include <QQmlContext> #include "Logging.h" +#include "MxcImageProvider.h" TimelineViewManager::TimelineViewManager(QWidget *parent) { @@ -18,6 +19,7 @@ TimelineViewManager::TimelineViewManager(QWidget *parent) container = QWidget::createWindowContainer(view, parent); container->setMinimumSize(200, 200); view->rootContext()->setContextProperty("timelineManager", this); + view->engine()->addImageProvider("MxcImage", new MxcImageProvider()); view->setSource(QUrl("qrc:///qml/TimelineView.qml")); } diff --git a/src/ui/Avatar.cpp b/src/ui/Avatar.cpp
index 501a8968..e4a90f81 100644 --- a/src/ui/Avatar.cpp +++ b/src/ui/Avatar.cpp
@@ -101,7 +101,7 @@ Avatar::setIcon(const QIcon &icon) void Avatar::paintEvent(QPaintEvent *) { - bool rounded = QSettings().value("user/avatar/circles", true).toBool(); + bool rounded = QSettings().value("user/avatar_circles", true).toBool(); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing);