File indexing completed on 2024-05-12 05:04:15
0001 // SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu> 0002 // SPDX-License-Identifier: LGPL-2.0-or-later 0003 0004 #include "maintimelinemodel.h" 0005 0006 #include <KLocalizedString> 0007 0008 MainTimelineModel::MainTimelineModel(QObject *parent) 0009 : TimelineModel(parent) 0010 { 0011 init(); 0012 } 0013 0014 QString MainTimelineModel::name() const 0015 { 0016 return m_timelineName; 0017 } 0018 0019 QString MainTimelineModel::displayName() const 0020 { 0021 if (m_timelineName == QStringLiteral("home")) { 0022 return i18nc("@title", "Home"); 0023 } else if (m_timelineName == QStringLiteral("public")) { 0024 return i18nc("@title", "Local Timeline"); 0025 } else if (m_timelineName == QStringLiteral("federated")) { 0026 return i18nc("@title", "Global Timeline"); 0027 } else if (m_timelineName == QStringLiteral("bookmarks")) { 0028 return i18nc("@title", "Bookmarks"); 0029 } else if (m_timelineName == QStringLiteral("favourites")) { 0030 return i18nc("@title", "Favourites"); 0031 } else if (m_timelineName == QStringLiteral("trending")) { 0032 return i18nc("@title", "Trending"); 0033 } else if (m_timelineName == QStringLiteral("list")) { 0034 return m_listId; 0035 } 0036 0037 return {}; 0038 } 0039 0040 QString MainTimelineModel::listId() const 0041 { 0042 return m_listId; 0043 } 0044 0045 void MainTimelineModel::setListId(const QString &id) 0046 { 0047 if (m_listId == id) { 0048 return; 0049 } 0050 0051 m_listId = id; 0052 Q_EMIT listIdChanged(); 0053 0054 setLoading(false); 0055 fillTimeline({}); 0056 } 0057 0058 void MainTimelineModel::setName(const QString &timelineName) 0059 { 0060 if (timelineName == m_timelineName) { 0061 return; 0062 } 0063 0064 m_timelineName = timelineName; 0065 Q_EMIT nameChanged(); 0066 setLoading(false); 0067 fillTimeline({}); 0068 } 0069 0070 void MainTimelineModel::fillTimeline(const QString &from_id) 0071 { 0072 static const QSet<QString> validTimelines = {QStringLiteral("home"), 0073 QStringLiteral("public"), 0074 QStringLiteral("federated"), 0075 QStringLiteral("bookmarks"), 0076 QStringLiteral("favourites"), 0077 QStringLiteral("trending"), 0078 QStringLiteral("list")}; 0079 static const QSet<QString> publicTimelines = {QStringLiteral("home"), QStringLiteral("public"), QStringLiteral("federated")}; 0080 0081 if (!m_account || m_loading || !validTimelines.contains(m_timelineName)) { 0082 return; 0083 } 0084 0085 if (m_timelineName == QStringLiteral("list") && m_listId.isEmpty()) { 0086 return; 0087 } 0088 0089 setLoading(true); 0090 0091 const bool local = m_timelineName == QStringLiteral("public"); 0092 0093 QUrlQuery q; 0094 if (local) { 0095 q.addQueryItem(QStringLiteral("local"), QStringLiteral("true")); 0096 } 0097 if (!from_id.isEmpty()) { 0098 q.addQueryItem(QStringLiteral("max_id"), from_id); 0099 } 0100 0101 QUrl uri; 0102 if (m_timelineName == QStringLiteral("list")) { 0103 const QString apiUrl = QStringLiteral("/api/v1/timelines/list/%1").arg(m_listId); 0104 uri = m_account->apiUrl(apiUrl); 0105 uri.setQuery(q); 0106 } else if (publicTimelines.contains(m_timelineName)) { 0107 // federated timeline is really "public" without local set 0108 const QString apiUrl = 0109 QStringLiteral("/api/v1/timelines/%1").arg(m_timelineName == QStringLiteral("federated") ? QStringLiteral("public") : m_timelineName); 0110 uri = m_account->apiUrl(apiUrl); 0111 uri.setQuery(q); 0112 } else { 0113 // Fixes issues where on reaching the end the data is fetched from the start 0114 if (m_next.isEmpty() && !m_timeline.isEmpty()) { 0115 setLoading(false); 0116 return; 0117 } 0118 uri = m_next.isEmpty() ? m_account->apiUrl( 0119 QStringLiteral("/api/v1/%1").arg(m_timelineName == QStringLiteral("trending") ? QStringLiteral("trends/statuses") : m_timelineName)) 0120 : m_next; 0121 } 0122 0123 auto account = m_account; 0124 auto currentTimelineName = m_timelineName; 0125 m_account->get( 0126 uri, 0127 true, 0128 this, 0129 [this, currentTimelineName, account](QNetworkReply *reply) { 0130 if (m_account != account || m_timelineName != currentTimelineName) { 0131 setLoading(false); 0132 return; 0133 } 0134 0135 static QRegularExpression re(QStringLiteral("<(.*)>; rel=\"next\"")); 0136 const auto next = reply->rawHeader(QByteArrayLiteral("Link")); 0137 const auto match = re.match(QString::fromUtf8(next)); 0138 m_next = QUrl::fromUserInput(match.captured(1)); 0139 Q_EMIT atEndChanged(); 0140 0141 fetchedTimeline(reply->readAll(), !publicTimelines.contains(m_timelineName)); 0142 setLoading(false); 0143 }, 0144 [this](QNetworkReply *reply) { 0145 Q_UNUSED(reply) 0146 setLoading(false); 0147 }); 0148 } 0149 0150 void MainTimelineModel::handleEvent(AbstractAccount::StreamingEventType eventType, const QByteArray &payload) 0151 { 0152 TimelineModel::handleEvent(eventType, payload); 0153 if (eventType == AbstractAccount::StreamingEventType::UpdateEvent && m_timelineName == QStringLiteral("home")) { 0154 const auto doc = QJsonDocument::fromJson(payload); 0155 const auto post = new Post(m_account, doc.object(), this); 0156 beginInsertRows({}, 0, 0); 0157 m_timeline.push_front(post); 0158 endInsertRows(); 0159 } 0160 } 0161 0162 bool MainTimelineModel::atEnd() const 0163 { 0164 return m_next.isEmpty(); 0165 } 0166 0167 void MainTimelineModel::reset() 0168 { 0169 beginResetModel(); 0170 qDeleteAll(m_timeline); 0171 m_timeline.clear(); 0172 endResetModel(); 0173 m_next.clear(); 0174 } 0175 0176 #include "moc_maintimelinemodel.cpp"