File indexing completed on 2024-05-12 16:28:11
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 #include "account/abstractaccount.h" 0007 #include "timelinemodel.h" 0008 #include <KLocalizedString> 0009 #include <QJsonObject> 0010 #include <qstringliteral.h> 0011 0012 ThreadModel::ThreadModel(QObject *parent) 0013 : TimelineModel(parent) 0014 { 0015 init(); 0016 } 0017 0018 QVariant ThreadModel::data(const QModelIndex &index, int role) const 0019 { 0020 if (role == SelectedRole) { 0021 return m_postId == TimelineModel::data(index, IdRole).toString(); 0022 } 0023 0024 return TimelineModel::data(index, role); 0025 } 0026 0027 QString ThreadModel::displayName() const 0028 { 0029 return i18nc("@title", "Thread"); 0030 } 0031 0032 QString ThreadModel::postId() const 0033 { 0034 return m_postId; 0035 } 0036 0037 void ThreadModel::setPostId(const QString &postId) 0038 { 0039 if (m_postId == postId) { 0040 return; 0041 } 0042 m_postId = postId; 0043 Q_EMIT postIdChanged(); 0044 0045 fillTimeline(); 0046 } 0047 0048 void ThreadModel::fillTimeline(const QString &fromId) 0049 { 0050 Q_UNUSED(fromId) 0051 0052 if (m_postId.isNull() || m_postId.isEmpty()) { 0053 return; 0054 } 0055 0056 setLoading(true); 0057 0058 if (!m_account) { 0059 m_account = AccountManager::instance().selectedAccount(); 0060 } 0061 0062 const auto statusUrl = m_account->apiUrl(QString("/api/v1/statuses/%1").arg(m_postId)); 0063 const auto contextUrl = m_account->apiUrl(QString("/api/v1/statuses/%1/context").arg(m_postId)); 0064 auto thread = std::make_shared<QList<Post *>>(); 0065 0066 auto handleError = [this](QNetworkReply *reply) { 0067 Q_UNUSED(reply); 0068 setLoading(false); 0069 }; 0070 0071 auto onFetchContext = [=](QNetworkReply *reply) { 0072 const auto data = reply->readAll(); 0073 const auto doc = QJsonDocument::fromJson(data); 0074 const auto obj = doc.object(); 0075 0076 if (!doc.isObject()) { 0077 return; 0078 } 0079 0080 auto ancestors = obj["ancestors"].toArray().toVariantList(); 0081 std::reverse(ancestors.begin(), ancestors.end()); 0082 0083 for (const auto &ancestor : ancestors) { 0084 if (ancestor.canConvert<QJsonObject>() || ancestor.canConvert<QVariantMap>()) { 0085 thread->push_front(new Post(m_account, ancestor.toJsonObject(), this)); 0086 } 0087 } 0088 0089 const auto descendents = obj["descendants"].toArray(); 0090 0091 for (const auto &descendent : descendents) { 0092 if (!descendent.isObject()) { 0093 continue; 0094 } 0095 0096 thread->push_back(new Post(m_account, descendent.toObject(), this)); 0097 } 0098 0099 beginResetModel(); 0100 m_timeline = *thread; 0101 endResetModel(); 0102 setLoading(false); 0103 }; 0104 0105 auto onFetchStatus = [=](QNetworkReply *reply) { 0106 const auto data = reply->readAll(); 0107 const auto doc = QJsonDocument::fromJson(data); 0108 const auto obj = doc.object(); 0109 0110 if (!doc.isObject()) { 0111 return; 0112 } 0113 thread->push_front(new Post(m_account, obj, this)); 0114 m_account->get(contextUrl, true, this, onFetchContext, handleError); 0115 }; 0116 0117 m_account->get(statusUrl, true, this, onFetchStatus, handleError); 0118 } 0119 0120 bool ThreadModel::canFetchMore(const QModelIndex &parent) const 0121 { 0122 Q_UNUSED(parent); 0123 return false; 0124 }