// This is the source code of AyuGram for Desktop. // // We do not and cannot prevent the use of our code, // but be respectful and credit the original author. // // Copyright @Radolyn, 2023 #include "telegram_helpers.h" #include #include #include "api/api_text_entities.h" #include "apiwrap.h" #include "data/data_forum.h" #include "data/data_forum_topic.h" #include "data/data_histories.h" #include "data/data_peer_id.h" #include "ayu/sync/models.h" #include "data/data_session.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_unread_things.h" Main::Session *getSession(ID userId) { for (const auto &[index, account] : Core::App().domain().accounts()) { if (const auto session = account->maybeSession()) { if (session->userId().bare == userId) { return session; } } } return nullptr; } bool accountExists(ID userId) { return userId == 0 || getSession(userId) != nullptr; } void dispatchToMainThread(std::function callback) { auto timer = new QTimer(); timer->moveToThread(qApp->thread()); timer->setSingleShot(true); QObject::connect(timer, &QTimer::timeout, [=]() { callback(); timer->deleteLater(); }); QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0)); } not_null getHistoryFromDialogId(ID dialogId, Main::Session *session) { if (dialogId > 0) { return session->data().history(peerFromUser(dialogId)); } auto history = session->data().history(peerFromChannel(abs(dialogId))); if (history->folderKnown()) { return history; } return session->data().history(peerFromChat(abs(dialogId))); } ID getDialogIdFromPeer(not_null peer) { auto peerId = peerIsUser(peer->id) ? peerToUser(peer->id).bare : peerIsChat(peer->id) ? peerToChat(peer->id).bare : peerIsChannel(peer->id) ? peerToChannel(peer->id).bare : peer->id.value; if (peer->isChannel() || peer->isChat()) { peerId = -peerId; } return peerId; } std::pair serializeTextWithEntities(not_null item) { if (item->emptyText()) { return std::make_pair("", ""); } auto textWithEntities = item->originalText(); auto text = textWithEntities.text.toStdString(); auto entities = EntitiesToMTP(&item->history()->owner().session(), textWithEntities.entities, Api::ConvertOption::SkipLocal); if (entities.v.isEmpty()) { return std::make_pair(text, ""); } auto buff = mtpBuffer(); for (auto entity : entities.v) { entity.write(buff); } return std::make_pair(text, std::string(reinterpret_cast(buff.data()), buff.size())); } void MarkAsReadChatList(not_null list) { auto mark = std::vector>(); for (const auto &row : list->indexed()->all()) { if (const auto history = row->history()) { mark.push_back(history); } } ranges::for_each(mark, MarkAsReadThread); } void MarkAsReadThread(not_null thread) { const auto readHistory = [&](not_null history) { history->owner().histories().readInbox(history); }; const auto readMentions = [=]( base::weak_ptr weakThread, auto resend) -> void { const auto thread = weakThread.get(); if (!thread) { return; } const auto peer = thread->peer(); const auto topic = thread->asTopic(); const auto rootId = topic ? topic->rootId() : 0; using Flag = MTPmessages_ReadMentions::Flag; peer->session().api().request(MTPmessages_ReadMentions( MTP_flags(rootId ? Flag::f_top_msg_id : Flag()), peer->input, MTP_int(rootId) )).done([=](const MTPmessages_AffectedHistory &result) { const auto offset = peer->session().api().applyAffectedHistory( peer, result); if (offset > 0) { resend(weakThread, resend); } else { peer->owner().history(peer)->clearUnreadMentionsFor(rootId); } }).send(); }; const auto sendReadMentions = [=]( not_null thread) { readMentions(base::make_weak(thread), readMentions); }; const auto readReactions = [=]( base::weak_ptr weakThread, auto resend) -> void { const auto thread = weakThread.get(); if (!thread) { return; } const auto topic = thread->asTopic(); const auto peer = thread->peer(); const auto rootId = topic ? topic->rootId() : 0; using Flag = MTPmessages_ReadReactions::Flag; peer->session().api().request(MTPmessages_ReadReactions( MTP_flags(rootId ? Flag::f_top_msg_id : Flag(0)), peer->input, MTP_int(rootId) )).done([=](const MTPmessages_AffectedHistory &result) { const auto offset = peer->session().api().applyAffectedHistory( peer, result); if (offset > 0) { resend(weakThread, resend); } else { peer->owner().history(peer)->clearUnreadReactionsFor(rootId); } }).send(); }; const auto sendReadReactions = [=]( not_null thread) { readReactions(base::make_weak(thread), readReactions); }; if (thread->chatListBadgesState().unread) { if (const auto forum = thread->asForum()) { forum->enumerateTopics([]( not_null topic) { MarkAsReadThread(topic); }); } else if (const auto history = thread->asHistory()) { readHistory(history); if (const auto migrated = history->migrateSibling()) { readHistory(migrated); } } else if (const auto topic = thread->asTopic()) { topic->readTillEnd(); } } if (thread->unreadMentions().has()) { sendReadMentions(thread); } if (thread->unreadReactions().has()) { sendReadReactions(thread); } }