From 602ba5bba951986ee71b6e956411286fbf6325a6 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 25 Oct 2022 11:20:22 +0400 Subject: [PATCH] Implement correct ForumTopic::canWrite logic. --- Telegram/SourceFiles/apiwrap.cpp | 26 ++- .../boxes/peers/add_bot_to_chat_box.cpp | 2 +- .../boxes/peers/edit_peer_invite_link.cpp | 5 +- Telegram/SourceFiles/boxes/share_box.cpp | 7 +- .../calls/group/calls_group_members.cpp | 2 +- .../calls/group/calls_group_panel.cpp | 2 +- .../calls/group/calls_group_settings.cpp | 7 +- Telegram/SourceFiles/data/data_channel.cpp | 7 +- Telegram/SourceFiles/data/data_channel.h | 2 +- Telegram/SourceFiles/data/data_forum.cpp | 7 + Telegram/SourceFiles/data/data_forum.h | 2 + .../SourceFiles/data/data_forum_topic.cpp | 7 + Telegram/SourceFiles/data/data_forum_topic.h | 1 + Telegram/SourceFiles/data/data_peer.cpp | 4 +- Telegram/SourceFiles/data/data_peer.h | 2 +- .../SourceFiles/data/data_peer_values.cpp | 51 ++++- Telegram/SourceFiles/data/data_peer_values.h | 10 +- Telegram/SourceFiles/history/history.cpp | 3 + .../history/history_inner_widget.cpp | 15 +- Telegram/SourceFiles/history/history_item.cpp | 8 +- .../SourceFiles/history/history_message.cpp | 51 ++--- .../SourceFiles/history/history_message.h | 16 +- .../SourceFiles/history/history_widget.cpp | 183 +++++++++++++----- Telegram/SourceFiles/history/history_widget.h | 6 + .../view/history_view_context_menu.cpp | 5 +- .../history/view/history_view_message.cpp | 2 +- .../view/history_view_replies_section.cpp | 11 +- .../inline_bots/bot_attach_web_view.cpp | 2 +- .../main/session/send_as_peers.cpp | 2 +- Telegram/SourceFiles/mainwidget.cpp | 19 +- .../mac/touchbar/items/mac_scrubber_item.mm | 14 +- .../mac/touchbar/mac_touchbar_manager.mm | 7 +- .../window/notifications_manager.cpp | 11 +- .../SourceFiles/window/window_peer_menu.cpp | 6 +- Telegram/lib_ui | 2 +- 35 files changed, 363 insertions(+), 144 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index e27fe368d..3d1c5b185 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -513,6 +513,12 @@ void ApiWrap::sendMessageFail( Assert(randomId != 0); _session->data().unregisterMessageRandomId(randomId); item->sendFailed(); + + if (error == u"TOPIC_CLOSED"_q) { + if (const auto topic = item->topic()) { + topic->setClosed(true); + } + } } } @@ -3005,7 +3011,10 @@ void ApiWrap::finishForwarding(const SendAction &action) { if (!toForward.items.empty()) { const auto error = GetErrorTextForSending( history->peer, - toForward.items); + { + .topicRootId = action.topicRootId, + .forward = &toForward.items, + }); if (!error.isEmpty()) { return; } @@ -3074,6 +3083,9 @@ void ApiWrap::forwardMessages( if (sendAs) { sendFlags |= MTPmessages_ForwardMessages::Flag::f_send_as; } + if (action.topicRootId) { + sendFlags |= MTPmessages_ForwardMessages::Flag::f_top_msg_id; + } auto forwardFrom = draft.items.front()->history()->peer; auto ids = QVector<MTPint>(); @@ -3093,7 +3105,7 @@ void ApiWrap::forwardMessages( MTP_vector<MTPint>(ids), MTP_vector<MTPlong>(randomIds), peer->input, - MTPint(), // top_msg_id + MTP_int(action.topicRootId), MTP_int(action.options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()) )).done([=](const MTPUpdates &result) { @@ -3145,7 +3157,7 @@ void ApiWrap::forwardMessages( HistoryItem::NewMessageDate(action.options.scheduled), messageFromId, messagePostAuthor, - item); + item); // #TODO forum forward _session->data().registerMessageRandomId(randomId, newId); if (!localIds) { localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>(); @@ -3405,7 +3417,13 @@ void ApiWrap::sendMessage(MessageToSend &&message) { action.generateLocal = true; sendAction(action); - if (!peer->canWrite() || Api::SendDice(message)) { + const auto replyToId = message.action.replyTo; + const auto replyTo = replyToId + ? peer->owner().message(peer, replyToId) + : nullptr; + const auto topic = replyTo ? replyTo->topic() : nullptr; + if (!(topic ? topic->canWrite() : peer->canWrite()) + || Api::SendDice(message)) { return; } local().saveRecentSentHashtags(textWithTags.text); 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 4e636da93..86c41e28a 100644 --- a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp @@ -342,7 +342,7 @@ auto AddBotToGroupBoxController::createRow(not_null<History*> history) bool AddBotToGroupBoxController::needToCreateRow( not_null<PeerData*> peer) const { if (sharingBotGame()) { - if (!peer->canWrite() + if (!peer->canWrite() // #TODO forum forward || peer->amRestricted(ChatRestriction::SendGames)) { return false; } diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp index 3f1e5b898..20acec9ad 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp @@ -1153,8 +1153,7 @@ object_ptr<Ui::BoxContent> ShareInviteLinkBox( for (const auto peer : result) { const auto error = GetErrorTextForSending( peer, - {}, - comment); + { .text = &comment }); if (!error.isEmpty()) { return std::make_pair(error, peer); } @@ -1205,7 +1204,7 @@ object_ptr<Ui::BoxContent> ShareInviteLinkBox( auto object = Box<ShareBox>(ShareBox::Descriptor{ .session = &peer->session(), .copyCallback = std::move(copyCallback), - .submitCallback = std::move(submitCallback), + .submitCallback = std::move(submitCallback), // #TODO forum forward .filterCallback = [](auto peer) { return peer->canWrite(); }, }); *box = Ui::MakeWeak(object.data()); diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index f18ab9324..10817279a 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -1292,11 +1292,10 @@ void FastShareMessage( } const auto error = [&] { - for (const auto peer : result) { + for (const auto peer : result) { // #TODO forum forward const auto error = GetErrorTextForSending( peer, - items, - comment); + { .forward = &items, .text = &comment }); if (!error.isEmpty()) { return std::make_pair(error, peer); } @@ -1399,7 +1398,7 @@ void FastShareMessage( } }; auto filterCallback = [isGame](PeerData *peer) { - if (peer->canWrite()) { + if (peer->canWrite()) { // #TODO forum forward if (auto channel = peer->asChannel()) { return isGame ? (!channel->isBroadcast()) : true; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_members.cpp b/Telegram/SourceFiles/calls/group/calls_group_members.cpp index f97807d6d..ebc047926 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members.cpp @@ -1642,7 +1642,7 @@ void Members::setupAddMember(not_null<GroupCall*> call) { return rpl::single(false) | rpl::type_erased(); } return rpl::combine( - Data::CanWriteValue(peer.get()), + Data::CanWriteValue(peer, false), _call->joinAsValue() ) | rpl::map([=](bool can, not_null<PeerData*> joinAs) { return can && joinAs->isSelf(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 76e0d0ef3..9d8d38a38 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -845,7 +845,7 @@ void Panel::setupMembers() { _members->addMembersRequests( ) | rpl::start_with_next([=] { if (!_peer->isBroadcast() - && _peer->canWrite() + && _peer->canWrite(false) && _call->joinAs()->isSelf()) { addMembers(); } else if (const auto channel = _peer->asChannel()) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_settings.cpp b/Telegram/SourceFiles/calls/group/calls_group_settings.cpp index 260f353d3..c8add875a 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_settings.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_settings.cpp @@ -141,11 +141,10 @@ object_ptr<ShareBox> ShareInviteLinkBox( } const auto error = [&] { - for (const auto peer : result) { + for (const auto peer : result) { // #TODO forum forward const auto error = GetErrorTextForSending( peer, - {}, - comment); + { .text = &comment }); if (!error.isEmpty()) { return std::make_pair(error, peer); } @@ -196,7 +195,7 @@ object_ptr<ShareBox> ShareInviteLinkBox( showToast(tr::lng_share_done(tr::now)); }; auto filterCallback = [](PeerData *peer) { - return peer->canWrite(); + return peer->canWrite(); // #TODO forum forward }; const auto scheduleStyle = [&] { diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index e9434c40a..6b99cb392 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -552,11 +552,14 @@ bool ChannelData::canPublish() const { || (adminRights() & AdminRight::PostMessages); } -bool ChannelData::canWrite() const { +bool ChannelData::canWrite(bool checkForForum) const { // Duplicated in Data::CanWriteValue(). const auto allowed = amIn() || ((flags() & Flag::HasLink) && !(flags() & Flag::JoinToWrite)); - return allowed && (canPublish() + const auto forumRestriction = checkForForum && isForum(); + return allowed + && !forumRestriction + && (canPublish() || (!isBroadcast() && !amRestricted(Restriction::SendMessages))); } diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index 73a7cc2b4..6e139bb0e 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -313,7 +313,7 @@ public: void setDefaultRestrictions(ChatRestrictions rights); // Like in ChatData. - [[nodiscard]] bool canWrite() const; + [[nodiscard]] bool canWrite(bool checkForForum = true) const; [[nodiscard]] bool allowsForwarding() const; [[nodiscard]] bool canEditInformation() const; [[nodiscard]] bool canEditPermissions() const; diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index 923739357..5a1779b5c 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -160,6 +160,8 @@ void Forum::applyReceivedTopics(const MTPmessages_ForumTopics &result) { } void Forum::applyTopicDeleted(MsgId rootId) { + _topicsDeleted.emplace(rootId); + const auto i = _topics.find(rootId); if (i != end(_topics)) { const auto raw = i->second.get(); @@ -192,6 +194,7 @@ void Forum::applyReceivedTopics( } applyTopicDeleted(rootId); }, [&](const MTPDforumTopic &data) { + _topicsDeleted.remove(rootId); const auto i = _topics.find(rootId); const auto creating = (i == end(_topics)); const auto raw = creating @@ -410,6 +413,10 @@ ForumTopic *Forum::enforceTopicFor(MsgId rootId) { return result; } +bool Forum::topicDeleted(MsgId rootId) const { + return _topicsDeleted.contains(rootId); +} + rpl::producer<> Forum::chatsListChanges() const { return _chatsListChanges.events(); } diff --git a/Telegram/SourceFiles/data/data_forum.h b/Telegram/SourceFiles/data/data_forum.h index fce162ec2..04aa3f896 100644 --- a/Telegram/SourceFiles/data/data_forum.h +++ b/Telegram/SourceFiles/data/data_forum.h @@ -55,6 +55,7 @@ public: void applyTopicDeleted(MsgId rootId); [[nodiscard]] ForumTopic *topicFor(MsgId rootId); [[nodiscard]] ForumTopic *enforceTopicFor(MsgId rootId); + [[nodiscard]] bool topicDeleted(MsgId rootId) const; void applyReceivedTopics(const MTPmessages_ForumTopics &topics); @@ -90,6 +91,7 @@ private: const not_null<History*> _history; base::flat_map<MsgId, std::unique_ptr<ForumTopic>> _topics; + base::flat_set<MsgId> _topicsDeleted; rpl::event_stream<not_null<ForumTopic*>> _topicDestroyed; Dialogs::MainList _topicsList; diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index 9bb0acefe..2416f10ce 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -205,6 +205,13 @@ bool ForumTopic::my() const { return (_flags & Flag::My); } +bool ForumTopic::canWrite() const { + const auto channel = this->channel(); + return channel->amIn() + && !channel->amRestricted(ChatRestriction::SendMessages) + && (!closed() || canToggleClosed()); +} + bool ForumTopic::canEdit() const { return my() || channel()->canManageTopics(); } diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h index 48ee8162b..7e3d9e4e5 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.h +++ b/Telegram/SourceFiles/data/data_forum_topic.h @@ -62,6 +62,7 @@ public: [[nodiscard]] MsgId rootId() const; [[nodiscard]] bool my() const; + [[nodiscard]] bool canWrite() const; [[nodiscard]] bool canEdit() const; [[nodiscard]] bool canToggleClosed() const; [[nodiscard]] bool canTogglePinned() const; diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 2b89ab335..8dbc5770b 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -937,11 +937,11 @@ Data::ForumTopic *PeerData::forumTopicFor(MsgId rootId) const { } -bool PeerData::canWrite() const { +bool PeerData::canWrite(bool checkForForum) const { if (const auto user = asUser()) { return user->canWrite(); } else if (const auto channel = asChannel()) { - return channel->canWrite(); + return channel->canWrite(checkForForum); } else if (const auto chat = asChat()) { return chat->canWrite(); } diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index f79f34e79..9c3e992c2 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -207,7 +207,7 @@ public: return _notify; } - [[nodiscard]] bool canWrite() const; + [[nodiscard]] bool canWrite(bool checkForForum = true) const; [[nodiscard]] bool allowsForwarding() const; [[nodiscard]] Data::RestrictionCheckResult amRestricted( ChatRestriction right) const; diff --git a/Telegram/SourceFiles/data/data_peer_values.cpp b/Telegram/SourceFiles/data/data_peer_values.cpp index 08feba690..ae46d9d6f 100644 --- a/Telegram/SourceFiles/data/data_peer_values.cpp +++ b/Telegram/SourceFiles/data/data_peer_values.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_user.h" #include "data/data_changes.h" +#include "data/data_forum_topic.h" #include "data/data_session.h" #include "data/data_message_reactions.h" #include "main/main_session.h" @@ -201,10 +202,11 @@ rpl::producer<bool> CanWriteValue(ChatData *chat) { }); } -rpl::producer<bool> CanWriteValue(ChannelData *channel) { +rpl::producer<bool> CanWriteValue(ChannelData *channel, bool checkForForum) { using Flag = ChannelDataFlag; const auto mask = 0 | Flag::Left + | Flag::Forum | Flag::JoinToWrite | Flag::HasLink | Flag::Forbidden @@ -221,15 +223,19 @@ rpl::producer<bool> CanWriteValue(ChannelData *channel) { DefaultRestrictionValue( channel, ChatRestriction::SendMessages), - []( + [=]( ChannelDataFlags flags, bool postMessagesRight, bool sendMessagesRestriction, bool defaultSendMessagesRestriction) { const auto notAmInFlags = Flag::Left | Flag::Forbidden; + const auto forumRestriction = checkForForum + && (flags & Flag::Forum); const auto allowed = !(flags & notAmInFlags) || ((flags & Flag::HasLink) && !(flags & Flag::JoinToWrite)); - return allowed && (postMessagesRight + return allowed + && !forumRestriction + && (postMessagesRight || (flags & Flag::Creator) || (!(flags & Flag::Broadcast) && !sendMessagesRestriction @@ -237,17 +243,52 @@ rpl::producer<bool> CanWriteValue(ChannelData *channel) { }); } -rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer) { +rpl::producer<bool> CanWriteValue( + not_null<PeerData*> peer, + bool checkForForum) { if (auto user = peer->asUser()) { return CanWriteValue(user); } else if (auto chat = peer->asChat()) { return CanWriteValue(chat); } else if (auto channel = peer->asChannel()) { - return CanWriteValue(channel); + return CanWriteValue(channel, checkForForum); } Unexpected("Bad peer value in CanWriteValue"); } +rpl::producer<bool> CanWriteValue(not_null<ForumTopic*> topic) { + using Flag = ChannelDataFlag; + const auto mask = 0 + | Flag::Left + | Flag::JoinToWrite + | Flag::Forum + | Flag::Forbidden; + const auto channel = topic->channel(); + return rpl::combine( + PeerFlagsValue(channel.get(), mask), + RestrictionValue( + channel, + ChatRestriction::SendMessages), + DefaultRestrictionValue( + channel, + ChatRestriction::SendMessages), + topic->session().changes().topicFlagsValue( + topic, + TopicUpdate::Flag::Closed), + [=]( + ChannelDataFlags flags, + bool sendMessagesRestriction, + bool defaultSendMessagesRestriction, + auto) { + const auto notAmInFlags = Flag::Left | Flag::Forbidden; + const auto allowed = !(flags & notAmInFlags); + return allowed + && !sendMessagesRestriction + && !defaultSendMessagesRestriction + && (!topic->closed() || topic->canToggleClosed()); + }); +} + // This is duplicated in PeerData::canPinMessages(). rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer) { using namespace rpl::mappers; diff --git a/Telegram/SourceFiles/data/data_peer_values.h b/Telegram/SourceFiles/data/data_peer_values.h index 7a5911775..72374bf0c 100644 --- a/Telegram/SourceFiles/data/data_peer_values.h +++ b/Telegram/SourceFiles/data/data_peer_values.h @@ -21,6 +21,7 @@ class Session; namespace Data { struct Reaction; +class ForumTopic; template <typename ChangeType, typename Error, typename Generator> inline auto FlagsValueWithMask( @@ -102,8 +103,13 @@ inline auto PeerFullFlagValue( [[nodiscard]] rpl::producer<bool> CanWriteValue(UserData *user); [[nodiscard]] rpl::producer<bool> CanWriteValue(ChatData *chat); -[[nodiscard]] rpl::producer<bool> CanWriteValue(ChannelData *channel); -[[nodiscard]] rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer); +[[nodiscard]] rpl::producer<bool> CanWriteValue( + ChannelData *channel, + bool checkForForum = true); +[[nodiscard]] rpl::producer<bool> CanWriteValue( + not_null<PeerData*> peer, + bool checkForForum = true); +[[nodiscard]] rpl::producer<bool> CanWriteValue(not_null<ForumTopic*> topic); [[nodiscard]] rpl::producer<bool> CanPinMessagesValue( not_null<PeerData*> peer); [[nodiscard]] rpl::producer<bool> CanManageGroupCallValue( diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 3d48d60bd..87cc62102 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1133,6 +1133,9 @@ void History::applyServiceChanges( if (const auto icon = data.vicon_emoji_id()) { topic->applyIconId(icon->v); } + if (const auto closed = data.vclosed()) { + topic->setClosed(mtpIsTrue(*closed)); + } } }, [](const auto &) { }); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 12d181bef..73033ce99 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -76,6 +76,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_message_reactions.h" #include "data/data_document.h" #include "data/data_channel.h" +#include "data/data_forum_topic.h" #include "data/data_poll.h" #include "data/data_photo.h" #include "data/data_photo_media.h" @@ -2003,7 +2004,6 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { return; } auto selectedState = getSelectionState(); - auto canSendMessages = _peer->canWrite(); // -2 - has full selected items, but not over, -1 - has selection, but no over, 0 - no selection, 1 - over text, 2 - over full selected items auto isUponSelected = 0; @@ -2079,7 +2079,18 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { return; } const auto itemId = item->fullId(); - if (canSendMessages) { + const auto canReply = [&] { + const auto peer = item->history()->peer; + if (const auto forum = item->history()->peer->forum()) { + const auto topicRootId = item->topicRootId(); + const auto topic = item->topic(); + return topic + ? topic->canWrite() + : peer->canWrite(!topicRootId); + } + return peer->canWrite(); + }(); + if (canReply) { _menu->addAction(tr::lng_context_reply_msg(tr::now), [=] { _widget->replyToMessage(itemId); }, &st::menuIconReply); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index c7eed9029..61e82e580 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -798,7 +798,13 @@ bool HistoryItem::canBeEdited() const { if (isPost() && channel->canEditMessages()) { return true; } else if (out()) { - return isPost() ? channel->canPublish() : channel->canWrite(); + if (isPost()) { + return channel->canPublish(); + } else if (const auto topic = this->topic()) { + return topic->canWrite(); + } else { + return channel->canWrite(); + } } else { return false; } diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 023b4b782..aaf15e69e 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -107,44 +107,52 @@ namespace { QString GetErrorTextForSending( not_null<PeerData*> peer, - const HistoryItemsList &items, - const TextWithTags &comment, - bool ignoreSlowmodeCountdown) { - if (!peer->canWrite()) { + SendingErrorRequest request) { + const auto forum = request.topicRootId ? peer->forum() : nullptr; + const auto topic = forum + ? forum->topicFor(request.topicRootId) + : nullptr; + if (!(topic ? topic->canWrite() : peer->canWrite())) { return tr::lng_forward_cant(tr::now); } - for (const auto &item : items) { - if (const auto media = item->media()) { - const auto error = media->errorTextForForward(peer); - if (!error.isEmpty() && error != qstr("skip")) { - return error; + if (request.forward) { + for (const auto &item : *request.forward) { + if (const auto media = item->media()) { + const auto error = media->errorTextForForward(peer); + if (!error.isEmpty() && error != qstr("skip")) { + return error; + } } } } const auto error = Data::RestrictionError( peer, ChatRestriction::SendInline); - if (error && HasInlineItems(items)) { + if (error && request.forward && HasInlineItems(*request.forward)) { return *error; } if (peer->slowmodeApplied()) { + const auto hasText = (request.text && !request.text->empty()); + const auto count = (hasText ? 1 : 0) + + (request.forward ? int(request.forward->size()) : 0); if (const auto history = peer->owner().historyLoaded(peer)) { - if (!ignoreSlowmodeCountdown + if (!request.ignoreSlowmodeCountdown && (history->latestSendingMessage() != nullptr) - && (!items.empty() || !comment.text.isEmpty())) { + && (count > 0)) { return tr::lng_slowmode_no_many(tr::now); } } - if (comment.text.size() > MaxMessageSize) { + if (request.text && request.text->text.size() > MaxMessageSize) { return tr::lng_slowmode_too_long(tr::now); - } else if (!items.empty() && !comment.text.isEmpty()) { + } else if (hasText && count > 1) { return tr::lng_slowmode_no_many(tr::now); - } else if (items.size() > 1) { + } else if (count > 1) { const auto albumForward = [&] { - if (const auto groupId = items.front()->groupId()) { - for (const auto &item : items) { + const auto first = request.forward->front(); + if (const auto groupId = first->groupId()) { + for (const auto &item : *request.forward) { if (item->groupId() != groupId) { return false; } @@ -159,7 +167,7 @@ QString GetErrorTextForSending( } } if (const auto left = peer->slowmodeSecondsLeft()) { - if (!ignoreSlowmodeCountdown) { + if (!request.ignoreSlowmodeCountdown) { return tr::lng_slowmode_enabled( tr::now, lt_left, @@ -242,13 +250,6 @@ MTPMessageReplyHeader NewMessageReplyHeader(const Api::SendAction &action) { return MTPMessageReplyHeader(); } -QString GetErrorTextForSending( - not_null<PeerData*> peer, - const HistoryItemsList &items, - bool ignoreSlowmodeCountdown) { - return GetErrorTextForSending(peer, items, {}, ignoreSlowmodeCountdown); -} - TextWithEntities DropCustomEmoji(TextWithEntities text) { text.entities.erase( ranges::remove( diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index 5a23a25ba..e12778688 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -40,15 +40,17 @@ void RequestDependentMessageData( MsgId replyToId); [[nodiscard]] MTPMessageReplyHeader NewMessageReplyHeader( const Api::SendAction &action); + +struct SendingErrorRequest { + MsgId topicRootId = 0; + const HistoryItemsList *forward = nullptr; + const TextWithTags *text = nullptr; + bool ignoreSlowmodeCountdown = false; +}; [[nodiscard]] QString GetErrorTextForSending( not_null<PeerData*> peer, - const HistoryItemsList &items, - bool ignoreSlowmodeCountdown = false); -[[nodiscard]] QString GetErrorTextForSending( - not_null<PeerData*> peer, - const HistoryItemsList &items, - const TextWithTags &comment, - bool ignoreSlowmodeCountdown = false); + SendingErrorRequest request); + [[nodiscard]] TextWithEntities DropCustomEmoji(TextWithEntities text); class HistoryMessage final : public HistoryItem { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 0e32ce8a4..53d662ceb 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -65,6 +65,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_media_types.h" #include "data/data_channel.h" #include "data/data_chat.h" +#include "data/data_forum.h" +#include "data/data_forum_topic.h" #include "data/data_user.h" #include "data/data_chat_filters.h" #include "data/data_scheduled_messages.h" @@ -1902,8 +1904,8 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) { auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0); clearFieldText(0, fieldHistoryAction); _field->setFocus(); - _replyEditMsg = nullptr; - _replyToId = 0; + _processingReplyItem = _replyEditMsg = nullptr; + _processingReplyId = _replyToId = 0; setEditMsgId(0); if (fieldWillBeHiddenAfterEdit) { updateControlsVisibility(); @@ -1926,23 +1928,25 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) { _parsedLinks = _fieldLinksParser->list().current(); _previewState = draft->previewState; - _replyEditMsg = nullptr; + _processingReplyItem = _replyEditMsg = nullptr; + _processingReplyId = _replyToId = 0; if (const auto editDraft = _history->localEditDraft({})) { setEditMsgId(editDraft->msgId); - _replyToId = 0; } else { - _replyToId = readyToForward() ? 0 : _history->localDraft({})->msgId; setEditMsgId(0); } updateCmdStartShown(); updateControlsVisibility(); updateControlsGeometry(); refreshTopBarActiveChat(); - if (_editMsgId || _replyToId) { + if (_editMsgId) { updateReplyEditTexts(); if (!_replyEditMsg) { - requestMessageData(_editMsgId ? _editMsgId : _replyToId); + requestMessageData(_editMsgId); } + } else if (!readyToForward()) { + _processingReplyId = _history->localDraft({})->msgId; + processReply(); } } @@ -2105,8 +2109,8 @@ void HistoryWidget::showHistory( HistoryView::Element::ClearGlobal(); _saveEditMsgRequestId = 0; - _replyEditMsg = nullptr; - _editMsgId = _replyToId = 0; + _processingReplyItem = _replyEditMsg = nullptr; + _processingReplyId = _editMsgId = _replyToId = 0; _previewData = nullptr; _previewCache.clear(); _fieldBarCancel->hide(); @@ -2503,7 +2507,7 @@ void HistoryWidget::setupScheduledToggle() { void HistoryWidget::refreshScheduledToggle() { const auto has = _history - && _peer->canWrite() + && _canSendMessages && (session().data().scheduledMessages().count(_history) > 0); if (!_scheduled && has) { _scheduled.create(this, st::historyScheduledToggle); @@ -2564,9 +2568,15 @@ bool HistoryWidget::canWriteMessage() const { } std::optional<QString> HistoryWidget::writeRestriction() const { - return _peer + auto result = _peer ? Data::RestrictionError(_peer, ChatRestriction::SendMessages) : std::nullopt; + if (result) { + return result; + } else if (_peer && _peer->isForum()) { + return u"You can reply to messages in topics."_q; + } + return std::nullopt; } void HistoryWidget::updateControlsVisibility() { @@ -3699,11 +3709,17 @@ void HistoryWidget::send(Api::SendOptions options) { message.webPageId = webPageId; if (_canSendMessages) { + const auto topicRootId = _replyEditMsg + ? _replyEditMsg->topicRootId() + : 0; const auto error = GetErrorTextForSending( _peer, - _toForward.items, - message.textWithTags, - options.scheduled); + { + .topicRootId = topicRootId, + .forward = &_toForward.items, + .text = &message.textWithTags, + .ignoreSlowmodeCountdown = (options.scheduled != 0), + }); if (!error.isEmpty()) { Ui::ShowMultilineToast({ .parentOverride = Window::Show(controller()).toastParent(), @@ -4027,7 +4043,7 @@ void HistoryWidget::chooseAttach( return; } - if (!_peer || !_peer->canWrite()) { + if (!_peer || !_canSendMessages) { return; } else if (const auto error = Data::RestrictionError( _peer, @@ -5248,6 +5264,10 @@ void HistoryWidget::itemRemoved(not_null<const HistoryItem*> item) { if (item == _replyEditMsg && _replyToId) { cancelReply(); } + if (item == _processingReplyItem) { + _processingReplyId = 0; + _processingReplyItem = nullptr; + } if (_kbReplyTo && item == _kbReplyTo) { toggleKeyboard(); _kbReplyTo = nullptr; @@ -6080,7 +6100,7 @@ void HistoryWidget::fieldTabbed() { } void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) { - if (!_peer || !_peer->canWrite()) { + if (!_peer || !_canSendMessages) { return; } else if (showSlowmodeError()) { return; @@ -6547,7 +6567,7 @@ bool HistoryWidget::sendExistingDocument( Ui::LayerOption::KeepOther); return false; } else if (!_peer - || !_peer->canWrite() + || !_canSendMessages || showSlowmodeError() || ShowSendPremiumError(controller(), document)) { return false; @@ -6583,7 +6603,7 @@ bool HistoryWidget::sendExistingPhoto( Ui::MakeInformBox(*error), Ui::LayerOption::KeepOther); return false; - } else if (!_peer || !_peer->canWrite()) { + } else if (!_peer || !_canSendMessages) { return false; } else if (showSlowmodeError()) { return false; @@ -6657,24 +6677,80 @@ void HistoryWidget::replyToMessage(FullMsgId itemId) { } void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) { - if (!item->isRegular() || !_canSendMessages) { + _processingReplyId = item->id; + _processingReplyItem = item; + processReply(); +} + +void HistoryWidget::processReply() { + const auto processContinue = [=] { + return crl::guard(_list, [=] { + if (!_peer || !_processingReplyId) { + return; + } else if (!_processingReplyItem) { + _processingReplyItem = _peer->owner().message( + _peer, + _processingReplyId); + if (!_processingReplyItem) { + _processingReplyId = 0; + } else { + processReply(); + } + } + }); + }; + const auto processCancel = [=] { + _processingReplyId = 0; + _processingReplyItem = nullptr; + }; + + if (!_peer || !_processingReplyId) { + return processCancel(); + } else if (!_processingReplyItem) { + session().api().requestMessageData( + _peer, + _processingReplyId, + processContinue()); return; - } else if (item->history() == _migrated) { - if (item->isService()) { + } else if (_processingReplyItem->history() == _migrated) { + if (_processingReplyItem->isService()) { controller()->show(Ui::MakeInformBox(tr::lng_reply_cant())); } else { - const auto itemId = item->fullId(); + const auto itemId = _processingReplyItem->fullId(); controller()->show( Ui::MakeConfirmBox({ .text = tr::lng_reply_cant_forward(), .confirmed = crl::guard(this, [=] { controller()->content()->setForwardDraft( _peer->id, - { .ids = { 1, itemId } }); + {.ids = { 1, itemId } }); }), .confirmText = tr::lng_selected_forward(), - })); + })); } + return processCancel(); + } else if (_processingReplyItem->history() != _history + || !_processingReplyItem->isRegular()) { + return processCancel(); + } else if (const auto forum = _peer->forum()) { + const auto topicRootId = _processingReplyItem->topicRootId(); + if (!topicRootId || forum->topicDeleted(topicRootId)) { + return processCancel(); + } else if (const auto topic = forum->topicFor(topicRootId)) { + if (!topic->canWrite()) { + return processCancel(); + } + } else { + forum->requestTopic(topicRootId, processContinue()); + } + } else if (!_peer->canWrite()) { + return processCancel(); + } + setReplyFieldsFromProcessing(); +} + +void HistoryWidget::setReplyFieldsFromProcessing() { + if (!_processingReplyId || !_processingReplyItem) { return; } @@ -6683,23 +6759,27 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) { _composeSearch->hideAnimated(); } + const auto id = base::take(_processingReplyId); + const auto item = base::take(_processingReplyItem); if (_editMsgId) { if (const auto localDraft = _history->localDraft({})) { - localDraft->msgId = item->id; + localDraft->msgId = id; } else { _history->setLocalDraft(std::make_unique<Data::Draft>( TextWithTags(), - item->id, - MsgId(), // topicRootId + id, + MsgId(), MessageCursor(), Data::PreviewState::Allowed)); } } else { _replyEditMsg = item; - _replyToId = item->id; + _replyToId = id; updateReplyEditText(_replyEditMsg); + updateCanSendMessage(); updateBotKeyboard(); updateReplyToName(); + updateControlsVisibility(); updateControlsGeometry(); updateField(); refreshTopBarActiveChat(); @@ -6709,7 +6789,9 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) { _saveDraftStart = crl::now(); saveDraft(); - _field->setFocus(); + if (!_field->isHidden()) { + _field->setFocus(); + } } void HistoryWidget::editMessage(FullMsgId itemId) { @@ -6836,16 +6918,17 @@ bool HistoryWidget::cancelReply(bool lastKeyboardUsed) { if (_replyToId) { wasReply = true; - _replyEditMsg = nullptr; - _replyToId = 0; + _processingReplyItem = _replyEditMsg = nullptr; + _processingReplyId = _replyToId = 0; mouseMoveEvent(0); if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_kbReplyTo) { _fieldBarCancel->hide(); updateMouseTracking(); } - updateBotKeyboard(); refreshTopBarActiveChat(); + updateCanSendMessage(); + updateControlsVisibility(); updateControlsGeometry(); update(); } else if (const auto localDraft = (_history ? _history->localDraft({}) : nullptr)) { @@ -7085,14 +7168,7 @@ void HistoryWidget::updatePreview() { void HistoryWidget::fullInfoUpdated() { auto refresh = false; if (_list) { - auto newCanSendMessages = _peer->canWrite(); - if (newCanSendMessages != _canSendMessages) { - _canSendMessages = newCanSendMessages; - if (!_canSendMessages) { - cancelReply(); - } - refreshScheduledToggle(); - refreshSilentToggle(); + if (updateCanSendMessage()) { refresh = true; } checkFieldAutocomplete(); @@ -7134,14 +7210,7 @@ void HistoryWidget::handlePeerUpdate() { || (!isBlocked() && _joinChannel->isHidden() == isJoinChannel())) { resize = true; } - bool newCanSendMessages = _peer->canWrite(); - if (newCanSendMessages != _canSendMessages) { - _canSendMessages = newCanSendMessages; - if (!_canSendMessages) { - cancelReply(); - } - refreshScheduledToggle(); - refreshSilentToggle(); + if (updateCanSendMessage()) { resize = true; } updateControlsVisibility(); @@ -7151,6 +7220,24 @@ void HistoryWidget::handlePeerUpdate() { } } +bool HistoryWidget::updateCanSendMessage() { + const auto replyTo = (_replyToId && !_editMsgId) ? _replyEditMsg : 0; + const auto topic = replyTo ? replyTo->topic() : nullptr; + const auto newCanSendMessages = topic + ? topic->canWrite() + : _peer->canWrite(); + if (_canSendMessages == newCanSendMessages) { + return false; + } + _canSendMessages = newCanSendMessages; + if (!_canSendMessages) { + cancelReply(); + } + refreshScheduledToggle(); + refreshSilentToggle(); + return true; +} + void HistoryWidget::forwardSelected() { if (!_list) { return; diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index f76b6e42f..845a70129 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -332,6 +332,8 @@ private: bool cornerButtonsHas(HistoryView::CornerButtonType type) override; void checkSuggestToGigagroup(); + void processReply(); + void setReplyFieldsFromProcessing(); void initTabbedSelector(); void initVoiceRecordBar(); @@ -382,6 +384,7 @@ private: void toggleTabbedSelectorMode(); void recountChatWidth(); void handlePeerUpdate(); + bool updateCanSendMessage(); void setMembersShowAreaActive(bool active); void handleHistoryChange(not_null<const History*> history); void showAboutTopPromotion(); @@ -616,6 +619,9 @@ private: Ui::Text::String _replyToName; int _replyToNameVersion = 0; + MsgId _processingReplyId = 0; + HistoryItem *_processingReplyItem = nullptr; + Data::ResolvedForwardDraft _toForward; Ui::Text::String _toForwardFrom, _toForwardText; int _toForwardNameVersion = 0; diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 019c086c1..07c2630bc 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_photo_media.h" #include "data/data_document.h" #include "data/data_media_types.h" +#include "data/data_forum_topic.h" #include "data/data_session.h" #include "data/data_groups.h" #include "data/data_channel.h" @@ -584,9 +585,11 @@ bool AddReplyToMessageAction( not_null<ListWidget*> list) { const auto context = list->elementContext(); const auto item = request.item; + const auto topic = item ? item->topic() : nullptr; + const auto peer = item ? item->history()->peer.get() : nullptr; if (!item || !item->isRegular() - || !item->history()->peer->canWrite() + || (topic ? topic->canWrite() : !peer->canWrite()) || (context != Context::History && context != Context::Replies)) { return false; } diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 779527b6c..69669237f 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -2703,7 +2703,7 @@ bool Message::hasFastReply() const { bool Message::displayFastReply() const { return hasFastReply() && data()->isRegular() - && data()->history()->peer->canWrite() + && data()->history()->peer->canWrite(false) && !delegate()->elementInSelectionMode(); } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 598c0798e..a0a7f0291 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -609,9 +609,11 @@ void RepliesWidget::setupComposeControls() { ChatRestriction::SendMessages); return restriction ? restriction - : _history->peer->canWrite() + : topicRestriction ? std::move(topicRestriction) - : tr::lng_group_not_accessible(tr::now); + : !(_topic ? _topic->canWrite() : _history->peer->canWrite()) + ? tr::lng_group_not_accessible(tr::now) + : std::optional<QString>(); }); _composeControls->setHistory({ @@ -1217,7 +1219,10 @@ void RepliesWidget::refreshJoinGroupButton() { } }; const auto channel = _history->peer->asChannel(); - if (channel->amIn() || channel->canWrite()) { + const auto canWrite = !channel->isForum() + ? channel->canWrite() + : (_topic && _topic->canWrite()); + if (channel->amIn() || canWrite) { set(nullptr); } else { if (!_joinGroup) { diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index 7126b925a..34a396086 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -129,7 +129,7 @@ void ShowChooseBox( callback(peer); }; auto filter = [=](not_null<PeerData*> peer) -> bool { - if (!peer->canWrite()) { + if (!peer->canWrite()) { // #TODO forum forward return false; } else if (const auto user = peer->asUser()) { if (user->isBot()) { diff --git a/Telegram/SourceFiles/main/session/send_as_peers.cpp b/Telegram/SourceFiles/main/session/send_as_peers.cpp index 8f6f1ac26..49339cd7e 100644 --- a/Telegram/SourceFiles/main/session/send_as_peers.cpp +++ b/Telegram/SourceFiles/main/session/send_as_peers.cpp @@ -43,7 +43,7 @@ SendAsPeers::SendAsPeers(not_null<Session*> session) bool SendAsPeers::shouldChoose(not_null<PeerData*> peer) { refresh(peer); - return peer->canWrite() && (list(peer).size() > 1); + return peer->canWrite(false) && (list(peer).size() > 1); } void SendAsPeers::refresh(not_null<PeerData*> peer, bool force) { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4b2f23f37..a213e2df7 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -335,7 +335,10 @@ MainWidget::MainWidget( _controller->activeChatValue( ) | rpl::map([](Dialogs::Key key) { const auto peer = key.peer(); - auto canWrite = peer + const auto topic = key.topic(); + auto canWrite = topic + ? Data::CanWriteValue(topic) + : peer ? Data::CanWriteValue(peer) : rpl::single(false); return std::move( @@ -516,10 +519,10 @@ bool MainWidget::setForwardDraft(PeerId peerId, Data::ForwardDraft &&draft) { Expects(peerId != 0); const auto peer = session().data().peer(peerId); + const auto items = session().data().idsToItems(draft.ids); const auto error = GetErrorTextForSending( - peer, - session().data().idsToItems(draft.ids), - true); + peer, // #TODO forum forward + { .forward = &items, .ignoreSlowmodeCountdown = true }); if (!error.isEmpty()) { Ui::show(Ui::MakeInformBox(error), Ui::LayerOption::KeepOther); return false; @@ -541,7 +544,7 @@ bool MainWidget::shareUrl( Expects(peerId != 0); const auto peer = session().data().peer(peerId); - if (!peer->canWrite()) { + if (!peer->canWrite()) { // #TODO forum forward _controller->show(Ui::MakeInformBox(tr::lng_share_cant())); return false; } @@ -575,7 +578,7 @@ bool MainWidget::inlineSwitchChosen( Expects(peerId != 0); const auto peer = session().data().peer(peerId); - if (!peer->canWrite()) { + if (!peer->canWrite()) { // #TODO forum forward Ui::show(Ui::MakeInformBox(tr::lng_inline_switch_cant())); return false; } @@ -607,7 +610,7 @@ bool MainWidget::sendPaths(PeerId peerId) { Expects(peerId != 0); auto peer = session().data().peer(peerId); - if (!peer->canWrite()) { + if (!peer->canWrite()) { // #TODO forum forward Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant())); return false; } else if (const auto error = Data::RestrictionError( @@ -638,7 +641,7 @@ void MainWidget::onFilesOrForwardDrop( } } else { auto peer = session().data().peer(peerId); - if (!peer->canWrite()) { + if (!peer->canWrite()) { // #TODO forum forward Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant())); return; } diff --git a/Telegram/SourceFiles/platform/mac/touchbar/items/mac_scrubber_item.mm b/Telegram/SourceFiles/platform/mac/touchbar/items/mac_scrubber_item.mm index 2d402f3d7..515ea5941 100644 --- a/Telegram/SourceFiles/platform/mac/touchbar/items/mac_scrubber_item.mm +++ b/Telegram/SourceFiles/platform/mac/touchbar/items/mac_scrubber_item.mm @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_document.h" #include "data/data_document_media.h" #include "data/data_file_origin.h" +#include "data/data_forum_topic.h" #include "data/data_session.h" #include "data/stickers/data_stickers.h" #include "history/history.h" @@ -168,7 +169,9 @@ auto ActiveChat(not_null<Window::Controller*> controller) { } bool CanWriteToActiveChat(not_null<Window::Controller*> controller) { - if (const auto history = ActiveChat(controller).history()) { + if (const auto topic = ActiveChat(controller).topic()) { + return topic->canWrite(); + } else if (const auto history = ActiveChat(controller).history()) { return history->peer->canWrite(); } return false; @@ -557,10 +560,11 @@ void AppendEmojiPacks( controller->sessionController()->activeChatValue( ) | rpl::map([](Dialogs::Key k) { - return k.peer() - && k.history() - && k.peer()->canWrite() - && !RestrictionToSendStickers(k.peer()); + const auto topic = k.topic(); + const auto peer = k.peer(); + return peer + && !RestrictionToSendStickers(peer) + && (topic ? topic->canWrite() : peer->canWrite()); }) | rpl::distinct_until_changed( ) | rpl::start_with_next([=](bool value) { [self dismissPopover:nil]; diff --git a/Telegram/SourceFiles/platform/mac/touchbar/mac_touchbar_manager.mm b/Telegram/SourceFiles/platform/mac/touchbar/mac_touchbar_manager.mm index febe82d82..3aa560faa 100644 --- a/Telegram/SourceFiles/platform/mac/touchbar/mac_touchbar_manager.mm +++ b/Telegram/SourceFiles/platform/mac/touchbar/mac_touchbar_manager.mm @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" // ApiWrap::updateStickers() #include "core/application.h" #include "data/data_peer.h" // PeerData::canWrite() +#include "data/data_forum_topic.h" // Data::ForumTopic::canWrite() #include "data/data_session.h" #include "data/stickers/data_stickers.h" // Stickers::setsRef() #include "main/main_domain.h" @@ -144,7 +145,11 @@ const auto kAudioItemIdentifier = @"touchbarAudio"; _canApplyMarkdownLast), _controller->sessionController()->activeChatValue( ) | rpl::map([](Dialogs::Key k) { - return k.peer() && k.history() && k.peer()->canWrite(); + const auto topic = k.topic(); + const auto peer = k.peer(); + return topic + ? topic->canWrite() + : (peer && peer->canWrite()); }) | rpl::distinct_until_changed() ) | rpl::start_with_next([=]( bool canApplyMarkdown, diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index f2acc5db3..202d90e4f 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -811,6 +811,8 @@ Manager::DisplayOptions Manager::getNotificationOptions( const auto hideEverything = Core::App().passcodeLocked() || forceHideDetails(); const auto view = Core::App().settings().notifyView(); + const auto peer = item ? item->history()->peer.get() : nullptr; + const auto topic = item ? item->topic() : nullptr; auto result = DisplayOptions(); result.hideNameAndPhoto = hideEverything @@ -820,12 +822,11 @@ Manager::DisplayOptions Manager::getNotificationOptions( result.hideMarkAsRead = result.hideMessageText || (type != Data::ItemNotificationType::Message) || !item - || ((item->out() || item->history()->peer->isSelf()) - && item->isFromScheduled()); + || ((item->out() || peer->isSelf()) && item->isFromScheduled()); result.hideReplyButton = result.hideMarkAsRead - || !item->history()->peer->canWrite() - || item->history()->peer->isBroadcast() - || (item->history()->peer->slowmodeSecondsLeft() > 0); + || (!peer->canWrite() && (!topic || !topic->canWrite())) + || peer->isBroadcast() + || (peer->slowmodeSecondsLeft() > 0); return result; } diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 8cfe2aa91..d9ecf509e 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -1219,7 +1219,7 @@ void PeerMenuShareContactBox( // There is no async to make weak from controller. const auto weak = std::make_shared<QPointer<Ui::BoxContent>>(); auto callback = [=](not_null<PeerData*> peer) { - if (!peer->canWrite()) { + if (!peer->canWrite()) { // #TODO forum forward navigation->parentController()->show( Ui::MakeInformBox(tr::lng_forward_share_cant()), Ui::LayerOption::KeepOther); @@ -1529,10 +1529,10 @@ QPointer<Ui::BoxContent> ShowSendNowMessagesBox( ? tr::lng_scheduled_send_now_many(tr::now, lt_count, items.size()) : tr::lng_scheduled_send_now(tr::now); + const auto list = session->data().idsToItems(items); const auto error = GetErrorTextForSending( history->peer, - session->data().idsToItems(items), - TextWithTags()); + { .forward = &list }); if (!error.isEmpty()) { Ui::ShowMultilineToast({ .parentOverride = Window::Show(navigation).toastParent(), diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 4ba3000a2..c199a1722 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 4ba3000a288772752fcf9b41a618ce5df5a185a5 +Subproject commit c199a1722fae72e254753f3095444a3c82a2a704