// SPDX-FileCopyrightText: 2022 Carl Schwan // SPDX-License-Identifier: LGPL-2.0-or-later #include "timeline/maintimelinemodel.h" #include MainTimelineModel::MainTimelineModel(QObject *parent) : TimelineModel(parent) { init(); } QString MainTimelineModel::name() const { return m_timelineName; } QString MainTimelineModel::displayName() const { if (m_timelineName == QStringLiteral("home")) { return i18nc("@title", "Home"); } else if (m_timelineName == QStringLiteral("public")) { return i18nc("@title", "Local Timeline"); } else if (m_timelineName == QStringLiteral("federated")) { return i18nc("@title", "Global Timeline"); } else if (m_timelineName == QStringLiteral("bookmarks")) { return i18nc("@title", "Bookmarks"); } else if (m_timelineName == QStringLiteral("favourites")) { return i18nc("@title", "Favorites"); } else if (m_timelineName == QStringLiteral("trending")) { return i18nc("@title", "Trending"); } else if (m_timelineName == QStringLiteral("list")) { return m_listId; } return {}; } QString MainTimelineModel::listId() const { return m_listId; } void MainTimelineModel::setListId(const QString &id) { if (m_listId == id) { return; } m_listId = id; Q_EMIT listIdChanged(); setLoading(false); fillTimeline({}); } void MainTimelineModel::setName(const QString &timelineName) { if (timelineName == m_timelineName) { return; } m_timelineName = timelineName; Q_EMIT nameChanged(); setLoading(false); fillTimeline({}); } void MainTimelineModel::fillTimeline(const QString &from_id) { static const QSet validTimelines = {QStringLiteral("home"), QStringLiteral("public"), QStringLiteral("federated"), QStringLiteral("bookmarks"), QStringLiteral("favourites"), QStringLiteral("trending"), QStringLiteral("list")}; static const QSet publicTimelines = {QStringLiteral("home"), QStringLiteral("public"), QStringLiteral("federated")}; if (!m_account || m_loading || !validTimelines.contains(m_timelineName)) { return; } if (m_timelineName == QStringLiteral("list") && m_listId.isEmpty()) { return; } setLoading(true); const bool local = m_timelineName == QStringLiteral("public"); QUrlQuery q; if (local) { q.addQueryItem(QStringLiteral("local"), QStringLiteral("true")); } if (!from_id.isEmpty()) { q.addQueryItem(QStringLiteral("max_id"), from_id); } QUrl uri; if (m_timelineName == QStringLiteral("list")) { const QString apiUrl = QStringLiteral("/api/v1/timelines/list/%1").arg(m_listId); uri = m_account->apiUrl(apiUrl); uri.setQuery(q); } else if (publicTimelines.contains(m_timelineName)) { // federated timeline is really "public" without local set const QString apiUrl = QStringLiteral("/api/v1/timelines/%1").arg(m_timelineName == QStringLiteral("federated") ? QStringLiteral("public") : m_timelineName); uri = m_account->apiUrl(apiUrl); uri.setQuery(q); } else { // Fixes issues where on reaching the end the data is fetched from the start if (m_next.isEmpty() && !m_timeline.isEmpty()) { setLoading(false); return; } uri = m_next.isEmpty() ? m_account->apiUrl( QStringLiteral("/api/v1/%1").arg(m_timelineName == QStringLiteral("trending") ? QStringLiteral("trends/statuses") : m_timelineName)) : m_next; } auto account = m_account; auto currentTimelineName = m_timelineName; m_account->get( uri, true, this, [this, currentTimelineName, account](QNetworkReply *reply) { if (m_account != account || m_timelineName != currentTimelineName) { setLoading(false); return; } static QRegularExpression re(QStringLiteral("<(.*)>; rel=\"next\"")); const auto next = reply->rawHeader(QByteArrayLiteral("Link")); const auto match = re.match(QString::fromUtf8(next)); m_next = QUrl::fromUserInput(match.captured(1)); Q_EMIT atEndChanged(); fetchedTimeline(reply->readAll(), !publicTimelines.contains(m_timelineName)); setLoading(false); }, [this](QNetworkReply *reply) { Q_UNUSED(reply) setLoading(false); }); } void MainTimelineModel::handleEvent(AbstractAccount::StreamingEventType eventType, const QByteArray &payload) { TimelineModel::handleEvent(eventType, payload); if (eventType == AbstractAccount::StreamingEventType::UpdateEvent && m_timelineName == QStringLiteral("home")) { const auto doc = QJsonDocument::fromJson(payload); const auto post = new Post(m_account, doc.object(), this); beginInsertRows({}, 0, 0); m_timeline.push_front(post); endInsertRows(); } } bool MainTimelineModel::atEnd() const { return m_next.isEmpty(); } void MainTimelineModel::reset() { beginResetModel(); qDeleteAll(m_timeline); m_timeline.clear(); endResetModel(); m_next.clear(); } #include "moc_maintimelinemodel.cpp"