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