File indexing completed on 2024-05-12 05:04:17

0001 // SPDX-FileCopyrightText: 2021 kaniini <https://git.pleroma.social/kaniini>
0002 // SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
0003 // SPDX-License-Identifier: GPL-3.0-only
0004 
0005 #include "threadmodel.h"
0006 
0007 #include <KLocalizedString>
0008 
0009 using namespace Qt::Literals::StringLiterals;
0010 
0011 ThreadModel::ThreadModel(QObject *parent)
0012     : TimelineModel(parent)
0013 {
0014     init();
0015 }
0016 
0017 QVariant ThreadModel::data(const QModelIndex &index, int role) const
0018 {
0019     if (role == SelectedRole) {
0020         return m_postId == TimelineModel::data(index, IdRole).toString();
0021     }
0022 
0023     return TimelineModel::data(index, role);
0024 }
0025 
0026 QString ThreadModel::displayName() const
0027 {
0028     return i18nc("@title", "Thread");
0029 }
0030 
0031 QString ThreadModel::postId() const
0032 {
0033     return m_postId;
0034 }
0035 
0036 void ThreadModel::setPostId(const QString &postId)
0037 {
0038     if (m_postId == postId) {
0039         return;
0040     }
0041     m_postId = postId;
0042     Q_EMIT postIdChanged();
0043 
0044     fillTimeline();
0045 }
0046 
0047 void ThreadModel::fillTimeline(const QString &fromId)
0048 {
0049     Q_UNUSED(fromId)
0050 
0051     if (m_postId.isNull() || m_postId.isEmpty()) {
0052         return;
0053     }
0054 
0055     setLoading(true);
0056 
0057     if (!m_account) {
0058         m_account = AccountManager::instance().selectedAccount();
0059     }
0060 
0061     const auto statusUrl = m_account->apiUrl(QStringLiteral("/api/v1/statuses/%1").arg(m_postId));
0062     const auto contextUrl = m_account->apiUrl(QStringLiteral("/api/v1/statuses/%1/context").arg(m_postId));
0063     auto thread = std::make_shared<QList<Post *>>();
0064 
0065     auto handleError = [this](QNetworkReply *reply) {
0066         Q_UNUSED(reply);
0067         setLoading(false);
0068     };
0069 
0070     auto onFetchContext = [=](QNetworkReply *reply) {
0071         const auto data = reply->readAll();
0072         const auto doc = QJsonDocument::fromJson(data);
0073         const auto obj = doc.object();
0074 
0075         if (!doc.isObject()) {
0076             return;
0077         }
0078 
0079         auto ancestors = obj["ancestors"_L1].toArray().toVariantList();
0080         std::reverse(ancestors.begin(), ancestors.end());
0081 
0082         for (const auto &ancestor : ancestors) {
0083             if (ancestor.canConvert<QJsonObject>() || ancestor.canConvert<QVariantMap>()) {
0084                 thread->push_front(new Post(m_account, ancestor.toJsonObject(), this));
0085             }
0086         }
0087 
0088         const auto descendents = obj["descendants"_L1].toArray();
0089 
0090         for (const auto &descendent : descendents) {
0091             if (!descendent.isObject()) {
0092                 continue;
0093             }
0094 
0095             thread->push_back(new Post(m_account, descendent.toObject(), this));
0096         }
0097 
0098         beginResetModel();
0099         m_timeline = *thread;
0100         endResetModel();
0101         setLoading(false);
0102     };
0103 
0104     auto onFetchStatus = [=](QNetworkReply *reply) {
0105         const auto data = reply->readAll();
0106         const auto doc = QJsonDocument::fromJson(data);
0107         const auto obj = doc.object();
0108 
0109         if (!doc.isObject()) {
0110             return;
0111         }
0112         thread->push_front(new Post(m_account, obj, this));
0113         m_account->get(contextUrl, true, this, onFetchContext, handleError);
0114     };
0115 
0116     m_account->get(statusUrl, true, this, onFetchStatus, handleError);
0117 }
0118 
0119 bool ThreadModel::canFetchMore(const QModelIndex &parent) const
0120 {
0121     Q_UNUSED(parent);
0122     return false;
0123 }
0124 
0125 int ThreadModel::getRootIndex() const
0126 {
0127     for (int i = 0; i < rowCount({}); i++) {
0128         if (data(index(i, 0), SelectedRole).toBool()) {
0129             return i;
0130         }
0131     }
0132 
0133     return -1;
0134 }
0135 
0136 void ThreadModel::reset()
0137 {
0138     beginResetModel();
0139     qDeleteAll(m_timeline);
0140     m_timeline.clear();
0141     endResetModel();
0142 }
0143 
0144 void ThreadModel::refresh()
0145 {
0146     reset();
0147     fillTimeline();
0148 }
0149 
0150 #include "moc_threadmodel.cpp"