diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/GridImagePackModel.cpp | 88 | ||||
-rw-r--r-- | src/GridImagePackModel.h | 72 | ||||
-rw-r--r-- | src/MainWindow.cpp | 2 | ||||
-rw-r--r-- | src/timeline/InputBar.cpp | 42 | ||||
-rw-r--r-- | src/timeline/InputBar.h | 2 | ||||
-rw-r--r-- | src/timeline/TimelineViewManager.cpp | 4 |
6 files changed, 194 insertions, 16 deletions
diff --git a/src/GridImagePackModel.cpp b/src/GridImagePackModel.cpp new file mode 100644 index 00000000..4fee086a --- /dev/null +++ b/src/GridImagePackModel.cpp @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "GridImagePackModel.h" + +#include "Cache_p.h" +#include "CompletionModelRoles.h" + +#include <algorithm> + +Q_DECLARE_METATYPE(StickerImage) + +GridImagePackModel::GridImagePackModel(const std::string &roomId, bool stickers, QObject *parent) + : QAbstractListModel(parent) + , room_id(roomId) +{ + [[maybe_unused]] static auto id = qRegisterMetaType<StickerImage>(); + + auto originalPacks = cache::client()->getImagePacks(room_id, stickers); + + for (auto &pack : originalPacks) { + PackDesc newPack{}; + newPack.packname = + pack.pack.pack ? QString::fromStdString(pack.pack.pack->display_name) : QString(); + newPack.room_id = pack.source_room; + newPack.state_key = pack.state_key; + + newPack.images.resize(pack.pack.images.size()); + std::ranges::transform(std::move(pack.pack.images), newPack.images.begin(), [](auto &&img) { + return std::pair(std::move(img.second), QString::fromStdString(img.first)); + }); + + size_t packRowCount = + (newPack.images.size() / columns) + (newPack.images.size() % columns ? 1 : 0); + newPack.firstRow = rowToPack.size(); + for (size_t i = 0; i < packRowCount; i++) + rowToPack.push_back(packs.size()); + packs.push_back(std::move(newPack)); + } +} + +int +GridImagePackModel::rowCount(const QModelIndex &) const +{ + return (int)rowToPack.size(); +} + +QHash<int, QByteArray> +GridImagePackModel::roleNames() const +{ + return { + {Roles::PackName, "packname"}, + {Roles::Row, "row"}, + }; +} + +QVariant +GridImagePackModel::data(const QModelIndex &index, int role) const +{ + if (index.row() < rowCount() && index.row() >= 0) { + const auto &pack = packs[rowToPack[index.row()]]; + switch (role) { + case Roles::PackName: + return pack.packname; + case Roles::Row: { + std::size_t offset = static_cast<std::size_t>(index.row()) - pack.firstRow; + QList<StickerImage> imgs; + auto endOffset = std::min((offset + 1) * 3, pack.images.size()); + for (std::size_t img = offset * 3; img < endOffset; img++) { + const auto &data = pack.images.at(img); + imgs.push_back({.url = QString::fromStdString(data.first.url), + .shortcode = data.second, + .body = QString::fromStdString(data.first.body), + .descriptor_ = std::vector{ + pack.room_id, + pack.state_key, + data.second.toStdString(), + }}); + } + return QVariant::fromValue(imgs); + } + default: + return {}; + } + } + return {}; +} diff --git a/src/GridImagePackModel.h b/src/GridImagePackModel.h new file mode 100644 index 00000000..1345b103 --- /dev/null +++ b/src/GridImagePackModel.h @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <QAbstractListModel> +#include <QObject> +#include <QString> + +#include <mtx/events/mscs/image_packs.hpp> + +struct StickerImage +{ + Q_GADGET + Q_PROPERTY(QString url MEMBER url CONSTANT) + Q_PROPERTY(QString shortcode MEMBER shortcode CONSTANT) + Q_PROPERTY(QString body MEMBER body CONSTANT) + Q_PROPERTY(QStringList descriptor READ descriptor CONSTANT) + +public: + QStringList descriptor() const + { + if (descriptor_.size() == 3) + return QStringList{ + QString::fromStdString(descriptor_[0]), + QString::fromStdString(descriptor_[1]), + QString::fromStdString(descriptor_[2]), + }; + else + return {}; + } + + QString url; + QString shortcode; + QString body; + + std::vector<std::string> descriptor_; // roomid, statekey, shortcode +}; + +class GridImagePackModel final : public QAbstractListModel +{ + Q_OBJECT +public: + enum Roles + { + PackName = Qt::UserRole, + Row, + }; + + GridImagePackModel(const std::string &roomId, bool stickers, QObject *parent = nullptr); + QHash<int, QByteArray> roleNames() const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + +private: + std::string room_id; + + struct PackDesc + { + QString packname; + QString packavatar; + std::string room_id, state_key; + + std::vector<std::pair<mtx::events::msc2545::PackImage, QString>> images; + std::size_t firstRow; + }; + + std::vector<PackDesc> packs; + std::vector<size_t> rowToPack; + int columns = 3; +}; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3ba40bb6..d9a03346 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -19,6 +19,7 @@ #include "CompletionProxyModel.h" #include "Config.h" #include "EventAccessors.h" +#include "GridImagePackModel.h" #include "ImagePackListModel.h" #include "InviteesModel.h" #include "JdenticonProvider.h" @@ -150,6 +151,7 @@ MainWindow::registerQmlTypes() qRegisterMetaType<mtx::responses::User>(); qRegisterMetaType<mtx::responses::Profile>(); qRegisterMetaType<CombinedImagePackModel *>(); + qRegisterMetaType<GridImagePackModel *>(); qRegisterMetaType<RoomSettingsAllowedRoomsModel *>(); qRegisterMetaType<mtx::events::collections::TimelineEvents>(); qRegisterMetaType<std::vector<DeviceInfo>>(); diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index dd6813c2..0c2e3752 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -836,28 +836,40 @@ InputBar::getCommandAndArgs(const QString ¤tText) const } void -InputBar::sticker(CombinedImagePackModel *model, int row) +InputBar::sticker(QStringList descriptor) { - if (!model || row < 0) + if (descriptor.size() != 3) return; - auto img = model->imageAt(row); + auto originalPacks = cache::client()->getImagePacks(room->roomId().toStdString(), true); - mtx::events::msg::StickerImage sticker{}; - sticker.info = img.info.value_or(mtx::common::ImageInfo{}); - sticker.url = img.url; - sticker.body = img.body.empty() ? model->shortcodeAt(row).toStdString() : img.body; + auto source_room = descriptor[0].toStdString(); + auto state_key = descriptor[1].toStdString(); + auto short_code = descriptor[2].toStdString(); - // workaround for https://github.com/vector-im/element-ios/issues/2353 - sticker.info.thumbnail_url = sticker.url; - sticker.info.thumbnail_info.mimetype = sticker.info.mimetype; - sticker.info.thumbnail_info.size = sticker.info.size; - sticker.info.thumbnail_info.h = sticker.info.h; - sticker.info.thumbnail_info.w = sticker.info.w; + for (auto &pack : originalPacks) { + if (pack.source_room == source_room && pack.state_key == state_key && + pack.pack.images.contains(short_code)) { + auto img = pack.pack.images.at(short_code); - sticker.relations = generateRelations(); + mtx::events::msg::StickerImage sticker{}; + sticker.info = img.info.value_or(mtx::common::ImageInfo{}); + sticker.url = img.url; + sticker.body = img.body.empty() ? short_code : img.body; - room->sendMessageEvent(sticker, mtx::events::EventType::Sticker); + // workaround for https://github.com/vector-im/element-ios/issues/2353 + sticker.info.thumbnail_url = sticker.url; + sticker.info.thumbnail_info.mimetype = sticker.info.mimetype; + sticker.info.thumbnail_info.size = sticker.info.size; + sticker.info.thumbnail_info.h = sticker.info.h; + sticker.info.thumbnail_info.w = sticker.info.w; + + sticker.relations = generateRelations(); + + room->sendMessageEvent(sticker, mtx::events::EventType::Sticker); + break; + } + } } bool diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index b2db377f..1f1d6fe1 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -217,7 +217,7 @@ public slots: MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED, bool rainbowify = false); void reaction(const QString &reactedEvent, const QString &reactionKey); - void sticker(CombinedImagePackModel *model, int row); + void sticker(QStringList descriptor); void acceptUploads(); void declineUploads(); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 44f288c6..4b171dc4 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -17,6 +17,7 @@ #include "CommandCompleter.h" #include "CompletionProxyModel.h" #include "EventAccessors.h" +#include "GridImagePackModel.h" #include "ImagePackListModel.h" #include "InviteesModel.h" #include "Logging.h" @@ -477,6 +478,9 @@ TimelineViewManager::completerFor(const QString &completerName, const QString &r auto proxy = new CompletionProxyModel(stickerModel, 1, static_cast<size_t>(-1) / 4); stickerModel->setParent(proxy); return proxy; + } else if (completerName == QLatin1String("stickergrid")) { + auto stickerModel = new GridImagePackModel(roomId.toStdString(), true); + return stickerModel; } else if (completerName == QLatin1String("customEmoji")) { auto stickerModel = new CombinedImagePackModel(roomId.toStdString(), false); auto proxy = new CompletionProxyModel(stickerModel); |