File indexing completed on 2024-05-12 05:04:14

0001 // SPDX-FileCopyrightText: 2022 Carl Schwan <carlschwan@kde.org>
0002 // SPDX-License-Identifier: LGPL-2.0-or-later
0003 
0004 #include "searchmodel.h"
0005 
0006 #include "account.h"
0007 
0008 #include <KLocalizedString>
0009 
0010 using namespace Qt::Literals::StringLiterals;
0011 
0012 SearchModel::SearchModel(QObject *parent)
0013     : AbstractTimelineModel(parent)
0014 {
0015     m_account = AccountManager::instance().selectedAccount();
0016 
0017     connect(&AccountManager::instance(), &AccountManager::invalidated, this, [=](AbstractAccount *account) {
0018         if (m_account == account) {
0019             beginResetModel();
0020             clear();
0021             endResetModel();
0022         }
0023     });
0024 
0025     connect(&AccountManager::instance(), &AccountManager::accountSelected, this, [=](AbstractAccount *account) {
0026         if (m_account != account) {
0027             m_account = account;
0028             beginResetModel();
0029             clear();
0030             endResetModel();
0031         }
0032     });
0033 }
0034 
0035 SearchModel::~SearchModel() = default;
0036 
0037 void SearchModel::search(const QString &queryString)
0038 {
0039     beginResetModel();
0040     clear();
0041     endResetModel();
0042 
0043     auto url = m_account->apiUrl(QStringLiteral("/api/v2/search"));
0044     url.setQuery({{QStringLiteral("q"), queryString}});
0045     setLoading(true);
0046     setLoaded(false);
0047     m_account->get(url, true, this, [this](QNetworkReply *reply) {
0048         const auto searchResult = QJsonDocument::fromJson(reply->readAll()).object();
0049         const auto statuses = searchResult[QStringLiteral("statuses")].toArray();
0050 
0051         beginResetModel();
0052         clear();
0053 
0054         std::transform(
0055             statuses.cbegin(),
0056             statuses.cend(),
0057             std::back_inserter(m_statuses),
0058             [this](const QJsonValue &value) -> auto{ return new Post(m_account, value.toObject(), this); });
0059         const auto accounts = searchResult[QStringLiteral("accounts")].toArray();
0060         std::transform(
0061             accounts.cbegin(),
0062             accounts.cend(),
0063             std::back_inserter(m_accounts),
0064             [this](const QJsonValue &value) -> auto{
0065                 const auto account = value.toObject();
0066                 return m_account->identityLookup(account["id"_L1].toString(), account);
0067             });
0068         const auto hashtags = searchResult[QStringLiteral("hashtags")].toArray();
0069         std::transform(
0070             hashtags.cbegin(),
0071             hashtags.cend(),
0072             std::back_inserter(m_hashtags),
0073             [](const QJsonValue &value) -> auto{ return SearchHashtag(value.toObject()); });
0074         endResetModel();
0075         setLoading(false);
0076         setLoaded(true);
0077     });
0078 }
0079 
0080 int SearchModel::rowCount(const QModelIndex &parent) const
0081 {
0082     Q_UNUSED(parent);
0083 
0084     return m_accounts.count() + m_statuses.count() + m_hashtags.count();
0085 }
0086 
0087 QVariant SearchModel::data(const QModelIndex &index, int role) const
0088 {
0089     const auto row = index.row();
0090 
0091     const bool isStatus = row >= m_accounts.count() && row < m_accounts.count() + m_statuses.size();
0092     const bool isHashtag = row >= m_accounts.size() + m_statuses.count();
0093 
0094     if (role == TypeRole) {
0095         if (isHashtag) {
0096             return Hashtag;
0097         } else if (isStatus) {
0098             return Status;
0099         } else {
0100             return Account;
0101         }
0102     }
0103 
0104     if (isStatus) {
0105         const auto post = m_statuses[row - m_accounts.count()];
0106         return postData(post, role);
0107     }
0108 
0109     if (isHashtag) {
0110         const auto hashtag = m_hashtags[row - m_accounts.count() - m_statuses.count()];
0111         switch (role) {
0112         case IdRole:
0113             return hashtag.getName();
0114         }
0115     }
0116 
0117     const auto identity = m_accounts[row];
0118     switch (role) {
0119     case AuthorIdentityRole:
0120         return QVariant::fromValue<Identity *>(identity.get());
0121     }
0122 
0123     return {};
0124 }
0125 
0126 void SearchModel::clear()
0127 {
0128     m_accounts.clear();
0129     qDeleteAll(m_statuses);
0130     m_statuses.clear();
0131     m_hashtags.clear();
0132     setLoading(false);
0133     setLoaded(false);
0134 }
0135 
0136 QString SearchModel::labelForType(ResultType sectionType)
0137 {
0138     switch (sectionType) {
0139     case Account:
0140         return i18n("Users");
0141     case Hashtag:
0142         return i18n("Hashtags");
0143     case Status:
0144         return i18n("Posts");
0145     default:
0146         return {};
0147     }
0148 }
0149 
0150 bool SearchModel::loaded() const
0151 {
0152     return m_loaded;
0153 }
0154 
0155 void SearchModel::setLoaded(bool loaded)
0156 {
0157     if (m_loaded == loaded) {
0158         return;
0159     }
0160     m_loaded = loaded;
0161     Q_EMIT loadedChanged();
0162 }
0163 
0164 SearchHashtag::SearchHashtag(const QJsonObject &object)
0165 {
0166     m_name = object["name"_L1].toString();
0167 }
0168 
0169 QString SearchHashtag::getName() const
0170 {
0171     return m_name;
0172 }
0173 
0174 #include "moc_searchmodel.cpp"