File indexing completed on 2024-05-12 05:04:15
0001 // SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org> 0002 // SPDX-License-Identifier: GPL-3.0-or-later 0003 0004 #include "abstracttimelinemodel.h" 0005 0006 #include "abstractaccount.h" 0007 #include "attachmenteditormodel.h" 0008 #include "posteditorbackend.h" 0009 0010 using namespace Qt::Literals::StringLiterals; 0011 0012 AbstractTimelineModel::AbstractTimelineModel(QObject *parent) 0013 : QAbstractListModel(parent) 0014 { 0015 } 0016 0017 bool AbstractTimelineModel::loading() const 0018 { 0019 return m_loading; 0020 } 0021 0022 void AbstractTimelineModel::setLoading(bool loading) 0023 { 0024 if (m_loading == loading) { 0025 return; 0026 } 0027 m_loading = loading; 0028 Q_EMIT loadingChanged(); 0029 } 0030 0031 QHash<int, QByteArray> AbstractTimelineModel::roleNames() const 0032 { 0033 return { 0034 {IdRole, QByteArrayLiteral("id")}, 0035 {OriginalIdRole, QByteArrayLiteral("originalId")}, 0036 {UrlRole, QByteArrayLiteral("url")}, 0037 {ContentRole, QByteArrayLiteral("content")}, 0038 {SpoilerTextRole, QByteArrayLiteral("spoilerText")}, 0039 {AuthorIdentityRole, QByteArrayLiteral("authorIdentity")}, 0040 {PublishedAtRole, QByteArrayLiteral("publishedAt")}, 0041 {VisibilityRole, QByteArrayLiteral("visibility")}, 0042 {WasEditedRole, QByteArrayLiteral("wasEdited")}, 0043 {EditedAtRole, QByteArrayLiteral("editedAt")}, 0044 {SelectedRole, QByteArrayLiteral("selected")}, 0045 {FiltersRole, QByteArrayLiteral("filters")}, 0046 {RelativeTimeRole, QByteArrayLiteral("relativeTime")}, 0047 {AbsoluteTimeRole, QByteArrayLiteral("absoluteTime")}, 0048 {SensitiveRole, QByteArrayLiteral("sensitive")}, 0049 0050 // Additional content 0051 {CardRole, QByteArrayLiteral("card")}, 0052 {ApplicationRole, QByteArrayLiteral("application")}, 0053 {PollRole, QByteArrayLiteral("poll")}, 0054 {MentionsRole, QByteArrayLiteral("mentions")}, 0055 {AttachmentsRole, QByteArrayLiteral("attachments")}, 0056 0057 // Reblog 0058 {IsBoostedRole, "isBoosted"}, 0059 {BoostAuthorIdentityRole, "boostAuthorIdentity"}, 0060 0061 // Reply 0062 {IsReplyRole, "isReply"}, 0063 {ReplyAuthorIdentityRole, "replyAuthorIdentity"}, 0064 0065 // Interaction count 0066 {ReblogsCountRole, QByteArrayLiteral("reblogsCount")}, 0067 {RepliesCountRole, QByteArrayLiteral("repliesCount")}, 0068 {FavouritesCountRole, QByteArrayLiteral("favouritesCount")}, 0069 0070 // User self interaction 0071 {FavouritedRole, QByteArrayLiteral("favourited")}, 0072 {RebloggedRole, QByteArrayLiteral("reblogged")}, 0073 {MutedRole, QByteArrayLiteral("muted")}, 0074 {BookmarkedRole, QByteArrayLiteral("bookmarked")}, 0075 {PinnedRole, QByteArrayLiteral("pinned")}, 0076 0077 // Notification 0078 {NotificationActorIdentityRole, "notificationActorIdentity"}, 0079 {TypeRole, "type"}, 0080 {PostRole, "post"}, 0081 {IsGroupRole, "isGroup"}, 0082 {NumInGroupRole, "numInGroup"}, 0083 {IsInGroupRole, "isInGroup"}, 0084 }; 0085 } 0086 0087 QVariant AbstractTimelineModel::postData(Post *post, int role) const 0088 { 0089 switch (role) { 0090 case IdRole: 0091 return post->postId(); 0092 case OriginalIdRole: 0093 return post->originalPostId(); 0094 case MentionsRole: 0095 return post->mentions(); 0096 case ContentRole: 0097 return post->content(); 0098 case AuthorIdentityRole: 0099 return QVariant::fromValue<Identity *>(post->authorIdentity().get()); 0100 case IsBoostedRole: 0101 return post->boosted(); 0102 case BoostAuthorIdentityRole: 0103 if (post->boostIdentity()) { 0104 return QVariant::fromValue<Identity *>(post->boostIdentity().get()); 0105 } 0106 return false; 0107 case IsReplyRole: 0108 return !post->inReplyTo().isEmpty(); 0109 case ReplyAuthorIdentityRole: 0110 if (!post->inReplyTo().isEmpty()) { 0111 return QVariant::fromValue<Identity *>(post->replyIdentity().get()); 0112 } 0113 return false; 0114 case PublishedAtRole: 0115 return post->publishedAt(); 0116 case RebloggedRole: 0117 return post->reblogged(); 0118 case FavouritedRole: 0119 return post->favourited(); 0120 case BookmarkedRole: 0121 return post->bookmarked(); 0122 case PinnedRole: 0123 return post->pinned(); 0124 0125 case FavouritesCountRole: 0126 return post->favouritesCount(); 0127 case RepliesCountRole: 0128 return post->repliesCount(); 0129 case ReblogsCountRole: 0130 return post->reblogsCount(); 0131 case SensitiveRole: 0132 return post->sensitive(); 0133 case SpoilerTextRole: 0134 return post->spoilerText(); 0135 case VisibilityRole: 0136 return post->visibility(); 0137 case WasEditedRole: 0138 return post->wasEdited(); 0139 case EditedAtRole: 0140 return post->editedAt(); 0141 case FiltersRole: 0142 return post->filters(); 0143 case AttachmentsRole: 0144 return QVariant::fromValue<QList<Attachment *>>(post->attachments()); 0145 case CardRole: 0146 if (post->card().has_value()) { 0147 return QVariant::fromValue<Card>(*post->card()); 0148 } 0149 return false; 0150 case ApplicationRole: 0151 if (post->application().has_value()) { 0152 return QVariant::fromValue<Application>(*post->application()); 0153 } 0154 return false; 0155 case UrlRole: 0156 return QVariant::fromValue<QUrl>(post->url()); 0157 case RelativeTimeRole: { 0158 return post->relativeTime(); 0159 } 0160 case AbsoluteTimeRole: { 0161 return post->absoluteTime(); 0162 } 0163 case PollRole: 0164 if (post->poll()) { 0165 return QVariant::fromValue<Poll>(*post->poll()); 0166 } 0167 return {}; 0168 case TypeRole: 0169 case NotificationActorIdentityRole: 0170 return {}; 0171 case PostRole: 0172 return QVariant::fromValue<Post *>(post); 0173 } 0174 0175 return {}; 0176 } 0177 0178 void AbstractTimelineModel::actionFavorite(const QModelIndex &index, Post *post) 0179 { 0180 if (!post->favourited()) { 0181 m_account->favorite(post); 0182 post->setFavourited(true); 0183 } else { 0184 m_account->unfavorite(post); 0185 post->setFavourited(false); 0186 } 0187 0188 Q_EMIT dataChanged(index, index, {FavouritedRole}); 0189 } 0190 0191 void AbstractTimelineModel::actionRepeat(const QModelIndex &index, Post *post) 0192 { 0193 if (!post->reblogged()) { 0194 m_account->repeat(post); 0195 post->setReblogged(true); 0196 } else { 0197 m_account->unrepeat(post); 0198 post->setReblogged(false); 0199 } 0200 0201 Q_EMIT dataChanged(index, index, {RebloggedRole}); 0202 } 0203 0204 void AbstractTimelineModel::actionRedraft(const QModelIndex &index, Post *post, bool isEdit) 0205 { 0206 m_account->get(m_account->apiUrl(QStringLiteral("/api/v1/statuses/%1/source").arg(post->postId())), 0207 true, 0208 this, 0209 [this, post, index, isEdit](QNetworkReply *reply) { 0210 const auto postSource = QJsonDocument::fromJson(reply->readAll()).object(); 0211 0212 auto backend = new PostEditorBackend(); 0213 backend->setId(post->postId()); 0214 backend->setStatus(postSource["text"_L1].toString()); 0215 backend->setSpoilerText(postSource["spoiler_text"_L1].toString()); 0216 backend->setInReplyTo(post->inReplyTo()); 0217 backend->setVisibility(post->visibility()); 0218 backend->setLanguage(post->language()); 0219 backend->setMentions(post->mentions()); // TODO: needed? 0220 backend->setSensitive(post->sensitive()); 0221 0222 Q_EMIT postSourceReady(backend, isEdit); 0223 0224 auto attachmentBackend = backend->attachmentEditorModel(); 0225 for (const auto &attachment : post->attachments()) { 0226 attachmentBackend->appendExisting(attachment); 0227 } 0228 0229 if (isEdit) { 0230 connect(backend, &PostEditorBackend::editComplete, this, [this, post, index](QJsonObject object) { 0231 post->fromJson(object); 0232 Q_EMIT dataChanged(index, index); 0233 }); 0234 } 0235 }); 0236 } 0237 0238 void AbstractTimelineModel::actionBookmark(const QModelIndex &index, Post *post) 0239 { 0240 if (!post->bookmarked()) { 0241 m_account->bookmark(post); 0242 post->setBookmarked(true); 0243 } else { 0244 m_account->unbookmark(post); 0245 post->setBookmarked(false); 0246 } 0247 0248 Q_EMIT dataChanged(index, index, {BookmarkedRole}); 0249 } 0250 0251 void AbstractTimelineModel::actionPin(const QModelIndex &index, Post *post) 0252 { 0253 if (!post->pinned()) { 0254 m_account->pin(post); 0255 post->setPinned(true); 0256 } else { 0257 m_account->unpin(post); 0258 post->setPinned(false); 0259 } 0260 0261 Q_EMIT dataChanged(index, index, {PinnedRole}); 0262 } 0263 0264 void AbstractTimelineModel::actionDelete(const QModelIndex &index, Post *post) 0265 { 0266 Q_UNUSED(index); 0267 m_account->deleteResource(m_account->apiUrl(QStringLiteral("/api/v1/statuses/%1").arg(post->postId())), true, this, {}); 0268 } 0269 0270 #include "moc_abstracttimelinemodel.cpp"