diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 645bd2766c..90d013cb60 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -388,7 +388,7 @@ void ApiWrap::savePinnedOrder(not_null saved) { const auto &order = _session->data().pinnedChatsOrder(saved); const auto input = [](Dialogs::Key key) { if (const auto sublist = key.sublist()) { - return MTP_inputDialogPeer(sublist->peer()->input); + return MTP_inputDialogPeer(sublist->sublistPeer()->input); } Unexpected("Key type in pinnedDialogsOrder()."); }; @@ -3303,6 +3303,13 @@ void ApiWrap::forwardMessages( if (topMsgId) { sendFlags |= SendFlag::f_top_msg_id; } + const auto monoforumPeerId = action.replyTo.monoforumPeerId; + const auto monoforumPeer = monoforumPeerId + ? session().data().peer(monoforumPeerId).get() + : nullptr; + if (monoforumPeer) { + sendFlags |= SendFlag::f_reply_to; + } auto forwardFrom = draft.items.front()->history()->peer; auto ids = QVector(); @@ -3332,7 +3339,9 @@ void ApiWrap::forwardMessages( MTP_vector(randomIds), peer->input, MTP_int(topMsgId), - MTPInputReplyTo(), + (monoforumPeer + ? MTP_inputReplyToMonoForum(monoforumPeer->input) + : MTPInputReplyTo()), MTP_int(action.options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()), Data::ShortcutIdToMTP(_session, action.options.shortcutId), @@ -3379,7 +3388,10 @@ void ApiWrap::forwardMessages( .id = newId.msg, .flags = flags, .from = NewMessageFromId(action), - .replyTo = { .topicRootId = topMsgId }, + .replyTo = { + .topicRootId = topMsgId, + .monoforumPeerId = monoforumPeerId, + }, .date = NewMessageDate(action.options), .shortcutId = action.options.shortcutId, .starsPaid = action.options.starsApproved, diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 3b22147532..c33da2ab35 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -23,6 +23,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/ui_utility.h" #include "main/main_session.h" #include "data/data_peer_values.h" +#include "data/data_saved_messages.h" +#include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_stories.h" #include "data/data_channel.h" @@ -867,6 +869,45 @@ void ChooseRecipientBoxController::rowClicked(not_null row) { *weak = owned.data(); delegate()->peerListUiShow()->showBox(std::move(owned)); return; + } else if (const auto monoforum = peer->monoforum()) { + const auto weak = std::make_shared>(); + auto callback = [=](not_null sublist) { + const auto exists = guard.get(); + if (!exists) { + if (*weak) { + (*weak)->closeBox(); + } + return; + } + auto onstack = std::move(_callback); + onstack(sublist); + if (guard) { + _callback = std::move(onstack); + } else if (*weak) { + (*weak)->closeBox(); + } + }; + const auto filter = [=](not_null sublist) { + return guard && (!_filter || _filter(sublist)); + }; + auto owned = Box( + std::make_unique( + monoforum, + std::move(callback), + filter), + [=](not_null box) { + box->addButton(tr::lng_cancel(), [=] { + box->closeBox(); + }); + + monoforum->destroyed( + ) | rpl::start_with_next([=] { + box->closeBox(); + }, box->lifetime()); + }); + *weak = owned.data(); + delegate()->peerListUiShow()->showBox(std::move(owned)); + return; } const auto history = peer->owner().history(peer); auto callback = std::move(_callback); @@ -1137,6 +1178,111 @@ auto ChooseTopicBoxController::createRow(not_null topic) return skip ? nullptr : std::make_unique(topic); }; +ChooseSublistBoxController::ChooseSublistBoxController( + not_null monoforum, + FnMut)> callback, + Fn)> filter) +: _monoforum(monoforum) +, _callback(std::move(callback)) +, _filter(std::move(filter)) { + setStyleOverrides(&st::chooseTopicList); + + _monoforum->chatsListChanges( + ) | rpl::start_with_next([=] { + refreshRows(); + }, lifetime()); + + _monoforum->sublistDestroyed( + ) | rpl::start_with_next([=](not_null sublist) { + const auto id = sublist->sublistPeer()->id.value; + if (const auto row = delegate()->peerListFindRow(id)) { + delegate()->peerListRemoveRow(row); + delegate()->peerListRefreshRows(); + } + }, lifetime()); +} + +Main::Session &ChooseSublistBoxController::session() const { + return _monoforum->session(); +} + +void ChooseSublistBoxController::rowClicked(not_null row) { + const auto weak = base::make_weak(this); + auto onstack = base::take(_callback); + onstack(_monoforum->sublist(row->peer())); + if (weak) { + _callback = std::move(onstack); + } +} + +void ChooseSublistBoxController::prepare() { + delegate()->peerListSetTitle(tr::lng_forward_choose()); + setSearchNoResultsText(tr::lng_topics_not_found(tr::now)); + delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); + refreshRows(true); + + session().changes().entryUpdates( + Data::EntryUpdate::Flag::Repaint + ) | rpl::start_with_next([=](const Data::EntryUpdate &update) { + if (const auto sublist = update.entry->asSublist()) { + if (sublist->parent() == _monoforum) { + const auto id = sublist->sublistPeer()->id.value; + if (const auto row = delegate()->peerListFindRow(id)) { + delegate()->peerListUpdateRow(row); + } + } + } + }, lifetime()); +} + +void ChooseSublistBoxController::refreshRows(bool initial) { + auto added = false; + for (const auto &row : _monoforum->chatsList()->indexed()->all()) { + if (const auto sublist = row->sublist()) { + const auto id = sublist->sublistPeer()->id.value; + auto already = delegate()->peerListFindRow(id); + if (initial || !already) { + if (auto created = createRow(sublist)) { + delegate()->peerListAppendRow(std::move(created)); + added = true; + } + } else if (already->isSearchResult()) { + delegate()->peerListAppendFoundRow(already); + added = true; + } + } + } + if (added) { + delegate()->peerListRefreshRows(); + } +} + +void ChooseSublistBoxController::loadMoreRows() { + _monoforum->loadMore(); +} + +std::unique_ptr ChooseSublistBoxController::createSearchRow( + PeerListRowId id) { + const auto peer = session().data().peer(PeerId(id)); + if (const auto sublist = _monoforum->sublistLoaded(peer)) { + auto result = std::make_unique(sublist->sublistPeer()); + result->setCustomStatus(QString()); + return result; + } + return nullptr; +} + +auto ChooseSublistBoxController::createRow( + not_null sublist) +-> std::unique_ptr { + if (const auto skip = _filter && !_filter(sublist)) { + return nullptr; + } + auto result = std::make_unique(sublist->sublistPeer()); + result->setCustomStatus(QString()); + return result; +}; + void PaintRestrictionBadge( Painter &p, not_null st, diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.h b/Telegram/SourceFiles/boxes/peer_list_controllers.h index de9c67dbfe..24887d3df2 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.h +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.h @@ -27,6 +27,8 @@ namespace Data { class Thread; class Forum; class ForumTopic; +class SavedSublist; +class SavedMessages; } // namespace Data namespace Ui { @@ -393,3 +395,30 @@ private: Fn)> _filter; }; + +class ChooseSublistBoxController final + : public PeerListController + , public base::has_weak_ptr { +public: + ChooseSublistBoxController( + not_null monoforum, + FnMut)> callback, + Fn)> filter = nullptr); + + Main::Session &session() const override; + void rowClicked(not_null row) override; + + void prepare() override; + void loadMoreRows() override; + std::unique_ptr createSearchRow(PeerListRowId id) override; + +private: + void refreshRows(bool initial = false); + [[nodiscard]] std::unique_ptr createRow( + not_null sublist); + + const not_null _monoforum; + FnMut)> _callback; + Fn)> _filter; + +}; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp index 70ad41acb0..aba3714395 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_forum_topic.h" #include "data/data_histories.h" #include "data/data_peer.h" +#include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/stickers/data_custom_emoji.h" @@ -1163,8 +1164,11 @@ void SingleRowController::prepare() { return; } const auto topic = strong->asTopic(); + const auto sublist = strong->asSublist(); auto row = topic ? ChooseTopicBoxController::MakeRow(topic) + : sublist + ? std::make_unique(sublist->sublistPeer()) : std::make_unique(strong->peer()); const auto raw = row.get(); if (_status) { diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index a8ed979a42..385ea7ea4f 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -45,6 +45,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_histories.h" #include "data/data_user.h" #include "data/data_peer_values.h" +#include "data/data_saved_messages.h" +#include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_folder.h" #include "data/data_forum.h" @@ -114,7 +116,9 @@ private: not_null history; not_null peer; Data::ForumTopic *topic = nullptr; + Data::SavedSublist *sublist = nullptr; rpl::lifetime topicLifetime; + rpl::lifetime sublistLifetime; Ui::RoundImageCheckbox checkbox; Ui::Text::String name; Ui::Animations::Simple nameActive; @@ -143,6 +147,7 @@ private: void preloadUserpic(not_null entry); void changeCheckState(Chat *chat); void chooseForumTopic(not_null forum); + void chooseMonoforumSublist(not_null monoforum); enum class ChangeStateWay { Default, SkipCallback, @@ -638,15 +643,18 @@ void ShareBox::addPeerToMultiSelect(not_null thread) { auto addItemWay = Ui::MultiSelect::AddItemWay::Default; const auto peer = thread->peer(); const auto topic = thread->asTopic(); + const auto sublist = thread->asSublist(); _select->addItem( peer->id.value, (topic ? topic->title() + : sublist + ? sublist->sublistPeer()->shortName() : peer->isSelf() ? tr::lng_saved_short(tr::now) : peer->shortName()), st::activeButtonBg, - (topic + ((topic || sublist) ? ForceRoundUserpicCallback(peer) : PaintUserpicCallback(peer, true)), addItemWay); @@ -970,6 +978,8 @@ void ShareBox::Inner::updateChatName(not_null chat) { const auto peer = chat->peer; const auto text = chat->topic ? chat->topic->title() + : chat->sublist + ? chat->sublist->sublistPeer()->name() : peer->isSelf() ? tr::lng_saved_messages(tr::now) : peer->isRepliesChat() @@ -1209,7 +1219,7 @@ ShareBox::Inner::Chat::Chat( st.checkbox, updateCallback, PaintUserpicCallback(peer, true), - [=](int size) { return peer->isForum() + [=](int size) { return (peer->isForum() || peer->isMonoforum()) ? int(size * Ui::ForumUserpicRadiusMultiplier()) : std::optional(); }) , name(st.checkbox.imageRadius * 2) { @@ -1350,10 +1360,13 @@ void ShareBox::Inner::changeCheckState(Chat *chat) { const auto checked = chat->checkbox.checked(); const auto forum = chat->peer->forum(); - if (checked || !forum) { + const auto monoforum = chat->peer->monoforum(); + if (checked || (!forum && !monoforum)) { changePeerCheckState(chat, !checked); - } else { - chooseForumTopic(chat->peer->forum()); + } else if (forum) { + chooseForumTopic(forum); + } else if (monoforum) { + chooseMonoforumSublist(monoforum); } } @@ -1404,6 +1417,54 @@ void ShareBox::Inner::chooseForumTopic(not_null forum) { _show->showBox(std::move(box)); } +void ShareBox::Inner::chooseMonoforumSublist( + not_null monoforum) { + const auto guard = Ui::MakeWeak(this); + const auto weak = std::make_shared>(); + auto chosen = [=](not_null sublist) { + if (const auto strong = *weak) { + strong->closeBox(); + } + if (!guard) { + return; + } + const auto row = _chatsIndexed->getRow(sublist->owningHistory()); + if (!row) { + return; + } + const auto chat = getChat(row); + Assert(!chat->sublist); + chat->sublist = sublist; + chat->sublist->destroyed( + ) | rpl::start_with_next([=] { + changePeerCheckState(chat, false); + }, chat->sublistLifetime); + updateChatName(chat); + changePeerCheckState(chat, true); + }; + auto initBox = [=](not_null box) { + box->addButton(tr::lng_cancel(), [=] { + box->closeBox(); + }); + + monoforum->destroyed( + ) | rpl::start_with_next([=] { + box->closeBox(); + }, box->lifetime()); + }; + auto filter = [=](not_null sublist) { + return guard && _descriptor.filterCallback(sublist); + }; + auto box = Box( + std::make_unique( + monoforum, + std::move(chosen), + std::move(filter)), + std::move(initBox)); + *weak = box.data(); + _show->showBox(std::move(box)); +} + void ShareBox::Inner::peerUnselected(not_null peer) { if (const auto i = _dataMap.find(peer); i != end(_dataMap)) { changePeerCheckState( @@ -1434,6 +1495,11 @@ void ShareBox::Inner::changePeerCheckState( chat->topic = nullptr; updateChatName(chat); } + if (chat->sublist) { + chat->sublistLifetime.destroy(); + chat->sublist = nullptr; + updateChatName(chat); + } } if (useCallback != ChangeStateWay::SkipCallback && _peerSelectedChangedCallback) { @@ -1565,6 +1631,8 @@ not_null ShareBox::Inner::chatThread( not_null chat) const { return chat->topic ? (Data::Thread*)chat->topic + : chat->sublist + ? (Data::Thread*)chat->sublist : chat->peer->owner().history(chat->peer).get(); } @@ -1675,6 +1743,7 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback( api.sendMessage(std::move(message)); } const auto topicRootId = thread->topicRootId(); + const auto sublistPeer = thread->maybeSublistPeer(); const auto kGeneralId = Data::ForumTopic::kGeneralId; const auto topMsgId = (topicRootId == kGeneralId) ? MsgId(0) @@ -1699,7 +1768,8 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback( | (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0)) - | (starsPaid ? Flag::f_allow_paid_stars : Flag()); + | (starsPaid ? Flag::f_allow_paid_stars : Flag()) + | (sublistPeer ? Flag::f_reply_to : Flag()); threadHistory->sendRequestId = api.request( MTPmessages_ForwardMessages( MTP_flags(sendFlags), @@ -1708,7 +1778,9 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback( MTP_vector(generateRandom()), peer->input, MTP_int(topMsgId), - MTPInputReplyTo(), + (sublistPeer + ? MTP_inputReplyToMonoForum(sublistPeer->input) + : MTPInputReplyTo()), MTP_int(options.scheduled), MTP_inputPeerEmpty(), // send_as Data::ShortcutIdToMTP(session, options.shortcutId), diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 0159fcca80..179b77d38a 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -228,6 +228,7 @@ void ChannelData::setFlags(ChannelDataFlags which) { } } if (diff & (Flag::Forum + | Flag::Monoforum | Flag::CallNotEmpty | Flag::SimilarExpanded | Flag::Signatures @@ -236,12 +237,14 @@ void ChannelData::setFlags(ChannelDataFlags which) { if (diff & Flag::CallNotEmpty) { history->updateChatListEntry(); } - if (diff & Flag::Forum) { + if (diff & (Flag::Forum | Flag::Monoforum)) { Core::App().notifications().clearFromHistory(history); history->updateChatListEntryHeight(); if (history->inChatList()) { if (const auto forum = this->forum()) { forum->preloadTopics(); + } else if (const auto monoforum = this->monoforum()) { + monoforum->loadMore(); } } } diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index 361135d885..4172ad1806 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -48,7 +48,6 @@ Forum::Forum(not_null history) , _topicsList(&session(), {}, owner().maxPinnedChatsLimitValue(this)) { Expects(_history->peer->isChannel()); - if (_history->inChatList()) { preloadTopics(); } diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index eb93c36375..6e03125eb9 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -867,7 +867,7 @@ void ForumTopic::setMuted(bool muted) { session().changes().topicUpdated(this, UpdateFlag::Notifications); } -not_null ForumTopic::sendActionPainter() { +HistoryView::SendActionPainter *ForumTopic::sendActionPainter() { return _sendActionPainter.get(); } diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h index 06423e4750..aafa12a788 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.h +++ b/Telegram/SourceFiles/data/data_forum_topic.h @@ -181,7 +181,7 @@ public: void setMuted(bool muted) override; [[nodiscard]] auto sendActionPainter() - ->not_null override; + -> HistoryView::SendActionPainter* override; private: enum class Flag : uchar { diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index e5dd4cdfbd..fec98a7920 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -1028,7 +1028,7 @@ void Reactions::requestMyTags(SavedSublist *sublist) { using Flag = MTPmessages_GetSavedReactionTags::Flag; my.requestId = api.request(MTPmessages_GetSavedReactionTags( MTP_flags(sublist ? Flag::f_peer : Flag()), - (sublist ? sublist->peer()->input : MTP_inputPeerEmpty()), + (sublist ? sublist->sublistPeer()->input : MTP_inputPeerEmpty()), MTP_long(my.hash) )).done([=](const MTPmessages_SavedReactionTags &result) { auto &my = _myTags[sublist]; diff --git a/Telegram/SourceFiles/data/data_saved_messages.cpp b/Telegram/SourceFiles/data/data_saved_messages.cpp index 72f5aca91f..a2c3f75daf 100644 --- a/Telegram/SourceFiles/data/data_saved_messages.cpp +++ b/Telegram/SourceFiles/data/data_saved_messages.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "history/history.h" #include "history/history_item.h" +#include "history/history_unread_things.h" #include "main/main_session.h" namespace Data { @@ -23,6 +24,7 @@ constexpr auto kPerPage = 50; constexpr auto kFirstPerPage = 10; constexpr auto kListPerPage = 100; constexpr auto kListFirstPerPage = 20; +constexpr auto kLoadedSublistsMinCount = 20; } // namespace @@ -36,6 +38,10 @@ SavedMessages::SavedMessages( FilterId(), _owner->maxPinnedChatsLimitValue(this)) , _loadMore([=] { sendLoadMoreRequests(); }) { + if (_parentChat + && _parentChat->owner().history(_parentChat)->inChatList()) { + preloadSublists(); + } } SavedMessages::~SavedMessages() = default; @@ -61,15 +67,19 @@ not_null SavedMessages::chatsList() { } not_null SavedMessages::sublist(not_null peer) { - const auto i = _sublists.find(peer); - if (i != end(_sublists)) { - return i->second.get(); + if (const auto loaded = sublistLoaded(peer)) { + return loaded; } return _sublists.emplace( peer, std::make_unique(this, peer)).first->second.get(); } +SavedSublist *SavedMessages::sublistLoaded(not_null peer) { + const auto i = _sublists.find(peer); + return (i != end(_sublists)) ? i->second.get() : nullptr; +} + rpl::producer<> SavedMessages::chatsListChanges() const { return _chatsListChanges.events(); } @@ -78,6 +88,13 @@ rpl::producer<> SavedMessages::chatsListLoadedEvents() const { return _chatsListLoadedEvents.events(); } +void SavedMessages::preloadSublists() { + if (parentChat() + && chatsList()->indexed()->size() < kLoadedSublistsMinCount) { + loadMore(); + } +} + void SavedMessages::loadMore() { _loadMoreScheduled = true; _loadMore.call(); @@ -152,7 +169,7 @@ void SavedMessages::sendLoadMore(not_null sublist) { MTPmessages_GetSavedHistory( MTP_flags(_parentChat ? Flag::f_parent_peer : Flag(0)), _parentChat ? _parentChat->input : MTPInputPeer(), - sublist->peer()->input, + sublist->sublistPeer()->input, MTP_int(offsetId), MTP_int(offsetDate), MTP_int(0), // add_offset diff --git a/Telegram/SourceFiles/data/data_saved_messages.h b/Telegram/SourceFiles/data/data_saved_messages.h index 6d6bbe3236..983fb7d08e 100644 --- a/Telegram/SourceFiles/data/data_saved_messages.h +++ b/Telegram/SourceFiles/data/data_saved_messages.h @@ -33,6 +33,7 @@ public: [[nodiscard]] not_null chatsList(); [[nodiscard]] not_null sublist(not_null peer); + [[nodiscard]] SavedSublist *sublistLoaded(not_null peer); [[nodiscard]] rpl::producer<> chatsListChanges() const; [[nodiscard]] rpl::producer<> chatsListLoadedEvents() const; @@ -41,6 +42,7 @@ public: [[nodiscard]] auto sublistDestroyed() const -> rpl::producer>; + void preloadSublists(); void loadMore(); void loadMore(not_null sublist); diff --git a/Telegram/SourceFiles/data/data_saved_sublist.cpp b/Telegram/SourceFiles/data/data_saved_sublist.cpp index 0ecfcf6739..c33361008c 100644 --- a/Telegram/SourceFiles/data/data_saved_sublist.cpp +++ b/Telegram/SourceFiles/data/data_saved_sublist.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_item_preview.h" #include "history/history.h" #include "history/history_item.h" +#include "history/history_unread_things.h" #include "main/main_session.h" namespace Data { @@ -22,7 +23,7 @@ namespace Data { SavedSublist::SavedSublist( not_null parent, not_null peer) -: Entry(&peer->owner(), Dialogs::Entry::Type::SavedSublist) +: Thread(&peer->owner(), Dialogs::Entry::Type::SavedSublist) , _parent(parent) , _history(peer->owner().history(peer)) { } @@ -33,7 +34,7 @@ not_null SavedSublist::parent() const { return _parent; } -not_null SavedSublist::parentHistory() const { +not_null SavedSublist::owningHistory() { const auto chat = parentChat(); return _history->owner().history(chat ? (PeerData*)chat @@ -44,18 +45,27 @@ ChannelData *SavedSublist::parentChat() const { return _parent->parentChat(); } -not_null SavedSublist::peer() const { +not_null SavedSublist::sublistPeer() const { return _history->peer; } bool SavedSublist::isHiddenAuthor() const { - return peer()->isSavedHiddenAuthor(); + return sublistPeer()->isSavedHiddenAuthor(); } bool SavedSublist::isFullLoaded() const { return (_flags & Flag::FullLoaded) != 0; } +rpl::producer<> SavedSublist::destroyed() const { + using namespace rpl::mappers; + return rpl::merge( + _parent->destroyed(), + _parent->sublistDestroyed() | rpl::filter( + _1 == this + ) | rpl::to_empty); +} + auto SavedSublist::messages() const -> const std::vector> & { return _items; @@ -231,8 +241,39 @@ void SavedSublist::paintUserpic( _history->paintUserpic(p, view, context); } +HistoryView::SendActionPainter *SavedSublist::sendActionPainter() { + return nullptr; +} + +void SavedSublist::hasUnreadMentionChanged(bool has) { + auto was = chatListUnreadState(); + if (has) { + was.mentions = 0; + } else { + was.mentions = 1; + } + notifyUnreadStateChange(was); +} + +void SavedSublist::hasUnreadReactionChanged(bool has) { + auto was = chatListUnreadState(); + if (has) { + was.reactions = was.reactionsMuted = 0; + } else { + was.reactions = 1; + was.reactionsMuted = muted() ? was.reactions : 0; + } + notifyUnreadStateChange(was); +} + +bool SavedSublist::isServerSideUnread( + not_null item) const { + return false; +} + + void SavedSublist::chatListPreloadData() { - peer()->loadUserpic(); + sublistPeer()->loadUserpic(); allowChatListMessageResolve(); } diff --git a/Telegram/SourceFiles/data/data_saved_sublist.h b/Telegram/SourceFiles/data/data_saved_sublist.h index 669aa97311..4217a8fb67 100644 --- a/Telegram/SourceFiles/data/data_saved_sublist.h +++ b/Telegram/SourceFiles/data/data_saved_sublist.h @@ -7,8 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "data/data_thread.h" #include "dialogs/ui/dialogs_message_view.h" -#include "dialogs/dialogs_entry.h" class PeerData; class History; @@ -18,17 +18,18 @@ namespace Data { class Session; class SavedMessages; -class SavedSublist final : public Dialogs::Entry { +class SavedSublist final : public Data::Thread { public: - SavedSublist(not_null parent,not_null peer); + SavedSublist(not_null parent, not_null peer); ~SavedSublist(); [[nodiscard]] not_null parent() const; - [[nodiscard]] not_null parentHistory() const; + [[nodiscard]] not_null owningHistory() override; [[nodiscard]] ChannelData *parentChat() const; - [[nodiscard]] not_null peer() const; + [[nodiscard]] not_null sublistPeer() const; [[nodiscard]] bool isHiddenAuthor() const; [[nodiscard]] bool isFullLoaded() const; + [[nodiscard]] rpl::producer<> destroyed() const; [[nodiscard]] auto messages() const -> const std::vector> &; @@ -41,10 +42,6 @@ public: [[nodiscard]] std::optional fullCount() const; [[nodiscard]] rpl::producer fullCountValue() const; - [[nodiscard]] Dialogs::Ui::MessageView &lastItemDialogsView() { - return _lastItemDialogsView; - } - int fixedOnTopIndex() const override; bool shouldBeInChatList() const override; Dialogs::UnreadState chatListUnreadState() const override; @@ -57,12 +54,21 @@ public: const base::flat_set &chatListNameWords() const override; const base::flat_set &chatListFirstLetters() const override; + void hasUnreadMentionChanged(bool has) override; + void hasUnreadReactionChanged(bool has) override; + + [[nodiscard]] bool isServerSideUnread( + not_null item) const override; + void chatListPreloadData() override; void paintUserpic( Painter &p, Ui::PeerUserpicView &view, const Dialogs::Ui::PaintContext &context) const override; + [[nodiscard]] auto sendActionPainter() + -> HistoryView::SendActionPainter* override; + private: enum class Flag : uchar { ResolveChatListMessage = (1 << 0), @@ -81,7 +87,6 @@ private: std::vector> _items; std::optional _fullCount; rpl::event_stream<> _changed; - Dialogs::Ui::MessageView _lastItemDialogsView; Flags _flags; }; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index d995d42083..dd71002706 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -4656,6 +4656,8 @@ void Session::refreshChatListEntry(Dialogs::Key key) { } if (const auto forum = history->peer->forum()) { forum->preloadTopics(); + } else if (const auto monoforum = history->peer->monoforum()) { + monoforum->preloadSublists(); } if (history->peer->isMonoforum() && !history->peer->monoforumBroadcast()) { diff --git a/Telegram/SourceFiles/data/data_thread.cpp b/Telegram/SourceFiles/data/data_thread.cpp index 1934c34507..67a346f7e2 100644 --- a/Telegram/SourceFiles/data/data_thread.cpp +++ b/Telegram/SourceFiles/data/data_thread.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_forum_topic.h" #include "data/data_changes.h" #include "data/data_peer.h" +#include "data/data_saved_sublist.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_unread_things.h" @@ -31,6 +32,13 @@ MsgId Thread::topicRootId() const { return MsgId(); } +PeerData *Thread::maybeSublistPeer() const { + if (const auto sublist = asSublist()) { + return sublist->sublistPeer(); + } + return nullptr; +} + not_null Thread::peer() const { return owningHistory()->peer; } diff --git a/Telegram/SourceFiles/data/data_thread.h b/Telegram/SourceFiles/data/data_thread.h index 9bbc6635fe..10eb0d27ee 100644 --- a/Telegram/SourceFiles/data/data_thread.h +++ b/Telegram/SourceFiles/data/data_thread.h @@ -67,6 +67,7 @@ public: return const_cast(this)->owningHistory(); } [[nodiscard]] MsgId topicRootId() const; + [[nodiscard]] PeerData *maybeSublistPeer() const; [[nodiscard]] not_null peer() const; [[nodiscard]] PeerNotifySettings ¬ify(); [[nodiscard]] const PeerNotifySettings ¬ify() const; @@ -112,7 +113,7 @@ public: } [[nodiscard]] virtual auto sendActionPainter() - -> not_null = 0; + -> HistoryView::SendActionPainter* = 0; [[nodiscard]] bool hasPinnedMessages() const; void setHasPinnedMessages(bool has); diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp index 501883a416..899fdde8db 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp @@ -84,9 +84,9 @@ Entry::Entry(not_null owner, Type type) , _flags((type == Type::History) ? (Flag::IsThread | Flag::IsHistory) : (type == Type::ForumTopic) - ? Flag::IsThread + ? (Flag::IsThread | Flag::IsForumTopic) : (type == Type::SavedSublist) - ? Flag::IsSavedSublist + ? (Flag::IsThread | Flag::IsSavedSublist) : Flag(0)) { } @@ -113,7 +113,7 @@ Data::Forum *Entry::asForum() { } Data::Folder *Entry::asFolder() { - return (_flags & (Flag::IsThread | Flag::IsSavedSublist)) + return (_flags & Flag::IsThread) ? nullptr : static_cast(this); } @@ -125,7 +125,7 @@ Data::Thread *Entry::asThread() { } Data::ForumTopic *Entry::asTopic() { - return ((_flags & Flag::IsThread) && !(_flags & Flag::IsHistory)) + return (_flags & Flag::IsForumTopic) ? static_cast(this) : nullptr; } diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.h b/Telegram/SourceFiles/dialogs/dialogs_entry.h index e52b45048d..8838bd05fb 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.h +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.h @@ -27,6 +27,7 @@ class Forum; class Folder; class ForumTopic; class SavedSublist; +class SavedMessages; class Thread; } // namespace Data @@ -168,9 +169,10 @@ private: enum class Flag : uchar { IsThread = (1 << 0), IsHistory = (1 << 1), - IsSavedSublist = (1 << 2), - UpdatePostponed = (1 << 3), - InUnreadChangeBlock = (1 << 4), + IsForumTopic = (1 << 2), + IsSavedSublist = (1 << 3), + UpdatePostponed = (1 << 4), + InUnreadChangeBlock = (1 << 5), }; friend inline constexpr bool is_flag_type(Flag) { return true; } using Flags = base::flags; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 79996bd7b6..2df6141026 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -3444,7 +3444,7 @@ void InnerWidget::applySearchState(SearchState state) { _searchFromShown = ignoreInChat ? nullptr : sublist - ? sublist->peer().get() + ? sublist->sublistPeer().get() : state.fromPeer; if (state.inChat) { onHashtagFilterUpdate(QStringView()); @@ -4222,7 +4222,7 @@ void InnerWidget::updateSearchIn() { const auto peerIcon = peer ? Ui::MakeUserpicThumbnail(peer) : sublist - ? Ui::MakeUserpicThumbnail(sublist->peer()) + ? Ui::MakeUserpicThumbnail(sublist->sublistPeer()) : nullptr; const auto myIcon = Ui::MakeIconThumbnail(st::menuIconChats); const auto publicIcon = (_searchHashOrCashtag != HashOrCashtag::None) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 6dea61f38a..b311225bf2 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1001,7 +1001,7 @@ void Widget::chosenRow(const ChosenRow &row) { using namespace HistoryView; controller()->showSection( std::make_shared(ChatViewId{ - .history = sublist->parentHistory(), + .history = sublist->owningHistory(), .sublist = sublist, }), params); @@ -2037,7 +2037,7 @@ void Widget::refreshTopBars() { ? Dialogs::Key(history) : Dialogs::Key(_openedFolder)), .section = Dialogs::EntryState::Section::ChatsList, - }, history ? history->sendActionPainter().get() : nullptr); + }, history ? history->sendActionPainter() : nullptr); if (_forumSearchRequested) { showSearchInTopBar(anim::type::instant); } @@ -2680,7 +2680,7 @@ bool Widget::search(bool inCache, SearchRequestDelay delay) { : _searchState.inChat.sublist(); const auto fromPeer = sublist ? nullptr : _searchQueryFrom; const auto savedPeer = sublist - ? sublist->peer().get() + ? sublist->sublistPeer().get() : nullptr; _historiesRequest = histories.sendRequest(history, type, [=]( Fn finish) { @@ -2856,7 +2856,7 @@ void Widget::searchMore() { : _searchState.inChat.sublist(); const auto fromPeer = sublist ? nullptr : _searchQueryFrom; const auto savedPeer = sublist - ? sublist->peer().get() + ? sublist->sublistPeer().get() : nullptr; _historiesRequest = histories.sendRequest(history, type, [=]( Fn finish) { @@ -4284,8 +4284,12 @@ PeerData *Widget::searchInPeer() const { ? nullptr : _openedForum ? _openedForum->channel().get() + : _openedMonoforum + ? (_openedMonoforum->parentChat() + ? _openedMonoforum->parentChat() + : (PeerData*)session().user().get()) : _searchState.inChat.sublist() - ? session().user().get() + ? _searchState.inChat.sublist()->owningHistory()->peer.get() : _searchState.inChat.peer(); } diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index dfdb7891d3..628c0ae4d5 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -62,7 +62,7 @@ const auto kPsaBadgePrefix = "cloud_lng_badge_psa_"; [[nodiscard]] bool ShowSendActionInDialogs(Data::Thread *thread) { const auto history = thread ? thread->owningHistory().get() : nullptr; - if (!history) { + if (!history || thread->asSublist()) { return false; } else if (const auto user = history->peer->asUser()) { return !user->lastseen().isHidden(); @@ -994,7 +994,7 @@ void RowPainter::Paint( ? history->peer->migrateTo() : history->peer.get()) : sublist - ? sublist->peer().get() + ? sublist->sublistPeer().get() : nullptr; const auto allowUserOnline = true;// !context.narrow || badgesState.empty(); const auto flags = (allowUserOnline ? Flag::AllowUserOnline : Flag(0)) diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 8963ab0a08..f8e0791d74 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -273,7 +273,7 @@ public: void setHasPendingResizedItems(); [[nodiscard]] auto sendActionPainter() - -> not_null override { + -> HistoryView::SendActionPainter* override { return &_sendActionPainter; } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index e084f47e6e..f5e349a505 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -537,6 +537,7 @@ HistoryItem::HistoryItem( const auto topicRootId = fields.replyTo.topicRootId; config.reply.messageId = config.reply.topMessageId = topicRootId; config.reply.topicPost = (topicRootId != 0) ? 1 : 0; + config.reply.monoforumPeerId = fields.replyTo.monoforumPeerId; if (const auto originalReply = original->Get()) { if (originalReply->external()) { config.reply = originalReply->fields().clone(this); @@ -3579,7 +3580,7 @@ Data::SavedSublist *HistoryItem::savedSublist() const { PeerData *HistoryItem::savedSublistPeer() const { if (const auto sublist = savedSublist()) { - return sublist->peer(); + return sublist->sublistPeer(); } return nullptr; } diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 7c38991768..6bf1382f86 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -503,6 +503,8 @@ TimeId NewMessageDate(const Api::SendOptions &options) { PeerId NewMessageFromId(const Api::SendAction &action) { return action.options.sendAs ? action.options.sendAs->id + : action.history->peer->amMonoforumAdmin() + ? action.history->peer->monoforumBroadcast()->id : action.history->peer->amAnonymous() ? PeerId() : action.history->session().userPeerId(); diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp index 6883918710..7bada5f52e 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp @@ -1693,7 +1693,7 @@ SendMenu::Details ChatWidget::sendMenuDetails() const { FullReplyTo ChatWidget::replyTo() const { const auto monoforumPeerId = (_sublist && _sublist->parentChat()) - ? _sublist->peer()->id + ? _sublist->sublistPeer()->id : PeerId(); if (auto custom = _composeControls->replyingToMessage()) { const auto item = custom.messageId @@ -1786,7 +1786,7 @@ void ChatWidget::checkLastPinnedClickedIdReset( } void ChatWidget::setupOpenChatButton() { - if (!_sublist || _sublist->peer()->isSavedHiddenAuthor()) { + if (!_sublist || _sublist->sublistPeer()->isSavedHiddenAuthor()) { return; } else if (_sublist->parentChat()) { _canSendTexts = true; @@ -1794,22 +1794,22 @@ void ChatWidget::setupOpenChatButton() { } _openChatButton = std::make_unique( this, - (_sublist->peer()->isBroadcast() + (_sublist->sublistPeer()->isBroadcast() ? tr::lng_saved_open_channel(tr::now) - : _sublist->peer()->isUser() + : _sublist->sublistPeer()->isUser() ? tr::lng_saved_open_chat(tr::now) : tr::lng_saved_open_group(tr::now)), st::historyComposeButton); _openChatButton->setClickedCallback([=] { controller()->showPeerHistory( - _sublist->peer(), + _sublist->sublistPeer(), Window::SectionShow::Way::Forward); }); } void ChatWidget::setupAboutHiddenAuthor() { - if (!_sublist || !_sublist->peer()->isSavedHiddenAuthor()) { + if (!_sublist || !_sublist->sublistPeer()->isSavedHiddenAuthor()) { return; } else if (_sublist->parentChat()) { _canSendTexts = true; @@ -3260,7 +3260,7 @@ bool ChatWidget::searchInChatEmbedded( this, controller(), _history, - sublist->peer(), + sublist->sublistPeer(), query); updateControlsGeometry(); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 21f0946ef0..eec58baf5c 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -1477,17 +1477,17 @@ void Element::recountMonoforumSenderBarInBlocks() { || item->isSponsored()) { return nullptr; } - const auto peer = sublist->peer(); + const auto sublistPeer = sublist->sublistPeer(); if (const auto previous = previousDisplayedInBlocks()) { const auto prev = previous->data(); if (const auto prevSublist = prev->savedSublist()) { Assert(prevSublist->parentChat() == parentChat); - if (prevSublist->peer() == peer) { + if (prevSublist->sublistPeer() == sublistPeer) { return nullptr; } } } - return peer; + return sublistPeer; }(); if (barPeer && !Has()) { AddComponents(MonoforumSenderBar::Bit()); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 0482f59ec9..49a7afafce 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -3712,7 +3712,7 @@ bool Message::hasFromName() const { case Context::AdminLog: return true; case Context::Monoforum: - return false; + return data()->out(); case Context::History: case Context::ChatPreview: case Context::TTLViewer: diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 978b95796b..d0e2aca0e6 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -82,7 +82,7 @@ QString TopBarNameText( const Dialogs::EntryState &state) { if (state.section == Dialogs::EntryState::Section::SavedSublist && state.key.sublist() - && state.key.sublist()->parentHistory()->peer->isSelf()) { + && state.key.sublist()->owningHistory()->peer->isSelf()) { if (peer->isSelf()) { return tr::lng_my_notes(tr::now); } else if (peer->isSavedHiddenAuthor()) { @@ -490,7 +490,8 @@ void TopBarWidget::paintTopBar(Painter &p) { const auto history = _activeChat.key.history(); const auto namePeer = history ? history->peer.get() - : sublist ? sublist->peer().get() + : sublist + ? sublist->sublistPeer().get() : nullptr; const auto broadcastForMonoforum = history ? history->peer->monoforumBroadcast() @@ -746,9 +747,9 @@ void TopBarWidget::infoClicked() { return; } else if (const auto topic = key.topic()) { _controller->showSection(std::make_shared(topic)); - } else if ([[maybe_unused]] const auto sublist = key.sublist()) { + } else if (const auto sublist = key.sublist()) { _controller->showSection(std::make_shared( - _controller->session().user(), + sublist->owningHistory()->peer, Info::Section(Storage::SharedMediaType::Photo))); } else if (key.peer()->savedSublistsInfo()) { _controller->showSection(std::make_shared( diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.cpp b/Telegram/SourceFiles/info/media/info_media_buttons.cpp index 9f53a17e2b..9d91702861 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.cpp +++ b/Telegram/SourceFiles/info/media/info_media_buttons.cpp @@ -275,7 +275,7 @@ not_null AddSavedSublistButton( const auto sublist = peer->owner().savedMessages().sublist(peer); navigation->showSection( std::make_shared(ChatViewId{ - .history = sublist->parentHistory(), + .history = sublist->owningHistory(), .sublist = sublist, })); }); diff --git a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp index 3afead749b..0ab5a23af5 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp @@ -69,7 +69,7 @@ SublistsWidget::SublistsWidget( params.dropSameFromStack = true; controller->showSection( std::make_shared(ChatViewId{ - .history = sublist->parentHistory(), + .history = sublist->owningHistory(), .sublist = sublist, }), params); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 3c33394661..e0953d45ca 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -644,6 +644,17 @@ bool MainWidget::filesOrForwardDrop( clearHider(_hider); } return true; + } else if (const auto history = thread->asHistory() + ; history && history->peer->monoforum()) { + Window::ShowDropMediaBox( + _controller, + Core::ShareMimeMediaData(data), + history->peer->monoforum()); + if (_hider) { + _hider->startHide(); + clearHider(_hider); + } + return true; } if (data->hasFormat(u"application/x-td-forward"_q)) { auto draft = Data::ForwardDraft{ @@ -780,7 +791,7 @@ void MainWidget::searchMessages( using namespace HistoryView; controller()->showSection( std::make_shared(ChatViewId{ - .history = sublist->parentHistory(), + .history = sublist->owningHistory(), .sublist = sublist, })); } else if (!tags.empty()) { @@ -1548,6 +1559,12 @@ void MainWidget::showMessage( if (params.activation != anim::activation::background) { _controller->window().activate(); } + } else if (const auto sublist = item->savedSublist() + ; sublist && sublist->parentChat()) { + _controller->showSublist(sublist, item->id, params); + if (params.activation != anim::activation::background) { + _controller->window().activate(); + } } else { // showPeerHistory may be redirected to different window, // so we don't call activate() on current controller's window. @@ -2621,10 +2638,10 @@ auto MainWidget::thirdSectionForCurrentMainSection( return std::make_shared( peer, Info::Memento::DefaultSection(peer)); - } else if (key.sublist()) { + } else if (const auto sublist = key.sublist()) { return std::make_shared( - session().user(), - Info::Memento::DefaultSection(session().user())); + sublist->owningHistory()->peer, + Info::Memento::DefaultSection(sublist->owningHistory()->peer)); } Unexpected("Key in MainWidget::thirdSectionForCurrentMainSection()."); } diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 841bffbd82..2f14936778 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -88,6 +88,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_forum.h" #include "data/data_forum_topic.h" #include "data/data_user.h" +#include "data/data_saved_messages.h" #include "data/data_saved_sublist.h" #include "data/data_histories.h" #include "data/data_chat_filters.h" @@ -435,7 +436,7 @@ void TogglePinnedThread( : MTPmessages_ToggleSavedDialogPin::Flag(0); owner->session().api().request(MTPmessages_ToggleSavedDialogPin( MTP_flags(flags), - MTP_inputDialogPeer(sublist->peer()->input) + MTP_inputDialogPeer(sublist->sublistPeer()->input) )).done([=] { owner->notifyPinnedDialogsOrderUpdated(); if (onToggled) { @@ -655,10 +656,9 @@ void Filler::addNewWindow() { _addAction(tr::lng_context_new_window(tr::now), [=] { Ui::PreventDelayedActivation(); if (const auto sublist = weak.get()) { - const auto peer = sublist->peer(); controller->showInNewWindow(SeparateId( SeparateType::SavedSublist, - peer->owner().history(peer))); + sublist->owner().history(sublist->sublistPeer()))); } }, &st::menuIconNewWindow); AddSeparatorAndShiftUp(_addAction); @@ -2850,6 +2850,46 @@ QPointer ShowDropMediaBox( return weak->data(); } +QPointer ShowDropMediaBox( + not_null navigation, + std::shared_ptr data, + not_null monoforum, + FnMut &&successCallback) { + const auto weak = std::make_shared>(); + auto chosen = [ + data = std::move(data), + callback = std::move(successCallback), + weak, + navigation + ](not_null sublist) mutable { + const auto content = navigation->parentController()->content(); + if (!content->filesOrForwardDrop(sublist, data.get())) { + return; + } else if (const auto strong = *weak) { + strong->closeBox(); + } + if (callback) { + callback(); + } + }; + auto initBox = [=](not_null box) { + box->addButton(tr::lng_cancel(), [=] { + box->closeBox(); + }); + + monoforum->destroyed( + ) | rpl::start_with_next([=] { + box->closeBox(); + }, box->lifetime()); + }; + *weak = navigation->parentController()->show(Box( + std::make_unique( + monoforum, + std::move(chosen)), + std::move(initBox))); + return weak->data(); +} + QPointer ShowSendNowMessagesBox( not_null navigation, not_null history, diff --git a/Telegram/SourceFiles/window/window_peer_menu.h b/Telegram/SourceFiles/window/window_peer_menu.h index a125c3c55d..fbc677bdb6 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.h +++ b/Telegram/SourceFiles/window/window_peer_menu.h @@ -32,6 +32,8 @@ class Folder; class Session; struct ForwardDraft; class ForumTopic; +class SavedMessages; +class SavedSublist; class Thread; } // namespace Data @@ -188,6 +190,11 @@ QPointer ShowDropMediaBox( std::shared_ptr data, not_null forum, FnMut &&successCallback = nullptr); +QPointer ShowDropMediaBox( + not_null navigation, + std::shared_ptr data, + not_null monoforum, + FnMut &&successCallback = nullptr); QPointer ShowSendNowMessagesBox( not_null navigation, diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 2cb230d6c8..f22dd049fe 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1259,12 +1259,30 @@ void SessionNavigation::showTopic( params); } +void SessionNavigation::showSublist( + not_null sublist, + MsgId itemId, + const SectionShow ¶ms) { + using namespace HistoryView; + auto memento = std::make_shared( + ChatViewId{ + .history = sublist->owningHistory(), + .sublist = sublist, + }, + itemId, + params.highlightPart, + params.highlightPartOffsetHint); + showSection(std::move(memento), params); +} + void SessionNavigation::showThread( not_null thread, MsgId itemId, const SectionShow ¶ms) { if (const auto topic = thread->asTopic()) { showTopic(topic, itemId, params); + } else if (const auto sublist = thread->asSublist()) { + showSublist(sublist, itemId, params); } else { showPeerHistory(thread->asHistory(), params, itemId); } @@ -1346,7 +1364,7 @@ void SessionNavigation::showByInitialId( using namespace HistoryView; showSection( std::make_shared(ChatViewId{ - .history = id.sublist()->parentHistory(), + .history = id.sublist()->owningHistory(), .sublist = id.sublist(), }), instant); diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 7eea85827a..391fbbafd3 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -74,6 +74,7 @@ enum class CloudThemeType; class Thread; class Forum; class ForumTopic; +class SavedSublist; class WallPaper; } // namespace Data @@ -201,6 +202,10 @@ public: not_null topic, MsgId itemId = 0, const SectionShow ¶ms = SectionShow()); + void showSublist( + not_null sublist, + MsgId itemId = 0, + const SectionShow ¶ms = SectionShow()); void showThread( not_null thread, MsgId itemId = 0,