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