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"