File indexing completed on 2024-10-06 04:33:33

0001 // SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 #pragma once
0005 
0006 #include <QAbstractListModel>
0007 #include <QQmlEngine>
0008 #include <QRegularExpression>
0009 
0010 #include "neochatconnection.h"
0011 
0012 struct CustomEmoji {
0013     QString name; // with :semicolons:
0014     QString url; // mxc://
0015     QRegularExpression regexp;
0016 
0017     Q_GADGET
0018     Q_PROPERTY(QString unicode MEMBER url)
0019     Q_PROPERTY(QString name MEMBER name)
0020 };
0021 
0022 /**
0023  * @class CustomEmojiModel
0024  *
0025  * This class defines the model for custom user emojis.
0026  *
0027  * This is based upon the im.ponies.user_emotes spec (MSC2545).
0028  */
0029 class CustomEmojiModel : public QAbstractListModel
0030 {
0031     Q_OBJECT
0032     QML_ELEMENT
0033     QML_SINGLETON
0034 
0035     Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
0036 
0037 public:
0038     /**
0039      * @brief Defines the model roles.
0040      */
0041     enum Roles {
0042         Name = Qt::DisplayRole, /**< The name of the emoji. */
0043         ImageURL, /**< The URL for the custom emoji. */
0044         ModelData, /**< for emulating the regular emoji model's usage, otherwise the UI code would get too complicated. */
0045         MxcUrl = 50, /**< The mxc source URL for the custom emoji. */
0046         DisplayRole = 51, /**< The name of the emoji. For compatibility with EmojiModel. */
0047         ReplacedTextRole = 52, /**< The name of the emoji. For compatibility with EmojiModel. */
0048         DescriptionRole = 53, /**< Invalid, reserved. For compatibility with EmojiModel. */
0049     };
0050     Q_ENUM(Roles)
0051 
0052     static CustomEmojiModel &instance()
0053     {
0054         static CustomEmojiModel _instance;
0055         return _instance;
0056     }
0057     static CustomEmojiModel *create(QQmlEngine *engine, QJSEngine *)
0058     {
0059         engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
0060         return &instance();
0061     }
0062 
0063     /**
0064      * @brief Get the given role value at the given index.
0065      *
0066      * @sa QAbstractItemModel::data
0067      */
0068     QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
0069 
0070     /**
0071      * @brief Number of rows in the model.
0072      *
0073      * @sa  QAbstractItemModel::rowCount
0074      */
0075     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0076 
0077     /**
0078      * @brief Returns a mapping from Role enum values to role names.
0079      *
0080      * @sa Roles, QAbstractItemModel::roleNames()
0081      */
0082     QHash<int, QByteArray> roleNames() const override;
0083 
0084     /**
0085      * @brief Substitute any custom emojis for an image in the input text.
0086      */
0087     Q_INVOKABLE QString preprocessText(QString text);
0088 
0089     /**
0090      * @brief Return a list of custom emojis where the name contains the filter text.
0091      */
0092     Q_INVOKABLE QVariantList filterModel(const QString &filter);
0093 
0094     /**
0095      * @brief Add a new emoji to the model.
0096      */
0097     Q_INVOKABLE void addEmoji(const QString &name, const QUrl &location);
0098 
0099     /**
0100      * @brief Remove an emoji from the model.
0101      */
0102     Q_INVOKABLE void removeEmoji(const QString &name);
0103 
0104     void setConnection(NeoChatConnection *connection);
0105     NeoChatConnection *connection() const;
0106 
0107 Q_SIGNALS:
0108     void connectionChanged();
0109 
0110 private:
0111     explicit CustomEmojiModel(QObject *parent = nullptr);
0112     QList<CustomEmoji> m_emojis;
0113     NeoChatConnection *m_connection = nullptr;
0114 
0115     void fetchEmojis();
0116 };