From abcf7e3a47f2d200678c1e11c78c2b1867e1e07d Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 9 May 2025 13:46:14 +0400 Subject: [PATCH] Update API scheme & fix monoforum send. --- Telegram/SourceFiles/data/data_channel.cpp | 6 ++++ Telegram/SourceFiles/data/data_channel.h | 1 + Telegram/SourceFiles/data/data_histories.cpp | 33 +++++++++++++++---- Telegram/SourceFiles/data/data_msg_id.h | 3 +- .../SourceFiles/data/data_saved_messages.cpp | 11 +++++-- Telegram/SourceFiles/data/data_session.cpp | 7 ++-- .../SourceFiles/dialogs/dialogs_widget.cpp | 9 +++++ .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 6 ++-- Telegram/SourceFiles/history/history.cpp | 6 ++++ Telegram/SourceFiles/history/history_item.cpp | 23 +++++++++++-- .../history/history_item_components.cpp | 7 ++++ .../history/history_item_components.h | 1 + .../view/history_view_top_bar_widget.cpp | 8 +++-- Telegram/SourceFiles/mtproto/scheme/api.tl | 3 +- 14 files changed, 102 insertions(+), 22 deletions(-) diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 0159fcca80..fc0842c896 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -341,6 +341,12 @@ ChannelData *ChannelData::monoforumLink() const { return _monoforumLink; } +bool ChannelData::requiresMonoforumPeer() const { + return isMonoforum() + && _monoforumLink + && (_monoforumLink->amCreator() || _monoforumLink->hasAdminRights()); +} + void ChannelData::setMembersCount(int newMembersCount) { if (_membersCount != newMembersCount) { if (isMegagroup() diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index 6dc802dcfc..9b3150de8f 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -429,6 +429,7 @@ public: void setMonoforumLink(ChannelData *link); [[nodiscard]] ChannelData *monoforumLink() const; + [[nodiscard]] bool requiresMonoforumPeer() const; void ptsInit(int32 pts) { _ptsWaiter.init(pts); diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index e9b0b02575..e7c5a14da4 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -60,6 +60,15 @@ MTPInputReplyTo ReplyToForMTP( && (to->history() != history || to->id != replyingToTopicId)) ? to->topicRootId() : replyingToTopicId; + const auto possibleMonoforumPeer = (to && to->savedSublistPeer()) + ? to->savedSublistPeer() + : replyTo.monoforumPeerId + ? history->owner().peer(replyTo.monoforumPeerId).get() + : history->session().user().get(); + const auto replyToMonoforumPeer = (history->peer->isChannel() + && history->peer->asChannel()->requiresMonoforumPeer()) + ? possibleMonoforumPeer + : nullptr; const auto external = replyTo.messageId && (replyTo.messageId.peer != history->peer->id || replyingToTopicId != replyToTopicId); @@ -74,6 +83,7 @@ MTPInputReplyTo ReplyToForMTP( | (replyTo.quote.text.isEmpty() ? Flag() : (Flag::f_quote_text | Flag::f_quote_offset)) + | (replyToMonoforumPeer ? Flag::f_monoforum_peer_id : Flag()) | (quoteEntities.v.isEmpty() ? Flag() : Flag::f_quote_entities)), @@ -84,7 +94,17 @@ MTPInputReplyTo ReplyToForMTP( : MTPInputPeer()), MTP_string(replyTo.quote.text), quoteEntities, - MTP_int(replyTo.quoteOffset)); + MTP_int(replyTo.quoteOffset), + (replyToMonoforumPeer + ? replyToMonoforumPeer->input + : MTPInputPeer())); + } else if (history->peer->isChannel() + && history->peer->asChannel()->requiresMonoforumPeer() + && replyTo.monoforumPeerId) { + const auto replyToMonoforumPeer = replyTo.monoforumPeerId + ? history->owner().peer(replyTo.monoforumPeerId) + : history->session().user(); + return MTP_inputReplyToMonoForum(replyToMonoforumPeer->input); } return MTPInputReplyTo(); } @@ -1054,13 +1074,12 @@ int Histories::sendPreparedMessage( _creatingTopicRequests.emplace(id); return id; } - const auto realReplyTo = FullReplyTo{ - .messageId = convertTopicReplyToId(history, replyTo.messageId), - .quote = replyTo.quote, - .storyId = replyTo.storyId, - .topicRootId = convertTopicReplyToId(history, replyTo.topicRootId), - .quoteOffset = replyTo.quoteOffset, + auto realReplyTo = replyTo; + const auto topicReplyToId = [&](const auto &id) { + return convertTopicReplyToId(history, id); }; + realReplyTo.messageId = topicReplyToId(replyTo.messageId); + realReplyTo.topicRootId = topicReplyToId(replyTo.topicRootId); return v::match(message(history, realReplyTo), [&](const auto &request) { const auto type = RequestType::Send; return sendRequest(history, type, [=](Fn finish) { diff --git a/Telegram/SourceFiles/data/data_msg_id.h b/Telegram/SourceFiles/data/data_msg_id.h index 48c57091b1..6a94211cbf 100644 --- a/Telegram/SourceFiles/data/data_msg_id.h +++ b/Telegram/SourceFiles/data/data_msg_id.h @@ -177,10 +177,11 @@ struct FullReplyTo { TextWithEntities quote; FullStoryId storyId; MsgId topicRootId = 0; + PeerId monoforumPeerId = 0; int quoteOffset = 0; [[nodiscard]] bool valid() const { - return messageId || (storyId && storyId.peer); + return messageId || (storyId && storyId.peer) || monoforumPeerId; } explicit operator bool() const { return valid(); diff --git a/Telegram/SourceFiles/data/data_saved_messages.cpp b/Telegram/SourceFiles/data/data_saved_messages.cpp index 74a597b287..72f5aca91f 100644 --- a/Telegram/SourceFiles/data/data_saved_messages.cpp +++ b/Telegram/SourceFiles/data/data_saved_messages.cpp @@ -163,8 +163,15 @@ void SavedMessages::sendLoadMore(not_null sublist) { ).done([=](const MTPmessages_Messages &result) { auto count = 0; auto list = (const QVector*)nullptr; - result.match([](const MTPDmessages_channelMessages &) { - LOG(("API Error: messages.channelMessages in sublist.")); + result.match([&](const MTPDmessages_channelMessages &data) { + if (const auto channel = _parentChat) { + channel->ptsReceived(data.vpts().v); + channel->processTopics(data.vtopics()); + list = &data.vmessages().v; + count = data.vcount().v; + } else { + LOG(("API Error: messages.channelMessages in sublist.")); + } }, [](const MTPDmessages_messagesNotModified &) { LOG(("API Error: messages.messagesNotModified in sublist.")); }, [&](const auto &data) { diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 71368f588a..de96c6c58a 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -372,18 +372,19 @@ void Session::clear() { // Optimization: clear notifications before destroying items. Core::App().notifications().clearFromSession(_session); - // We must clear all forums before clearing customEmojiManager. + // We must clear all [mono]forums before clearing customEmojiManager. // Because in Data::ForumTopic an Ui::Text::CustomEmoji is cached. auto forums = base::flat_set>(); for (const auto &[peerId, peer] : _peers) { if (const auto channel = peer->asChannel()) { - if (channel->isForum()) { + if (channel->isForum() || channel->isMonoforum()) { forums.emplace(channel); } } } for (const auto &channel : forums) { - channel->setFlags(channel->flags() & ~ChannelDataFlag::Forum); + channel->setFlags(channel->flags() + & ~(ChannelDataFlag::Forum | ChannelDataFlag::Monoforum)); } _sendActionManager->clear(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index cc817e3011..31dd678231 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -2497,6 +2497,15 @@ void Widget::escape() { } else if (initial != forum) { controller()->showForum(initial); } + } else if (const auto monoforum + = controller()->shownMonoforum().current()) { + const auto id = controller()->windowId(); // #TODO monoforum + const auto initial = (Data::SavedMessages*)nullptr; + if (!initial) { + controller()->closeMonoforum(); + } else if (initial != monoforum) { + controller()->showMonoforum(initial); + } } else if (controller()->openedFolder().current()) { if (!controller()->windowId().folder()) { controller()->closeFolder(); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 9d312d44c9..dfdb7891d3 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -458,7 +458,9 @@ void PaintRow( const auto promoted = (history && history->useTopPromotion()) && !context.search; - const auto verifyInfo = (from && !from->isSelf()) + const auto verifyInfo = (from + && (!from->isSelf() + || (!(flags & Flag::SavedMessages) && !(flags & Flag::MyNotes)))) ? from->botVerifyDetails() : nullptr; if (promoted) { @@ -996,7 +998,7 @@ void RowPainter::Paint( : nullptr; const auto allowUserOnline = true;// !context.narrow || badgesState.empty(); const auto flags = (allowUserOnline ? Flag::AllowUserOnline : Flag(0)) - | ((sublist && from->isSelf()) + | ((sublist && !sublist->parentChat() && from->isSelf()) ? Flag::MyNotes : (peer && peer->isSelf()) ? Flag::SavedMessages diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 98a7b830d8..641adcae73 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -2241,6 +2241,12 @@ Dialogs::BadgesState History::chatListBadgesState() const { forum->topicsList()->unreadState(), Dialogs::CountInBadge::Chats, Dialogs::IncludeInBadge::UnmutedOrAll)); + } else if (const auto monoforum = peer->monoforum()) { + return adjustBadgesStateByFolder( + Dialogs::BadgesForUnread( + monoforum->chatsList()->unreadState(), + Dialogs::CountInBadge::Chats, + Dialogs::IncludeInBadge::UnmutedOrAll)); } return computeBadgesState(); } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 275edd80f8..2f9bf79236 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -3435,8 +3435,12 @@ FullStoryId HistoryItem::replyToStory() const { } FullReplyTo HistoryItem::replyTo() const { + const auto monoforumPeer = _history->peer->isMonoforum() + ? savedSublistPeer() + : nullptr; auto result = FullReplyTo{ .topicRootId = topicRootId(), + .monoforumPeerId = monoforumPeer ? monoforumPeer->id : PeerId(), }; if (const auto reply = Get()) { const auto &fields = reply->fields(); @@ -3564,7 +3568,7 @@ Data::SavedSublist *HistoryItem::savedSublist() const { that->Get()->sublist = sublist; return sublist; } else if (const auto monoforum = _history->peer->monoforum()) { - const auto sublist = monoforum->sublist(_history->peer); + const auto sublist = monoforum->sublist(_from); const auto that = const_cast(this); that->AddComponents(HistoryMessageSaved::Bit()); that->Get()->sublist = sublist; @@ -3766,7 +3770,11 @@ void HistoryItem::createComponents(CreateConfig &&config) { } else if (config.inlineMarkup) { mask |= HistoryMessageReplyMarkup::Bit(); } - if (_history->peer->isSelf()) { + const auto requiresMonoforumPeer = _history->peer->isChannel() + && _history->peer->asChannel()->requiresMonoforumPeer(); + if (_history->peer->isSelf() + || config.savedSublistPeer + || requiresMonoforumPeer) { mask |= HistoryMessageSaved::Bit(); } if (!config.restrictions.empty()) { @@ -3780,7 +3788,11 @@ void HistoryItem::createComponents(CreateConfig &&config) { if (const auto saved = Get()) { if (!config.savedSublistPeer) { - if (config.savedFromPeer) { + if (config.reply.monoforumPeerId) { + config.savedSublistPeer = config.reply.monoforumPeerId; + } else if (!_history->peer->isSelf()) { + config.savedSublistPeer = _from->id; + } else if (config.savedFromPeer) { config.savedSublistPeer = config.savedFromPeer; } else if (config.originalSenderId) { config.savedSublistPeer = config.originalSenderId; @@ -4023,6 +4035,11 @@ void HistoryItem::createComponentsHelper(HistoryItemCommonFields &&fields) { ? replyTo.messageId.peer : PeerId(); const auto to = LookupReplyTo(_history, replyTo.messageId); + config.reply.monoforumPeerId = (to && to->savedSublistPeer()) + ? to->savedSublistPeer()->id + : replyTo.monoforumPeerId + ? replyTo.monoforumPeerId + : PeerId(); const auto replyToTop = replyTo.topicRootId ? replyTo.topicRootId : LookupReplyToTop(_history, to); diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 9b3f23fb17..28eea2027d 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -417,6 +417,13 @@ FullReplyTo ReplyToFromMTP( }; } return FullReplyTo(); + }, [&](const MTPDinputReplyToMonoForum &data) { + const auto parsed = Data::PeerFromInputMTP( + &history->owner(), + data.vmonoforum_peer_id()); + return FullReplyTo{ + .monoforumPeerId = parsed ? parsed->id : PeerId(), + }; }); } diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 331ee24dfe..57dbeba73f 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -256,6 +256,7 @@ struct ReplyFields { QString externalSenderName; QString externalPostAuthor; PeerId externalPeerId = 0; + PeerId monoforumPeerId = 0; MsgId messageId = 0; MsgId topMessageId = 0; StoryId storyId = 0; diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index c5c3a6187a..568d747b95 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -79,8 +79,10 @@ constexpr auto kEmojiInteractionSeenDuration = 3 * crl::time(1000); QString TopBarNameText( not_null peer, - Dialogs::EntryState::Section section) { - if (section == Dialogs::EntryState::Section::SavedSublist) { + const Dialogs::EntryState &state) { + if (state.section == Dialogs::EntryState::Section::SavedSublist + && state.key.history() + && state.key.history()->peer->isSelf()) { if (peer->isSelf()) { return tr::lng_my_notes(tr::now); } else if (peer->isSavedHiddenAuthor()) { @@ -567,7 +569,7 @@ void TopBarWidget::paintTopBar(Painter &p) { _titleNameVersion = namePeer->nameVersion(); _title.setText( st::msgNameStyle, - TopBarNameText(namePeer, _activeChat.section), + TopBarNameText(namePeer, _activeChat), Ui::NameTextOptions()); } if (const auto info = namePeer->botVerifyDetails()) { diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index accfcd29e4..ba20014278 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -1638,8 +1638,9 @@ stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; -inputReplyToMessage#22c0f6d5 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int = InputReplyTo; +inputReplyToMessage#b07038b0 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer = InputReplyTo; inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; +inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; exportedStoryLink#3fc9053b link:string = ExportedStoryLink;