File indexing completed on 2024-05-12 16:28:11

0001 // SPDX-FileCopyrightText: 2023 Shubham Arora <shubhamarora@protonmail.com>
0002 // SPDX-License-Identifier: GPL-3.0-only
0003 
0004 #include "tagsmodel.h"
0005 #include <KLocalizedString>
0006 #include <QJsonArray>
0007 #include <QUrlQuery>
0008 #include <QtMath>
0009 #include <algorithm>
0010 
0011 TagsModel::TagsModel(QObject *parent)
0012     : AbstractListModel(parent)
0013 {
0014     connect(this, &AbstractListModel::nameChanged, this, &TagsModel::onNameChanged);
0015 }
0016 
0017 void TagsModel::onNameChanged()
0018 {
0019     fillTimeline();
0020 }
0021 
0022 QString TagsModel::displayName() const
0023 {
0024     return i18n("Trending");
0025 }
0026 
0027 void TagsModel::fetchMore(const QModelIndex &parent)
0028 {
0029     Q_UNUSED(parent);
0030     if (shouldLoadMore()) {
0031         fillTimeline();
0032     } else {
0033         setShouldLoadMore(true);
0034     }
0035 }
0036 
0037 bool TagsModel::canFetchMore(const QModelIndex &parent) const
0038 {
0039     Q_UNUSED(parent);
0040     return !m_next.isEmpty();
0041 }
0042 
0043 void TagsModel::fillTimeline(const QString &fromId)
0044 {
0045     Q_UNUSED(fromId);
0046 
0047     if (!account() || loading() || name() != "trending") {
0048         return;
0049     }
0050 
0051     QUrlQuery q;
0052     q.addQueryItem("limit", "20");
0053     QUrl uri;
0054     if (m_next.isEmpty()) {
0055         if (name() == "trending") {
0056             uri = account()->apiUrl("/api/v1/trends/tags");
0057             uri.setQuery(q);
0058         }
0059     } else {
0060         uri = m_next;
0061     }
0062 
0063     setLoading(true);
0064     account()->get(
0065         uri,
0066         false,
0067         this,
0068         [this, uri](QNetworkReply *reply) {
0069             const auto data = reply->readAll();
0070             const auto doc = QJsonDocument::fromJson(data);
0071             if (!doc.isArray()) {
0072                 return;
0073             }
0074             static QRegularExpression re("<(.*)>; rel=\"next\"");
0075             const auto next = reply->rawHeader(QByteArrayLiteral("Link"));
0076             const auto match = re.match(next);
0077             m_next = QUrl::fromUserInput(match.captured(1));
0078             const auto values = doc.array();
0079 
0080             QList<Tag> tags;
0081             std::transform(values.cbegin(), values.cend(), std::back_inserter(tags), [](const QJsonValue &value) {
0082                 return Tag(value.toObject());
0083             });
0084 
0085             beginInsertRows({}, m_tags.size(), m_tags.size() + tags.size() - 1);
0086             m_tags += tags;
0087             endInsertRows();
0088             setLoading(false);
0089         },
0090         [this](QNetworkReply *reply) {
0091             Q_UNUSED(reply);
0092             setLoading(false);
0093         });
0094 }
0095 
0096 QHash<int, QByteArray> TagsModel::roleNames() const
0097 {
0098     return {
0099         {CustomRoles::NameRole, "name"},
0100         {CustomRoles::UrlRole, "url"},
0101         {CustomRoles::HistoryRole, "history"},
0102     };
0103 }
0104 
0105 QVariant TagsModel::data(const QModelIndex &index, int role) const
0106 {
0107     Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid));
0108 
0109     switch (role) {
0110     case CustomRoles::NameRole:
0111         return m_tags[index.row()].name();
0112     case CustomRoles::UrlRole:
0113         return m_tags[index.row()].url();
0114     case CustomRoles::HistoryRole:
0115         return QVariant::fromValue<QList<History>>(m_tags[index.row()].history());
0116     default:
0117         return {};
0118     }
0119 }
0120 
0121 int TagsModel::rowCount(const QModelIndex &parent) const
0122 {
0123     Q_UNUSED(parent)
0124     return m_tags.size();
0125 }