diff --git a/Telegram/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index ad1d54edff..8b77c3a469 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -192,7 +192,7 @@ messageActionChatJoinedByRequest#ebbca3cb = MessageAction; messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; messageActionGiftPremium#aba0f5c6 currency:string amount:long months:int = MessageAction; -messageActionTopicCreate#4619708d title:string = MessageAction; +messageActionTopicCreate#6fa796ac flags:# title:string icon_emoji_id:flags.0?long = MessageAction; messageActionTopicEditTitle#ce0b23cd title:string = MessageAction; messageActionTopicEditIcon#820a6e2b emoji_document_id:long = MessageAction; @@ -1856,7 +1856,7 @@ channels.deleteParticipantHistory#367544db channel:InputChannel participant:Inpu channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates; channels.toggleForum#a4298b29 channel:InputChannel enabled:Bool = Updates; -channels.createForumTopic#21289f15 flags:# no_webpage:flags.3?true channel:InputChannel title:string icon_emoji_id:flags.3?long media:flags.0?InputMedia message:string random_id:long entities:flags.1?Vector send_as:flags.2?InputPeer = Updates; +channels.createForumTopic#60bf3bc9 flags:# channel:InputChannel title:string icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; channels.getForumTopics#de560d1 flags:# channel:InputChannel q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; channels.getForumTopicsByID#b0831eb9 channel:InputChannel topics:Vector = messages.ForumTopics; channels.editForumTitle#8881b9b1 channel:InputChannel topic_id:int title:string = Updates; diff --git a/Telegram/SourceFiles/api/api_polls.cpp b/Telegram/SourceFiles/api/api_polls.cpp index d90198df43..68aae67975 100644 --- a/Telegram/SourceFiles/api/api_polls.cpp +++ b/Telegram/SourceFiles/api/api_polls.cpp @@ -65,47 +65,40 @@ void Polls::create( sendFlags |= MTPmessages_SendMedia::Flag::f_send_as; } auto &histories = history->owner().histories(); - const auto requestType = Data::Histories::RequestType::Send; - histories.sendRequest(history, requestType, [=](Fn finish) { - const auto replyTo = action.replyTo; - history->sendRequestId = _api.request(MTPmessages_SendMedia( + const auto replyTo = action.replyTo; + const auto randomId = base::RandomValue(); + histories.sendPreparedMessage( + history, + replyTo, + randomId, + MTPmessages_SendMedia( MTP_flags(sendFlags), peer->input, MTP_int(replyTo), PollDataToInputMedia(&data), MTP_string(), - MTP_long(base::RandomValue()), + MTP_long(randomId), MTPReplyMarkup(), MTPVector(), MTP_int(action.options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()) - )).done([=]( - const MTPUpdates &result, - const MTP::Response &response) mutable { - _session->updates().applyUpdates(result); - if (clearCloudDraft) { - history->finishSavingCloudDraft( - UnixtimeFromMsgId(response.outerMsgId)); - } - _session->changes().historyUpdated( - history, - (action.options.scheduled - ? Data::HistoryUpdate::Flag::ScheduledSent - : Data::HistoryUpdate::Flag::MessageSent)); - done(); - finish(); - }).fail([=]( - const MTP::Error &error, - const MTP::Response &response) mutable { - if (clearCloudDraft) { - history->finishSavingCloudDraft( - UnixtimeFromMsgId(response.outerMsgId)); - } - fail(); - finish(); - }).afterRequest(history->sendRequestId - ).send(); - return history->sendRequestId; + ), [=](const MTPUpdates &result, const MTP::Response &response) { + if (clearCloudDraft) { + history->finishSavingCloudDraft( + UnixtimeFromMsgId(response.outerMsgId)); + } + _session->changes().historyUpdated( + history, + (action.options.scheduled + ? Data::HistoryUpdate::Flag::ScheduledSent + : Data::HistoryUpdate::Flag::MessageSent)); + done(); + }, [=](const MTP::Error &error, const MTP::Response &response) { + if (clearCloudDraft) { + history->finishSavingCloudDraft( + UnixtimeFromMsgId(response.outerMsgId)); + } + fail(); }); } diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index 1a1f12a722..d23d9493e5 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -141,12 +141,14 @@ void SendExistingMedia( caption, HistoryMessageMarkupData()); - auto performRequest = [=](const auto &repeatRequest) -> void { + const auto performRequest = [=](const auto &repeatRequest) -> void { auto &histories = history->owner().histories(); - const auto requestType = Data::Histories::RequestType::Send; - histories.sendRequest(history, requestType, [=](Fn finish) { - const auto usedFileReference = media->fileReference(); - history->sendRequestId = api->request(MTPmessages_SendMedia( + const auto usedFileReference = media->fileReference(); + histories.sendPreparedMessage( + history, + replyTo, + randomId, + MTPmessages_SendMedia( MTP_flags(sendFlags), peer->input, MTP_int(replyTo), @@ -157,26 +159,20 @@ void SendExistingMedia( sentEntities, MTP_int(message.action.options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()) - )).done([=](const MTPUpdates &result) { - api->applyUpdates(result, randomId); - finish(); - }).fail([=](const MTP::Error &error) { - if (error.code() == 400 - && error.type().startsWith(qstr("FILE_REFERENCE_"))) { - api->refreshFileReference(origin, [=](const auto &result) { - if (media->fileReference() != usedFileReference) { - repeatRequest(repeatRequest); - } else { - api->sendMessageFail(error, peer, randomId, newId); - } - }); - } else { - api->sendMessageFail(error, peer, randomId, newId); - } - finish(); - }).afterRequest(history->sendRequestId - ).send(); - return history->sendRequestId; + ), [=](const MTPUpdates &result, const MTP::Response &response) { + }, [=](const MTP::Error &error, const MTP::Response &response) { + if (error.code() == 400 + && error.type().startsWith(qstr("FILE_REFERENCE_"))) { + api->refreshFileReference(origin, [=](const auto &result) { + if (media->fileReference() != usedFileReference) { + repeatRequest(repeatRequest); + } else { + api->sendMessageFail(error, peer, randomId, newId); + } + }); + } else { + api->sendMessageFail(error, peer, randomId, newId); + } }); }; performRequest(performRequest); @@ -314,10 +310,11 @@ bool SendDice(MessageToSend &message) { TextWithEntities(), MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)), HistoryMessageMarkupData()); - - const auto requestType = Data::Histories::RequestType::Send; - histories.sendRequest(history, requestType, [=](Fn finish) { - history->sendRequestId = api->request(MTPmessages_SendMedia( + histories.sendPreparedMessage( + history, + replyTo, + randomId, + MTPmessages_SendMedia( MTP_flags(sendFlags), peer->input, MTP_int(replyTo), @@ -328,15 +325,9 @@ bool SendDice(MessageToSend &message) { MTP_vector(), MTP_int(message.action.options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()) - )).done([=](const MTPUpdates &result) { - api->applyUpdates(result, randomId); - finish(); - }).fail([=](const MTP::Error &error) { - api->sendMessageFail(error, peer, randomId, newId); - finish(); - }).afterRequest(history->sendRequestId - ).send(); - return history->sendRequestId; + ), [=](const MTPUpdates &result, const MTP::Response &response) { + }, [=](const MTP::Error &error, const MTP::Response &response) { + api->sendMessageFail(error, peer, randomId, newId); }); api->finishForwarding(message.action); return true; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 0e703dab83..2367e6e205 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3479,53 +3479,47 @@ void ApiWrap::sendMessage(MessageToSend &&message) { sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date; } const auto viaBotId = UserId(); + const auto replyTo = action.replyTo; lastMessage = history->addNewLocalMessage( newId.msg, flags, viaBotId, - action.replyTo, + replyTo, HistoryItem::NewMessageDate(action.options.scheduled), messageFromId, messagePostAuthor, sending, media, HistoryMessageMarkupData()); - histories.sendRequest(history, requestType, [=](Fn finish) { - history->sendRequestId = request(MTPmessages_SendMessage( + histories.sendPreparedMessage( + history, + replyTo, + randomId, + MTPmessages_SendMessage( MTP_flags(sendFlags), peer->input, - MTP_int(action.replyTo), + MTP_int(replyTo), msgText, MTP_long(randomId), MTPReplyMarkup(), sentEntities, MTP_int(action.options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()) - )).done([=]( - const MTPUpdates &result, - const MTP::Response &response) { - applyUpdates(result, randomId); - if (clearCloudDraft) { - history->finishSavingCloudDraft( - UnixtimeFromMsgId(response.outerMsgId)); - } - finish(); - }).fail([=]( - const MTP::Error &error, - const MTP::Response &response) { - if (error.type() == qstr("MESSAGE_EMPTY")) { - lastMessage->destroy(); - } else { - sendMessageFail(error, peer, randomId, newId); - } - if (clearCloudDraft) { - history->finishSavingCloudDraft( - UnixtimeFromMsgId(response.outerMsgId)); - } - finish(); - }).afterRequest(history->sendRequestId - ).send(); - return history->sendRequestId; + ), [=](const MTPUpdates &result, const MTP::Response &response) { + if (clearCloudDraft) { + history->finishSavingCloudDraft( + UnixtimeFromMsgId(response.outerMsgId)); + } + }, [=](const MTP::Error &error, const MTP::Response &response) { + if (error.type() == qstr("MESSAGE_EMPTY")) { + lastMessage->destroy(); + } else { + sendMessageFail(error, peer, randomId, newId); + } + if (clearCloudDraft) { + history->finishSavingCloudDraft( + UnixtimeFromMsgId(response.outerMsgId)); + } }); } @@ -3639,34 +3633,27 @@ void ApiWrap::sendInlineResult( history->startSavingCloudDraft(); auto &histories = history->owner().histories(); - const auto requestType = Data::Histories::RequestType::Send; - histories.sendRequest(history, requestType, [=](Fn finish) { - history->sendRequestId = request(MTPmessages_SendInlineBotResult( + const auto replyTo = action.replyTo; + histories.sendPreparedMessage( + history, + replyTo, + randomId, + MTPmessages_SendInlineBotResult( MTP_flags(sendFlags), peer->input, - MTP_int(action.replyTo), + MTP_int(replyTo), MTP_long(randomId), MTP_long(data->getQueryId()), MTP_string(data->getId()), MTP_int(action.options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()) - )).done([=]( - const MTPUpdates &result, - const MTP::Response &response) { - applyUpdates(result, randomId); - history->finishSavingCloudDraft( - UnixtimeFromMsgId(response.outerMsgId)); - finish(); - }).fail([=]( - const MTP::Error &error, - const MTP::Response &response) { - sendMessageFail(error, peer, randomId, newId); - history->finishSavingCloudDraft( - UnixtimeFromMsgId(response.outerMsgId)); - finish(); - }).afterRequest(history->sendRequestId - ).send(); - return history->sendRequestId; + ), [=](const MTPUpdates &result, const MTP::Response &response) { + history->finishSavingCloudDraft( + UnixtimeFromMsgId(response.outerMsgId)); + }, [=](const MTP::Error &error, const MTP::Response &response) { + sendMessageFail(error, peer, randomId, newId); + history->finishSavingCloudDraft( + UnixtimeFromMsgId(response.outerMsgId)); }); finishForwarding(action); } @@ -3792,11 +3779,13 @@ void ApiWrap::sendMediaWithRandomId( : MTPmessages_SendMedia::Flag(0)); auto &histories = history->owner().histories(); - const auto requestType = Data::Histories::RequestType::Send; - histories.sendRequest(history, requestType, [=](Fn finish) { - const auto peer = history->peer; - const auto itemId = item->fullId(); - history->sendRequestId = request(MTPmessages_SendMedia( + const auto peer = history->peer; + const auto itemId = item->fullId(); + histories.sendPreparedMessage( + history, + replyTo, + randomId, + MTPmessages_SendMedia( MTP_flags(flags), peer->input, MTP_int(replyTo), @@ -3807,20 +3796,12 @@ void ApiWrap::sendMediaWithRandomId( sentEntities, MTP_int(options.scheduled), (options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()) - )).done([=](const MTPUpdates &result) { - applyUpdates(result); - finish(); - - if (updateRecentStickers) { - requestRecentStickersForce(true); - } - }).fail([=](const MTP::Error &error) { - sendMessageFail(error, peer, randomId, itemId); - finish(); - }).afterRequest( - history->sendRequestId - ).send(); - return history->sendRequestId; + ), [=](const MTPUpdates &result, const MTP::Response &response) { + if (updateRecentStickers) { + requestRecentStickersForce(true); + } + }, [=](const MTP::Error &error, const MTP::Response &response) { + sendMessageFail(error, peer, randomId, itemId); }); } @@ -3904,33 +3885,28 @@ void ApiWrap::sendAlbumIfReady(not_null album) { ? MTPmessages_SendMultiMedia::Flag::f_send_as : MTPmessages_SendMultiMedia::Flag(0)); auto &histories = history->owner().histories(); - const auto requestType = Data::Histories::RequestType::Send; - histories.sendRequest(history, requestType, [=](Fn finish) { - const auto peer = history->peer; - history->sendRequestId = request(MTPmessages_SendMultiMedia( + const auto peer = history->peer; + histories.sendPreparedMessage( + history, + replyTo, + uint64(0), // randomId + MTPmessages_SendMultiMedia( MTP_flags(flags), peer->input, MTP_int(replyTo), MTP_vector(medias), MTP_int(album->options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()) - )).done([=](const MTPUpdates &result) { - _sendingAlbums.remove(groupId); - applyUpdates(result); - finish(); - }).fail([=](const MTP::Error &error) { - if (const auto album = _sendingAlbums.take(groupId)) { - for (const auto &item : (*album)->items) { - sendMessageFail(error, peer, item.randomId, item.msgId); - } - } else { - sendMessageFail(error, peer); + ), [=](const MTPUpdates &result, const MTP::Response &response) { + _sendingAlbums.remove(groupId); + }, [=](const MTP::Error &error, const MTP::Response &response) { + if (const auto album = _sendingAlbums.take(groupId)) { + for (const auto &item : (*album)->items) { + sendMessageFail(error, peer, item.randomId, item.msgId); } - finish(); - }).afterRequest( - history->sendRequestId - ).send(); - return history->sendRequestId; + } else { + sendMessageFail(error, peer); + } }); } diff --git a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp index ffc32993d7..273e5156d2 100644 --- a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp @@ -63,11 +63,13 @@ void ShareBotGame( const QString &shortName) { const auto history = chat->owner().history(chat); auto &histories = history->owner().histories(); - const auto requestType = Data::Histories::RequestType::Send; - histories.sendRequest(history, requestType, [=](Fn finish) { - const auto randomId = base::RandomValue(); - const auto api = &chat->session().api(); - history->sendRequestId = api->request(MTPmessages_SendMedia( + const auto randomId = base::RandomValue(); + const auto replyTo = 0; + histories.sendPreparedMessage( + history, + replyTo, + randomId, + MTPmessages_SendMedia( MTP_flags(0), chat->input, MTP_int(0), @@ -81,16 +83,9 @@ void ShareBotGame( MTPVector(), MTP_int(0), // schedule_date MTPInputPeer() // send_as - )).done([=](const MTPUpdates &result) { - api->applyUpdates(result, randomId); - finish(); - }).fail([=](const MTP::Error &error) { - api->sendMessageFail(error, chat); - finish(); - }).afterRequest( - history->sendRequestId - ).send(); - return history->sendRequestId; + ), [=](const MTPUpdates &result, const MTP::Response &response) { + }, [=](const MTP::Error &error, const MTP::Response &response) { + chat->session().api().sendMessageFail(error, chat); }); } diff --git a/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp index bf1b8643b8..bef12b9a37 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/stickers/data_custom_emoji.h" #include "main/main_session.h" #include "history/history.h" +#include "history/view/history_view_replies_section.h" #include "lang/lang_keys.h" #include "info/profile/info_profile_emoji_status_panel.h" #include "window/window_session_controller.h" @@ -142,9 +143,16 @@ void EditForumTopicBox( box->closeBox(); return; } else if (title->getLastText().trimmed().isEmpty()) { - title->setFocus(); + title->showError(); return; } + controller->showSection( + std::make_shared( + forum, + forum->peer->forum()->reserveCreatingId( + title->getLastText().trimmed(), + state->iconId)), + Window::SectionShow::Way::ClearStack); #if 0 // #TODO forum create const auto randomId = base::RandomValue(); const auto api = &forum->session().api(); @@ -178,7 +186,7 @@ void EditForumTopicBox( const auto api = &forum->session().api(); if (state->titleRequestId <= 0) { if (title->getLastText().trimmed().isEmpty()) { - title->setFocus(); + title->showError(); return; } state->titleRequestId = api->request(MTPchannels_EditForumTitle( diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index ba6dae3534..7d8ab9f4c7 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -120,17 +120,24 @@ void Forum::applyReceivedTopics( } } -void Forum::applyTopicAdded(MsgId rootId, const QString &title) { +void Forum::applyTopicAdded( + MsgId rootId, + const QString &title, + DocumentId iconId) { if (const auto i = _topics.find(rootId); i != end(_topics)) { i->second->applyTitle(title); + i->second->applyIconId(iconId); } else { const auto raw = _topics.emplace( rootId, std::make_unique(_history, rootId) ).first->second.get(); raw->applyTitle(title); - raw->addToChatList(FilterId(), topicsList()); - _chatsListChanges.fire({}); + raw->applyIconId(iconId); + if (!creating(rootId)) { + raw->addToChatList(FilterId(), topicsList()); + _chatsListChanges.fire({}); + } } } @@ -140,6 +147,30 @@ void Forum::applyTopicRemoved(MsgId rootId) { //} } +MsgId Forum::reserveCreatingId( + const QString &title, + DocumentId iconId) { + const auto result = _history->owner().nextLocalMessageId(); + _creatingRootIds.emplace(result); + applyTopicAdded(result, title, iconId); + return result; +} + +void Forum::discardCreatingId(MsgId rootId) { + Expects(creating(rootId)); + + const auto i = _topics.find(rootId); + if (i != end(_topics)) { + Assert(!i->second->inChatList()); + _topics.erase(i); + } + _creatingRootIds.remove(rootId); +} + +bool Forum::creating(MsgId rootId) const { + return _creatingRootIds.contains(rootId); +} + ForumTopic *Forum::topicFor(not_null item) { return topicFor(item->topicRootId()); } @@ -151,7 +182,7 @@ ForumTopic *Forum::topicFor(MsgId rootId) { } } else { // #TODO forum lang - applyTopicAdded(rootId, "General! Created."); + applyTopicAdded(rootId, "General! Created.", DocumentId(0)); return _topics.find(rootId)->second.get(); } return nullptr; diff --git a/Telegram/SourceFiles/data/data_forum.h b/Telegram/SourceFiles/data/data_forum.h index 01451a77a8..f52540d293 100644 --- a/Telegram/SourceFiles/data/data_forum.h +++ b/Telegram/SourceFiles/data/data_forum.h @@ -31,13 +31,22 @@ public: [[nodiscard]] rpl::producer<> chatsListChanges() const; [[nodiscard]] rpl::producer<> chatsListLoadedEvents() const; - void applyTopicAdded(MsgId rootId, const QString &title); + void applyTopicAdded( + MsgId rootId, + const QString &title, + DocumentId iconId); void applyTopicRemoved(MsgId rootId); [[nodiscard]] ForumTopic *topicFor(not_null item); [[nodiscard]] ForumTopic *topicFor(MsgId rootId); void applyReceivedTopics(const MTPmessages_ForumTopics &topics); + [[nodiscard]] MsgId reserveCreatingId( + const QString &title, + DocumentId iconId); + void discardCreatingId(MsgId rootId); + [[nodiscard]] bool creating(MsgId rootId) const; + private: void applyReceivedTopics( const MTPmessages_ForumTopics &topics, @@ -54,6 +63,8 @@ private: MsgId _offsetTopicId = 0; bool _allLoaded = false; + base::flat_set _creatingRootIds; + rpl::event_stream<> _chatsListChanges; rpl::event_stream<> _chatsListLoadedEvents; diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index 9be4d5b83b..9ca85be8cc 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -10,27 +10,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_forum.h" #include "data/data_session.h" +#include "data/stickers/data_custom_emoji.h" #include "dialogs/dialogs_main_list.h" #include "core/application.h" #include "core/core_settings.h" #include "history/history.h" #include "history/history_item.h" +#include "ui/painter.h" namespace Data { -ForumTopic::ForumTopic(not_null forum, MsgId rootId) -: Entry(&forum->owner(), Type::ForumTopic) -, _forum(forum) -, _list(forum->peer->asChannel()->forum()->topicsList()) +ForumTopic::ForumTopic(not_null history, MsgId rootId) +: Entry(&history->owner(), Type::ForumTopic) +, _history(history) +, _list(forum()->topicsList()) , _rootId(rootId) { } not_null ForumTopic::channel() const { - return _forum->peer->asChannel(); + return _history->peer->asChannel(); } -not_null ForumTopic::forum() const { - return _forum; +not_null ForumTopic::history() const { + return _history; +} + +not_null ForumTopic::forum() const { + return channel()->forum(); } MsgId ForumTopic::rootId() const { @@ -110,7 +116,7 @@ void ForumTopic::applyTopicFields( void ForumTopic::applyTopicTopMessage(MsgId topMessageId) { if (topMessageId) { - const auto itemId = FullMsgId(_forum->peer->id, topMessageId); + const auto itemId = FullMsgId(_history->peer->id, topMessageId); if (const auto item = owner().message(itemId)) { setLastServerMessage(item); } else { @@ -193,6 +199,9 @@ void ForumTopic::setOutboxReadTill(MsgId upTo) { } void ForumTopic::loadUserpic() { + if (_icon) { + [[maybe_unused]] const auto preload = _icon->ready(); + } } void ForumTopic::paintUserpic( @@ -201,7 +210,19 @@ void ForumTopic::paintUserpic( int x, int y, int size) const { - // #TODO forum + if (_icon) { + const auto emoji = Data::FrameSizeFromTag( + Data::CustomEmojiManager::SizeTag::Isolated + ) / style::DevicePixelRatio(); + _icon->paint(p, { + .preview = st::windowBgOver->c, + .now = crl::now(), + .position = QPoint( + x + (size - emoji) / 2, + y + (size - emoji) / 2), + .paused = false, + }); + } } void ForumTopic::requestChatListMessage() { @@ -270,7 +291,15 @@ DocumentId ForumTopic::iconId() const { } void ForumTopic::applyIconId(DocumentId iconId) { - _iconId = iconId; + if (_iconId != iconId) { + _iconId = iconId; + _icon = iconId + ? _history->owner().customEmojiManager().create( + _iconId, + [=] { updateChatListEntry(); }, + Data::CustomEmojiManager::SizeTag::Isolated) + : nullptr; + } updateChatListEntry(); } @@ -348,7 +377,7 @@ Dialogs::UnreadState ForumTopic::chatListUnreadState() const { auto result = Dialogs::UnreadState(); const auto count = _unreadCount.value_or(0); const auto mark = !count && _unreadMark; - const auto muted = _forum->mute(); + const auto muted = _history->mute(); result.messages = count; result.messagesMuted = muted ? count : 0; result.chats = count ? 1 : 0; diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h index 8a5f75bee6..8f36d87b65 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.h +++ b/Telegram/SourceFiles/data/data_forum_topic.h @@ -23,18 +23,20 @@ class Session; namespace Data { class Session; +class Forum; class ForumTopic final : public Dialogs::Entry { public: static constexpr auto kGeneralId = 1; - ForumTopic(not_null forum, MsgId rootId); + ForumTopic(not_null history, MsgId rootId); ForumTopic(const ForumTopic &) = delete; ForumTopic &operator=(const ForumTopic &) = delete; [[nodiscard]] not_null channel() const; - [[nodiscard]] not_null forum() const; + [[nodiscard]] not_null history() const; + [[nodiscard]] not_null forum() const; [[nodiscard]] MsgId rootId() const; [[nodiscard]] bool isGeneral() const { return (_rootId == kGeneralId); @@ -107,7 +109,7 @@ private: int chatListNameVersion() const override; - const not_null _forum; + const not_null _history; const not_null _list; const MsgId _rootId = 0; @@ -117,6 +119,8 @@ private: base::flat_set _titleFirstLetters; int _titleVersion = 0; + std::unique_ptr _icon; + std::optional _inboxReadBefore; std::optional _outboxReadBefore; std::optional _unreadCount; diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 60e7127ea4..d5f2442e95 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -841,6 +841,39 @@ int Histories::sendRequest( return id; } +int Histories::sendPreparedMessage( + not_null history, + MsgId replyTo, + uint64 randomId, + PreparedMessage message, + Fn done, + Fn fail) { + return v::match(message, [&](const auto &request) { + const auto type = RequestType::Send; + return sendRequest(history, type, [=](Fn finish) { + const auto session = &_owner->session(); + const auto api = &session->api(); + history->sendRequestId = api->request( + base::duplicate(request) + ).done([=]( + const MTPUpdates &result, + const MTP::Response &response) { + api->applyUpdates(result, randomId); + done(result, response); + finish(); + }).fail([=]( + const MTP::Error &error, + const MTP::Response &response) { + fail(error, response); + finish(); + }).afterRequest( + history->sendRequestId + ).send(); + return history->sendRequestId; + }); + }); +} + void Histories::checkPostponed(not_null history, int id) { if (const auto state = lookup(history)) { finishSentRequest(history, state, id); diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index 6d36b2f488..faccd7da86 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -16,6 +16,11 @@ namespace Main { class Session; } // namespace Main +namespace MTP { +class Error; +struct Response; +} // namespace MTP + namespace Data { class Session; @@ -90,6 +95,19 @@ public: Fn finish)> generator); void cancelRequest(int id); + using PreparedMessage = std::variant< + MTPmessages_SendMessage, + MTPmessages_SendMedia, + MTPmessages_SendInlineBotResult, + MTPmessages_SendMultiMedia>; + int sendPreparedMessage( + not_null history, + MsgId replyTo, + uint64 randomId, + PreparedMessage message, + Fn done, + Fn fail); + private: struct PostponedHistoryRequest { Fn finish)> generator; diff --git a/Telegram/SourceFiles/data/data_replies_list.cpp b/Telegram/SourceFiles/data/data_replies_list.cpp index d45b691ee6..c682a8067b 100644 --- a/Telegram/SourceFiles/data/data_replies_list.cpp +++ b/Telegram/SourceFiles/data/data_replies_list.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_changes.h" #include "data/data_channel.h" #include "data/data_messages.h" +#include "data/data_forum.h" #include "data/data_forum_topic.h" #include "lang/lang_keys.h" #include "apiwrap.h" @@ -36,6 +37,13 @@ constexpr auto kMessagesPerPage = 50; HistoryService::PreparedText{ { .text = text } }); } +[[nodiscard]] bool IsCreating(not_null history, MsgId rootId) { + if (const auto forum = history->peer->forum()) { + return forum->creating(rootId); + } + return false; +} + } // namespace struct RepliesList::Viewer { @@ -50,7 +58,8 @@ struct RepliesList::Viewer { RepliesList::RepliesList(not_null history, MsgId rootId) : _history(history) -, _rootId(rootId) { +, _rootId(rootId) +, _creating(IsCreating(history, rootId)) { } RepliesList::~RepliesList() { @@ -104,7 +113,9 @@ rpl::producer RepliesList::source( _history->owner().channelDifferenceTooLong( ) | rpl::filter([=](not_null channel) { - if (_history->peer != channel || !_skippedAfter.has_value()) { + if (_creating + || _history->peer != channel + || !_skippedAfter.has_value()) { return false; } _skippedAfter = std::nullopt; @@ -297,7 +308,8 @@ void RepliesList::injectRootDivider( } bool RepliesList::buildFromData(not_null viewer) { - if (_list.empty() && _skippedBefore == 0 && _skippedAfter == 0) { + if (_creating + || (_list.empty() && _skippedBefore == 0 && _skippedAfter == 0)) { viewer->slice.ids.clear(); viewer->slice.nearestToAround = FullMsgId(); viewer->slice.fullCount @@ -429,6 +441,8 @@ HistoryItem *RepliesList::lookupRoot() { } void RepliesList::loadAround(MsgId id) { + Expects(!_creating); + if (_loadingAround && *_loadingAround == id) { return; } diff --git a/Telegram/SourceFiles/data/data_replies_list.h b/Telegram/SourceFiles/data/data_replies_list.h index ed87dc0e8e..693897d43c 100644 --- a/Telegram/SourceFiles/data/data_replies_list.h +++ b/Telegram/SourceFiles/data/data_replies_list.h @@ -72,6 +72,7 @@ private: std::optional _loadingAround; HistoryService *_divider = nullptr; bool _dividerWithComments = false; + bool _creating = false; int _beforeId = 0; int _afterId = 0; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index f3dc1895a6..345503f780 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1244,7 +1244,21 @@ void Session::setupUserIsContactViewer() { }, _lifetime); } -Session::~Session() = default; +Session::~Session() { + // We must clear all 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()) { + forums.emplace(channel); + } + } + } + for (const auto &channel : forums) { + channel->setFlags(channel->flags() & ~ChannelDataFlag::Forum); + } +} template void Session::enumerateItemViews( @@ -3789,13 +3803,16 @@ void Session::refreshChatListEntry(Dialogs::Key key) { using namespace Dialogs; const auto entry = key.entry(); - const auto history = key.history(); - const auto mainList = entry->asTopic() - ? entry->asTopic()->forum()->peer->forum()->topicsList() + const auto history = entry->asHistory(); + const auto topic = entry->asTopic(); + const auto mainList = topic + ? topic->forum()->topicsList() : chatsList(entry->folder()); auto event = ChatListEntryRefresh{ .key = key }; const auto creating = event.existenceChanged = !entry->inChatList(); - if (event.existenceChanged) { + if (creating && topic && topic->forum()->creating(topic->rootId())) { + return; + } else if (event.existenceChanged) { const auto mainRow = entry->addToChatList(0, mainList); _contactsNoChatsList.del(key, mainRow); } else { @@ -3860,7 +3877,7 @@ void Session::removeChatListEntry(Dialogs::Key key) { } } const auto mainList = entry->asTopic() - ? entry->asTopic()->forum()->peer->forum()->topicsList() + ? entry->asTopic()->forum()->topicsList() : chatsList(entry->folder()); entry->removeFromChatList(0, mainList); _chatListEntryRefreshes.fire(ChatListEntryRefresh{ diff --git a/Telegram/SourceFiles/dialogs/dialogs_key.cpp b/Telegram/SourceFiles/dialogs/dialogs_key.cpp index 1c07f3622d..ecd9ad9885 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_key.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_key.cpp @@ -59,7 +59,7 @@ History *Key::parentHistory() const { if (const auto result = history()) { return result; } else if (const auto child = topic()) { - return child->forum(); + return child->history(); } return nullptr; } diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index a51c45712a..4263a43bdb 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -385,7 +385,7 @@ void Widget::chosenRow(const ChosenRow &row) { const auto history = row.key.history(); if (const auto topic = row.key.topic()) { controller()->showRepliesForMessage( - topic->forum(), + topic->history(), topic->rootId(), ShowAtUnreadMsgId, Window::SectionShow::Way::ClearStack); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 7f13049685..1a19f6db68 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1045,29 +1045,7 @@ bool HistoryItem::computeDropForwardedInfo() const { && (!media || !media->forceForwardedInfo())); } -MsgId HistoryItem::replyToId() const { - if (const auto reply = Get()) { - return reply->replyToId(); - } - return 0; -} - -MsgId HistoryItem::replyToTop() const { - if (const auto reply = Get()) { - return reply->replyToTop(); - } - return 0; -} - -MsgId HistoryItem::topicRootId() const { - if (const auto reply = Get() - ; reply && reply->topicPost) { - return reply->replyToTop(); - } - return Data::ForumTopic::kGeneralId; -} - -MsgId HistoryItem::inThread(MsgId rootId) const { +bool HistoryItem::inThread(MsgId rootId) const { const auto checkId = (rootId == Data::ForumTopic::kGeneralId) ? topicRootId() : replyToTop(); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index f1cb3ad124..84c3502a74 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -341,8 +341,7 @@ public: PeerId replier, std::optional unread) { } - virtual void setReplyToTop(MsgId replyToTop) { - } + virtual void setReplyToTop(MsgId replyToTop) = 0; virtual void setPostAuthor(const QString &author) { } virtual void setRealId(MsgId newId); @@ -405,10 +404,10 @@ public: virtual void setText(const TextWithEntities &textWithEntities) { } - [[nodiscard]] MsgId replyToId() const; - [[nodiscard]] MsgId replyToTop() const; - [[nodiscard]] MsgId topicRootId() const; - [[nodiscard]] MsgId inThread(MsgId rootId) const; + [[nodiscard]] virtual MsgId replyToId() const = 0; + [[nodiscard]] virtual MsgId replyToTop() const = 0; + [[nodiscard]] virtual MsgId topicRootId() const = 0; + [[nodiscard]] bool inThread(MsgId rootId) const; [[nodiscard]] not_null author() const; diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index e7c3ef83f1..ab1d432baa 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_changes.h" #include "data/data_media_types.h" #include "data/data_channel.h" +#include "data/data_forum_topic.h" #include "data/data_user.h" #include "data/data_web_page.h" #include "data/data_sponsored_messages.h" @@ -1490,6 +1491,28 @@ TextWithEntities HistoryMessage::withLocalEntities( return textWithEntities; } +MsgId HistoryMessage::replyToId() const { + if (const auto reply = Get()) { + return reply->replyToId(); + } + return 0; +} + +MsgId HistoryMessage::replyToTop() const { + if (const auto reply = Get()) { + return reply->replyToTop(); + } + return 0; +} + +MsgId HistoryMessage::topicRootId() const { + if (const auto reply = Get() + ; reply && reply->topicPost) { + return reply->replyToTop(); + } + return Data::ForumTopic::kGeneralId; +} + void HistoryMessage::setText(const TextWithEntities &textWithEntities) { for (const auto &entity : textWithEntities.entities) { auto type = entity.type(); diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index ccc25e8beb..400e8b03be 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -180,6 +180,10 @@ public: void destroyHistoryEntry() override; [[nodiscard]] Storage::SharedMediaTypesMask sharedMediaTypes() const override; + [[nodiscard]] MsgId replyToId() const override; + [[nodiscard]] MsgId replyToTop() const override; + [[nodiscard]] MsgId topicRootId() const override; + void setText(const TextWithEntities &textWithEntities) override; [[nodiscard]] TextWithEntities originalText() const override; [[nodiscard]] auto originalTextWithLocalEntities() const diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index 5841ee9e1a..c568645aa8 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_item_preview.h" #include "data/data_folder.h" #include "data/data_forum.h" +#include "data/data_forum_topic.h" #include "data/data_session.h" #include "data/data_media_types.h" #include "data/data_game.h" @@ -30,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_changes.h" #include "data/data_group_call.h" // Data::GroupCall::id(). +#include "data/stickers/data_custom_emoji.h" #include "core/application.h" #include "core/click_handler_types.h" #include "base/unixtime.h" @@ -652,13 +654,15 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { auto result = PreparedText{}; result.text = { "topic icon: " }; // #TODO forum lang result.text.append(TextWithEntities{ - " ", + "@", { EntityInText( EntityType::CustomEmoji, 0, 1, - QString::number(+action.vemoji_document_id().v)) }, + Data::SerializeCustomEmojiId({ + .id = action.vemoji_document_id().v })) }, }); + return result; }; @@ -800,7 +804,20 @@ void HistoryService::applyAction(const MTPMessageAction &action) { data.vmonths().v); }, [&](const MTPDmessageActionTopicCreate &data) { if (const auto forum = history()->peer->forum()) { - forum->applyTopicAdded(id, qs(data.vtitle())); + const auto iconId = DocumentId(0); // #TODO forum icon + forum->applyTopicAdded(id, qs(data.vtitle()), iconId); + } + }, [&](const MTPDmessageActionTopicEditTitle &data) { + if (const auto forum = history()->peer->forum()) { + if (const auto topic = forum->topicFor(replyToTop())) { + topic->applyTitle(qs(data.vtitle())); + } + } + }, [&](const MTPDmessageActionTopicEditIcon &data) { + if (const auto forum = history()->peer->forum()) { + if (const auto topic = forum->topicFor(replyToTop())) { + topic->applyIconId(data.vemoji_document_id().v); + } } }, [](const auto &) { }); @@ -1299,6 +1316,36 @@ TextWithEntities HistoryService::inReplyText() const { return Ui::Text::Wrapped(result, EntityType::PlainLink); } +MsgId HistoryService::replyToId() const { + return 0; // Don't render replies info in service, only handle threads. +} + +MsgId HistoryService::replyToTop() const { + if (const auto data = GetDependentData()) { + return data->topId; + } + return 0; +} + +MsgId HistoryService::topicRootId() const { + if (const auto data = GetDependentData() + ; data && data->topicPost) { + return data->topId; + } + return Data::ForumTopic::kGeneralId; +} + +void HistoryService::setReplyToTop(MsgId replyToTop) { + const auto data = GetDependentData(); + if (!data + || (data->topId == replyToTop) + || (data->topId != 0) + || isScheduled()) { + return; + } + data->topId = replyToTop; +} + std::unique_ptr HistoryService::createView( not_null delegate, HistoryView::Element *replacing) { @@ -1422,7 +1469,13 @@ void HistoryService::createFromMtp(const MTPDmessage &message) { void HistoryService::createFromMtp(const MTPDmessageService &message) { const auto type = message.vaction().type(); - if (type == mtpc_messageActionSetChatTheme) { + if (type == mtpc_messageActionPinMessage) { + UpdateComponents(HistoryServicePinned::Bit()); + } else if (type == mtpc_messageActionTopicCreate + || type == mtpc_messageActionTopicEditTitle + || type == mtpc_messageActionTopicEditIcon) { + UpdateComponents(HistoryServiceTopicInfo::Bit()); + } else if (type == mtpc_messageActionSetChatTheme) { setupChatThemeChange(); } else if (type == mtpc_messageActionSetMessagesTTL) { setupTTLChange(); @@ -1505,14 +1558,13 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) { const auto peerId = data.vreply_to_peer_id() ? peerFromMTP(*data.vreply_to_peer_id()) : history()->peer->id; - if (message.vaction().type() == mtpc_messageActionPinMessage) { - UpdateComponents(HistoryServicePinned::Bit()); - } if (const auto dependent = GetDependentData()) { dependent->peerId = (peerId != history()->peer->id) ? peerId : 0; dependent->msgId = data.vreply_to_msg_id().v; + dependent->topId = data.vreply_to_top_id().value_or( + data.vreply_to_msg_id().v); if (!updateDependent()) { RequestDependentMessageData( this, diff --git a/Telegram/SourceFiles/history/history_service.h b/Telegram/SourceFiles/history/history_service.h index daac1eacfd..9d3aff08f6 100644 --- a/Telegram/SourceFiles/history/history_service.h +++ b/Telegram/SourceFiles/history/history_service.h @@ -15,9 +15,11 @@ class Service; struct HistoryServiceDependentData { PeerId peerId = 0; - MsgId msgId = 0; HistoryItem *msg = nullptr; ClickHandlerPtr lnk; + MsgId msgId = 0; + MsgId topId = 0; + bool topicPost = false; }; struct HistoryServicePinned @@ -25,6 +27,11 @@ struct HistoryServicePinned , public HistoryServiceDependentData { }; +struct HistoryServiceTopicInfo +: public RuntimeComponent +, public HistoryServiceDependentData { +}; + struct HistoryServiceGameScore : public RuntimeComponent , public HistoryServiceDependentData { @@ -129,6 +136,11 @@ public: ItemPreview toPreview(ToPreviewOptions options) const override; TextWithEntities inReplyText() const override; + MsgId replyToId() const override; + MsgId replyToTop() const override; + MsgId topicRootId() const override; + void setReplyToTop(MsgId replyToTop) override; + std::unique_ptr createView( not_null delegate, HistoryView::Element *replacing = nullptr) override; @@ -149,12 +161,14 @@ protected: private: HistoryServiceDependentData *GetDependentData() { - if (auto pinned = Get()) { + if (const auto pinned = Get()) { return pinned; - } else if (auto gamescore = Get()) { + } else if (const auto gamescore = Get()) { return gamescore; - } else if (auto payment = Get()) { + } else if (const auto payment = Get()) { return payment; + } else if (const auto info = Get()) { + return info; } return nullptr; } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 3317968519..2cbdaf8946 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -72,6 +72,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_window.h" #include "styles/style_info.h" #include "styles/style_boxes.h" +#include "styles/style_layers.h" #include @@ -332,6 +333,10 @@ RepliesWidget::RepliesWidget( } RepliesWidget::~RepliesWidget() { + if (_topic && _topic->forum()->creating(_rootId)) { + _topic->forum()->discardCreatingId(_rootId); + _topic = nullptr; + } if (_readRequestTimer.isActive()) { sendReadTillRequest(); } @@ -895,7 +900,7 @@ std::optional RepliesWidget::writeRestriction() const { } void RepliesWidget::pushReplyReturn(not_null item) { - if (item->history() == _history && item->replyToTop() == _rootId) { + if (item->history() == _history && item->inThread(_rootId)) { _replyReturns.push_back(item->id); } else { return; @@ -1542,7 +1547,30 @@ Dialogs::RowDescriptor RepliesWidget::activeChat() const { } bool RepliesWidget::preventsClose(Fn &&continueCallback) const { - return _composeControls->preventsClose(std::move(continueCallback)); + if (_composeControls->preventsClose(base::duplicate(continueCallback))) { + return true; + } else if (!_newTopicDiscarded + && _topic + && _topic->forum()->creating(_rootId)) { + const auto weak = Ui::MakeWeak(this); + auto sure = [=](Fn &&close) { + if (const auto strong = weak.data()) { + strong->_newTopicDiscarded = true; + } + close(); + if (continueCallback) { + continueCallback(); + } + }; + controller()->show(Ui::MakeConfirmBox({ + .text = rpl::single(u"Sure discard?"_q), // #TODO forum lang + .confirmed = std::move(sure), + .confirmText = tr::lng_record_lock_discard(), + .confirmStyle = &st::attentionBoxButton, + })); + return true; + } + return false; } QPixmap RepliesWidget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) { @@ -1628,7 +1656,7 @@ bool RepliesWidget::showMessage( && _inner->viewByPosition(returnTo->position()) && returnTo->replyToId() == messageId) { return returnTo; - } else if (!general && (returnTo->replyToTop() == _rootId)) { + } else if (!general && returnTo->inThread(_rootId)) { return returnTo; } } @@ -1655,7 +1683,6 @@ Window::SectionActionResult RepliesWidget::sendBotCommand( } void RepliesWidget::replyToMessage(FullMsgId itemId) { - // if (item->history() != _history || item->replyToTop() != _rootId) { _composeControls->replyToMessage(itemId); refreshTopBarActiveChat(); } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index 0bbb714f57..806133c519 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -269,10 +269,11 @@ private: [[nodiscard]] std::optional writeRestriction() const; const not_null _history; - const MsgId _rootId = 0; + MsgId _rootId = 0; std::shared_ptr _theme; HistoryItem *_root = nullptr; Data::ForumTopic *_topic = nullptr; + mutable bool _newTopicDiscarded = false; std::shared_ptr _replies; rpl::variable _areComments = false; diff --git a/Telegram/SourceFiles/info/info_content_widget.cpp b/Telegram/SourceFiles/info/info_content_widget.cpp index b6e85972a4..10b21c08df 100644 --- a/Telegram/SourceFiles/info/info_content_widget.cpp +++ b/Telegram/SourceFiles/info/info_content_widget.cpp @@ -21,9 +21,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/info_controller.h" #include "boxes/peer_list_box.h" #include "data/data_chat.h" +#include "data/data_channel.h" #include "data/data_session.h" #include "data/data_forum_topic.h" -#include "history/history.h" #include "main/main_session.h" #include "styles/style_info.h" #include "styles/style_profile.h" @@ -337,7 +337,7 @@ Key ContentMemento::key() const { } ContentMemento::ContentMemento(not_null topic) -: _peer(topic->forum()->peer) +: _peer(topic->channel()) , _migratedPeerId(_peer->migrateFrom() ? _peer->migrateFrom()->id : 0) , _topic(topic) { } diff --git a/Telegram/SourceFiles/info/info_controller.cpp b/Telegram/SourceFiles/info/info_controller.cpp index fe42ecab56..a374ba2ee3 100644 --- a/Telegram/SourceFiles/info/info_controller.cpp +++ b/Telegram/SourceFiles/info/info_controller.cpp @@ -22,7 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_media_types.h" #include "data/data_download_manager.h" #include "history/history_item.h" -#include "history/history.h" #include "main/main_session.h" #include "window/window_session_controller.h" @@ -48,7 +47,7 @@ PeerData *Key::peer() const { if (const auto peer = std::get_if>(&_value)) { return *peer; } else if (const auto topic = this->topic()) { - return topic->forum()->peer; + return topic->channel(); } return nullptr; } diff --git a/Telegram/SourceFiles/storage/file_upload.cpp b/Telegram/SourceFiles/storage/file_upload.cpp index 3105d99a5d..a1098e9096 100644 --- a/Telegram/SourceFiles/storage/file_upload.cpp +++ b/Telegram/SourceFiles/storage/file_upload.cpp @@ -257,7 +257,7 @@ void Uploader::sendProgressUpdate( const auto history = item->history(); auto &manager = _api->session().sendProgressManager(); manager.update(history, type, progress); - if (const auto replyTo = item->replyToTop()) { + if (const auto replyTo = item->topicRootId()) { if (history->peer->isMegagroup()) { manager.update(history, replyTo, type, progress); } diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 736fed8089..0252734d86 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -752,7 +752,7 @@ void Filler::addManageTopic() { return; } // #TODO forum lang - const auto history = _topic->forum(); + const auto history = _topic->history(); const auto rootId = _topic->rootId(); const auto navigation = _controller; _addAction(u"Edit topic"_q, [=] {