From 21f840335707263e64a09a37255b29bf018abbf2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 9 May 2025 16:45:44 +0400 Subject: [PATCH] Merge SublistSection into ChatSection. --- Telegram/CMakeLists.txt | 2 - .../SourceFiles/data/data_saved_sublist.cpp | 13 +- .../SourceFiles/data/data_saved_sublist.h | 2 +- .../SourceFiles/dialogs/dialogs_widget.cpp | 12 +- .../view/history_view_chat_section.cpp | 334 ++++++-- .../history/view/history_view_chat_section.h | 28 +- .../view/history_view_sublist_section.cpp | 795 ------------------ .../view/history_view_sublist_section.h | 237 ------ .../info/media/info_media_buttons.cpp | 11 +- .../info/saved/info_saved_sublists_widget.cpp | 9 +- Telegram/SourceFiles/mainwidget.cpp | 9 +- .../window/window_session_controller.cpp | 8 +- 12 files changed, 355 insertions(+), 1105 deletions(-) delete mode 100644 Telegram/SourceFiles/history/view/history_view_sublist_section.cpp delete mode 100644 Telegram/SourceFiles/history/view/history_view_sublist_section.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 1d52a00a53..85a7703fd6 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -888,8 +888,6 @@ PRIVATE history/view/history_view_sponsored_click_handler.h history/view/history_view_sticker_toast.cpp history/view/history_view_sticker_toast.h - history/view/history_view_sublist_section.cpp - history/view/history_view_sublist_section.h history/view/history_view_text_helper.cpp history/view/history_view_text_helper.h history/view/history_view_transcribe_button.cpp diff --git a/Telegram/SourceFiles/data/data_saved_sublist.cpp b/Telegram/SourceFiles/data/data_saved_sublist.cpp index 134ada5295..0ecfcf6739 100644 --- a/Telegram/SourceFiles/data/data_saved_sublist.cpp +++ b/Telegram/SourceFiles/data/data_saved_sublist.cpp @@ -9,11 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_histories.h" #include "data/data_peer.h" +#include "data/data_user.h" #include "data/data_saved_messages.h" #include "data/data_session.h" #include "history/view/history_view_item_preview.h" #include "history/history.h" #include "history/history_item.h" +#include "main/main_session.h" namespace Data { @@ -31,12 +33,15 @@ not_null SavedSublist::parent() const { return _parent; } -ChannelData *SavedSublist::parentChat() const { - return _parent->parentChat(); +not_null SavedSublist::parentHistory() const { + const auto chat = parentChat(); + return _history->owner().history(chat + ? (PeerData*)chat + : _history->session().user().get()); } -not_null SavedSublist::history() const { - return _history; +ChannelData *SavedSublist::parentChat() const { + return _parent->parentChat(); } not_null SavedSublist::peer() const { diff --git a/Telegram/SourceFiles/data/data_saved_sublist.h b/Telegram/SourceFiles/data/data_saved_sublist.h index 8e59854e45..669aa97311 100644 --- a/Telegram/SourceFiles/data/data_saved_sublist.h +++ b/Telegram/SourceFiles/data/data_saved_sublist.h @@ -24,8 +24,8 @@ public: ~SavedSublist(); [[nodiscard]] not_null parent() const; + [[nodiscard]] not_null parentHistory() const; [[nodiscard]] ChannelData *parentChat() const; - [[nodiscard]] not_null history() const; [[nodiscard]] not_null peer() const; [[nodiscard]] bool isHiddenAuthor() const; [[nodiscard]] bool isFullLoaded() const; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 31dd678231..b593d960b5 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -21,11 +21,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_key.h" #include "history/history.h" #include "history/history_item.h" -#include "history/view/history_view_top_bar_widget.h" +#include "history/view/history_view_chat_section.h" #include "history/view/history_view_contact_status.h" -#include "history/view/history_view_requests_bar.h" #include "history/view/history_view_group_call_bar.h" -#include "history/view/history_view_sublist_section.h" +#include "history/view/history_view_requests_bar.h" +#include "history/view/history_view_top_bar_widget.h" #include "boxes/peers/edit_peer_requests_box.h" #include "ui/text/text_utilities.h" #include "ui/widgets/buttons.h" @@ -998,8 +998,12 @@ void Widget::chosenRow(const ChosenRow &row) { using namespace Window; auto params = SectionShow(SectionShow::Way::Forward); params.dropSameFromStack = true; + using namespace HistoryView; controller()->showSection( - std::make_shared(sublist), + std::make_shared(ChatViewId{ + .history = sublist->parentHistory(), + .sublist = sublist, + }), params); } if (row.filteredRow && !session().supportMode()) { diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp index 250d952f0c..b70bc08ec7 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp @@ -57,6 +57,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "main/main_session_settings.h" #include "data/components/scheduled_messages.h" +#include "data/data_saved_messages.h" +#include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/data_chat.h" @@ -120,7 +122,7 @@ ChatMemento::ChatMemento( , _highlightPart(highlightPart) , _highlightPartOffsetHint(highlightPartOffsetHint) , _highlightId(highlightId) { - if (highlightId) { + if (highlightId || _id.sublist) { _list.setAroundPosition({ .fullId = FullMsgId(_id.history->peer->id, highlightId), .date = TimeId(0), @@ -271,6 +273,8 @@ ChatWidget::ChatWidget( setupRoot(); setupRootView(); + setupOpenChatButton(); + setupAboutHiddenAuthor(); setupShortcuts(); setupTranslateBar(); @@ -300,9 +304,7 @@ ChatWidget::ChatWidget( }, _topBar->lifetime()); _topBar->searchRequest( ) | rpl::start_with_next([=] { - if (!preventsClose(crl::guard(this, [=]{ searchInTopic(); }))) { - searchInTopic(); - } + searchRequested(); }, _topBar->lifetime()); controller->adaptive().value( @@ -427,8 +429,10 @@ ChatWidget::ChatWidget( ChatWidget::~ChatWidget() { base::take(_sendAction); - session().api().saveCurrentDraftToCloud(); - controller()->sendingAnimation().clear(); + if (_repliesRootId) { + session().api().saveCurrentDraftToCloud(); + controller()->sendingAnimation().clear(); + } if (_topic) { if (_topic->creating()) { _emptyPainter = nullptr; @@ -1494,6 +1498,9 @@ void ChatWidget::edit( } void ChatWidget::refreshJoinGroupButton() { + if (!_repliesRootId) { + return; + } const auto set = [&](std::unique_ptr button) { if (!button && !_joinGroup) { return; @@ -1518,8 +1525,10 @@ void ChatWidget::refreshJoinGroupButton() { ? Data::CanSendAnything(channel) : (_topic && Data::CanSendAnything(_topic)); if (channel->amIn() || canSend) { + _canSendTexts = true; set(nullptr); } else { + _canSendTexts = false; if (!_joinGroup) { set(std::make_unique( this, @@ -1697,9 +1706,16 @@ FullReplyTo ChatWidget::replyTo() const { void ChatWidget::refreshTopBarActiveChat() { using namespace Dialogs; + const auto state = EntryState{ - .key = (_topic ? Key{ _topic } : Key{ _history }), - .section = EntryState::Section::Replies, + .key = (_sublist + ? Key{ _sublist } + : _topic + ? Key{ _topic } + : Key{ _history }), + .section = _sublist + ? EntryState::Section::SavedSublist + : EntryState::Section::Replies, .currentReplyTo = replyTo(), }; _topBar->setActiveChat(state, _sendAction.get()); @@ -1755,6 +1771,53 @@ void ChatWidget::checkLastPinnedClickedIdReset( } } +void ChatWidget::setupOpenChatButton() { + if (!_sublist || _sublist->peer()->isSavedHiddenAuthor()) { + return; + } else if (_sublist->parentChat()) { + _canSendTexts = true; + return; + } + _openChatButton = std::make_unique( + this, + (_sublist->peer()->isBroadcast() + ? tr::lng_saved_open_channel(tr::now) + : _sublist->peer()->isUser() + ? tr::lng_saved_open_chat(tr::now) + : tr::lng_saved_open_group(tr::now)), + st::historyComposeButton); + + _openChatButton->setClickedCallback([=] { + controller()->showPeerHistory( + _sublist->peer(), + Window::SectionShow::Way::Forward); + }); +} + +void ChatWidget::setupAboutHiddenAuthor() { + if (!_sublist || !_sublist->peer()->isSavedHiddenAuthor()) { + return; + } else if (_sublist->parentChat()) { + _canSendTexts = true; + return; + } + _aboutHiddenAuthor = std::make_unique(this); + _aboutHiddenAuthor->paintRequest() | rpl::start_with_next([=] { + auto p = QPainter(_aboutHiddenAuthor.get()); + auto rect = _aboutHiddenAuthor->rect(); + + p.fillRect(rect, st::historyReplyBg); + + p.setFont(st::normalFont); + p.setPen(st::windowSubTextFg); + p.drawText( + rect.marginsRemoved( + QMargins(st::historySendPadding, 0, st::historySendPadding, 0)), + tr::lng_saved_about_hidden(tr::now), + style::al_center); + }, _aboutHiddenAuthor->lifetime()); +} + void ChatWidget::setupTranslateBar() { controller()->adaptive().oneColumnValue( ) | rpl::start_with_next([=, raw = _translateBar.get()](bool one) { @@ -2031,7 +2094,11 @@ void ChatWidget::cornerButtonsShowAtPosition( } Data::Thread *ChatWidget::cornerButtonsThread() { - return _topic ? static_cast(_topic) : _history; + return _sublist + ? nullptr + : _topic + ? static_cast(_topic) + : _history; } FullMsgId ChatWidget::cornerButtonsCurrentId() { @@ -2094,7 +2161,8 @@ void ChatWidget::showAtPosition( const Window::SectionShow ¶ms) { _lastShownAt = position.fullId; controller()->setActiveChatEntry(activeChat()); - const auto ignore = (position.fullId.msg == _repliesRootId); + const auto ignore = _repliesRootId + && (position.fullId.msg == _repliesRootId); _inner->showAtPosition( position, params, @@ -2107,15 +2175,13 @@ void ChatWidget::updateAdaptiveLayout() { _topBar->height()); } -not_null ChatWidget::history() const { - return _history; -} - Dialogs::RowDescriptor ChatWidget::activeChat() const { const auto messageId = _lastShownAt ? _lastShownAt : FullMsgId(_peer->id, ShowAtUnreadMsgId); - if (_topic) { + if (_sublist) { + return { _sublist, messageId }; + } else if (_topic) { return { _topic, messageId }; } return { _history, messageId }; @@ -2205,6 +2271,10 @@ bool ChatWidget::showInternal( return false; } +bool ChatWidget::sameTypeAs(not_null memento) { + return dynamic_cast(memento.get()) != nullptr; +} + void ChatWidget::setInternalState( const QRect &geometry, not_null memento) { @@ -2242,11 +2312,14 @@ bool ChatWidget::showMessage( const auto message = _history->owner().message(id); if (!message) { return false; - } - if (_repliesRootId + } else if (_repliesRootId && !message->inThread(_repliesRootId) && id.msg != _repliesRootId) { return false; + } else if (_sublist && message->savedSublist() != _sublist) { + return false; + } else { + Unexpected("ChatWidget::showMessage context."); } const auto originMessage = [&]() -> HistoryItem* { using OriginMessage = Window::SectionShow::OriginMessage; @@ -2257,6 +2330,9 @@ bool ChatWidget::showMessage( } else if (_repliesRootId && returnTo->inThread(_repliesRootId)) { return returnTo; + } else if (_sublist + && returnTo->savedSublist() == _sublist) { + return returnTo; } } } @@ -2274,7 +2350,9 @@ bool ChatWidget::showMessage( Window::SectionActionResult ChatWidget::sendBotCommand( Bot::SendCommandRequest request) { - if (request.peer != _peer) { + if (!_repliesRootId) { + return Window::SectionActionResult::Fallback; + } else if (request.peer != _peer) { return Window::SectionActionResult::Ignore; } listSendBotCommand(request.command, request.context); @@ -2368,7 +2446,7 @@ void ChatWidget::setReplies(std::shared_ptr replies) { void ChatWidget::restoreState(not_null memento) { if (auto replies = memento->getReplies()) { setReplies(std::move(replies)); - } else if (!_replies) { + } else if (!_replies && _repliesRootId) { refreshReplies(); } _cornerButtons.setReplyReturns(memento->replyReturns()); @@ -2431,11 +2509,24 @@ void ChatWidget::updateControlsGeometry() { _translateBar->resizeToWidth(contentWidth); top += _translateBarHeight; - const auto bottom = height(); - const auto controlsHeight = _joinGroup - ? _joinGroup->height() - : _composeControls->heightCurrent(); - const auto scrollHeight = bottom - top - controlsHeight; + auto bottom = height(); + if (_openChatButton) { + _openChatButton->resizeToWidth(width()); + bottom -= _openChatButton->height(); + _openChatButton->move(0, bottom); + } else if (_aboutHiddenAuthor) { + _aboutHiddenAuthor->resize(width(), st::historyUnblock.height); + bottom -= _aboutHiddenAuthor->height(); + _aboutHiddenAuthor->move(0, bottom); + } else if (_joinGroup) { + _joinGroup->resizeToWidth(width()); + bottom -= _joinGroup->height(); + _joinGroup->move(0, bottom); + } else { + bottom -= _composeControls->heightCurrent(); + } + + const auto scrollHeight = bottom - top; const auto scrollSize = QSize(contentWidth, scrollHeight); if (_scroll->size() != scrollSize) { _skipScrollEvent = true; @@ -2450,14 +2541,7 @@ void ChatWidget::updateControlsGeometry() { } updateInnerVisibleArea(); } - if (_joinGroup) { - _joinGroup->setGeometry( - 0, - bottom - _joinGroup->height(), - contentWidth, - _joinGroup->height()); - } - _composeControls->move(0, bottom - controlsHeight); + _composeControls->move(0, bottom); _composeControls->setAutocompleteBoundingRect(_scroll->geometry()); _cornerButtons.updatePositions(); @@ -2570,7 +2654,7 @@ void ChatWidget::showAnimatedHook( void ChatWidget::showFinishedHook() { _topBar->setAnimatingMode(false); - if (_joinGroup) { + if (_joinGroup || _openChatButton || _aboutHiddenAuthor) { if (Ui::InFocusChain(this)) { _inner->setFocus(); } @@ -2606,7 +2690,7 @@ QRect ChatWidget::floatPlayerAvailableRect() { } Context ChatWidget::listContext() { - return Context::Replies; + return _sublist ? Context::SavedSublist : Context::Replies; } bool ChatWidget::listScrollTo(int top, bool syntetic) { @@ -2651,24 +2735,97 @@ void ChatWidget::listTryProcessKeyInput(not_null e) { _composeControls->tryProcessKeyInput(e); } +void ChatWidget::markLoaded() { + if (!_loaded) { + _loaded = true; + crl::on_main(this, [=] { + updatePinnedVisibility(); + }); + } +} + rpl::producer ChatWidget::listSource( Data::MessagePosition aroundId, int limitBefore, int limitAfter) { + if (_replies) { + return repliesSource(aroundId, limitBefore, limitAfter); + } else if (_sublist) { + return sublistSource(aroundId, limitBefore, limitAfter); + } + Unexpected("ChatWidget::listSource in unknown mode"); +} + +rpl::producer ChatWidget::repliesSource( + Data::MessagePosition aroundId, + int limitBefore, + int limitAfter) { return _replies->source( aroundId, limitBefore, limitAfter ) | rpl::before_next([=] { // after_next makes a copy of value. - if (!_loaded) { - _loaded = true; - crl::on_main(this, [=] { - updatePinnedVisibility(); - }); - } + markLoaded(); }); } +rpl::producer ChatWidget::sublistSource( + Data::MessagePosition aroundId, + int limitBefore, + int limitAfter) { + const auto messageId = aroundId.fullId.msg + ? aroundId.fullId.msg + : (ServerMaxMsgId - 1); + return [=](auto consumer) { + const auto pushSlice = [=] { + auto result = Data::MessagesSlice(); + result.fullCount = _sublist->fullCount(); + _topBar->setCustomTitle(result.fullCount + ? tr::lng_forum_messages( + tr::now, + lt_count_decimal, + *result.fullCount) + : tr::lng_contacts_loading(tr::now)); + const auto &messages = _sublist->messages(); + const auto i = ranges::lower_bound( + messages, + messageId, + ranges::greater(), + [](not_null item) { return item->id; }); + const auto before = int(end(messages) - i); + const auto useBefore = std::min(before, limitBefore); + const auto after = int(i - begin(messages)); + const auto useAfter = std::min(after, limitAfter); + const auto from = i - useAfter; + const auto till = i + useBefore; + auto nearestDistance = std::numeric_limits::max(); + result.ids.reserve(useAfter + useBefore); + for (auto j = till; j != from;) { + const auto item = *--j; + result.ids.push_back(item->fullId()); + const auto distance = std::abs((messageId - item->id).bare); + if (nearestDistance > distance) { + nearestDistance = distance; + result.nearestToAround = result.ids.back(); + } + } + result.skippedAfter = after - useAfter; + result.skippedBefore = result.fullCount + ? (*result.fullCount - after - useBefore) + : std::optional(); + if (!result.fullCount || useBefore < limitBefore) { + _sublist->parent()->loadMore(_sublist); + } + markLoaded(); + consumer.put_next(std::move(result)); + }; + auto lifetime = rpl::lifetime(); + _sublist->changes() | rpl::start_with_next(pushSlice, lifetime); + pushSlice(); + return lifetime; + }; +} + bool ChatWidget::listAllowsMultiSelect() { return true; } @@ -2681,7 +2838,9 @@ bool ChatWidget::listIsItemGoodForSelection( bool ChatWidget::listIsLessInOrder( not_null first, not_null second) { - return first->position() < second->position(); + return _sublist + ? (first->id < second->id) + : first->position() < second->position(); } void ChatWidget::listSelectionChanged(SelectedItems &&items) { @@ -2705,17 +2864,21 @@ void ChatWidget::listSelectionChanged(SelectedItems &&items) { } void ChatWidget::listMarkReadTill(not_null item) { - _replies->readTill(item); + if (_replies) { + _replies->readTill(item); + } } void ChatWidget::listMarkContentsRead( const base::flat_set> &items) { - session().api().markContentsRead(items); + if (!_sublist) { + session().api().markContentsRead(items); + } } MessagesBarData ChatWidget::listMessagesBar( const std::vector> &elements) { - if (elements.empty()) { + if (_sublist || elements.empty()) { return {}; } const auto till = _replies->computeInboxReadTillFull(); @@ -2759,7 +2922,9 @@ void ChatWidget::listUpdateDateLink( } bool ChatWidget::listElementHideReply(not_null view) { - if (const auto reply = view->data()->Get()) { + if (_sublist) { + return false; + } else if (const auto reply = view->data()->Get()) { const auto replyToPeerId = reply->externalPeerId() ? reply->externalPeerId() : _peer->id; @@ -2781,7 +2946,9 @@ bool ChatWidget::listElementHideReply(not_null view) { } bool ChatWidget::listElementShownUnread(not_null view) { - return _replies->isServerSideUnread(view->data()); + return _replies + ? _replies->isServerSideUnread(view->data()) + : view->data()->unread(view->data()->history()); } bool ChatWidget::listIsGoodForAroundPosition( @@ -2792,7 +2959,9 @@ bool ChatWidget::listIsGoodForAroundPosition( void ChatWidget::listSendBotCommand( const QString &command, const FullMsgId &context) { - sendBotCommandWithOptions(command, context, {}); + if (!_sublist) { + sendBotCommandWithOptions(command, context, {}); + } } void ChatWidget::sendBotCommandWithOptions( @@ -2825,11 +2994,18 @@ void ChatWidget::sendBotCommandWithOptions( void ChatWidget::listSearch( const QString &query, const FullMsgId &context) { - controller()->searchMessages(query, _history); + const auto inChat = !_sublist + ? Dialogs::Key(_history) + : Data::SearchTagFromQuery(query) + ? Dialogs::Key(_sublist) + : Dialogs::Key(); + controller()->searchMessages(query, inChat); } void ChatWidget::listHandleViaClick(not_null bot) { - _composeControls->setText({ '@' + bot->username() + ' ' }); + if (_canSendTexts) { + _composeControls->setText({ '@' + bot->username() + ' ' }); + } } not_null ChatWidget::listChatTheme() { @@ -3001,14 +3177,20 @@ void ChatWidget::setupShortcuts() { }) | rpl::start_with_next([=](not_null request) { using Command = Shortcuts::Command; request->check(Command::Search, 1) && request->handle([=] { - if (!preventsClose(crl::guard(this, [=]{ searchInTopic(); }))) { - searchInTopic(); - } + searchRequested(); return true; }); }, lifetime()); } +void ChatWidget::searchRequested() { + if (_sublist) { + controller()->searchInChat(_sublist); + } else if (!preventsClose(crl::guard(this, [=] { searchInTopic(); }))) { + searchInTopic(); + } +} + void ChatWidget::searchInTopic() { if (_topic) { controller()->searchInChat(_topic); @@ -3048,4 +3230,52 @@ void ChatWidget::searchInTopic() { } } +bool ChatWidget::searchInChatEmbedded( + QString query, + Dialogs::Key chat, + PeerData *searchFrom) { + const auto sublist = chat.sublist(); + if (!sublist || sublist != _sublist) { + return false; + } else if (_composeSearch) { + _composeSearch->setQuery(query); + _composeSearch->setInnerFocus(); + return true; + } + _composeSearch = std::make_unique( + this, + controller(), + _history, + sublist->peer(), + query); + + updateControlsGeometry(); + setInnerFocus(); + + _composeSearch->activations( + ) | rpl::start_with_next([=](ComposeSearch::Activation activation) { + const auto item = activation.item; + auto params = ::Window::SectionShow( + ::Window::SectionShow::Way::ClearStack); + params.highlightPart = { activation.query }; + params.highlightPartOffsetHint = kSearchQueryOffsetHint; + controller()->showPeerHistory( + item->history()->peer->id, + params, + item->fullId().msg); + }, _composeSearch->lifetime()); + + _composeSearch->destroyRequests( + ) | rpl::take( + 1 + ) | rpl::start_with_next([=] { + _composeSearch = nullptr; + + updateControlsGeometry(); + setInnerFocus(); + }, _composeSearch->lifetime()); + + return true; +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.h b/Telegram/SourceFiles/history/view/history_view_chat_section.h index f66391d801..c38fe6dbe8 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_section.h +++ b/Telegram/SourceFiles/history/view/history_view_chat_section.h @@ -93,7 +93,9 @@ public: ChatViewId id); ~ChatWidget(); - [[nodiscard]] not_null history() const; + [[nodiscard]] ChatViewId id() const { + return _id; + } Dialogs::RowDescriptor activeChat() const override; bool preventsClose(Fn &&continueCallback) const override; @@ -107,6 +109,7 @@ public: bool showInternal( not_null memento, const Window::SectionShow ¶ms) override; + bool sameTypeAs(not_null memento) override; std::shared_ptr createMemento() override; bool showMessage( PeerId peerId, @@ -116,6 +119,11 @@ public: Window::SectionActionResult sendBotCommand( Bot::SendCommandRequest request) override; + bool searchInChatEmbedded( + QString query, + Dialogs::Key chat, + PeerData *searchFrom = nullptr) override; + bool confirmSendingFiles(const QStringList &files) override; bool confirmSendingFiles(not_null data) override; @@ -221,6 +229,16 @@ private: int starsApproved, Fn withPaymentApproved); + void markLoaded(); + [[nodiscard]] rpl::producer repliesSource( + Data::MessagePosition aroundId, + int limitBefore, + int limitAfter); + [[nodiscard]] rpl::producer sublistSource( + Data::MessagePosition aroundId, + int limitBefore, + int limitAfter); + void onScroll(); void updateInnerVisibleArea(); void updateControlsGeometry(); @@ -249,10 +267,15 @@ private: void subscribeToTopic(); void subscribeToPinnedMessages(); void setTopic(Data::ForumTopic *topic); + + void setupOpenChatButton(); + void setupAboutHiddenAuthor(); + void setupDragArea(); void setupShortcuts(); void setupTranslateBar(); + void searchRequested(); void searchInTopic(); void updatePinnedVisibility(); @@ -377,7 +400,10 @@ private: std::unique_ptr _joinGroup; std::unique_ptr _payForMessage; std::unique_ptr _topicReopenBar; + std::unique_ptr _openChatButton; + std::unique_ptr _aboutHiddenAuthor; std::unique_ptr _emptyPainter; + bool _canSendTexts = false; bool _skipScrollEvent = false; bool _synteticScrollEvent = false; diff --git a/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp b/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp deleted file mode 100644 index c3f74ac708..0000000000 --- a/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp +++ /dev/null @@ -1,795 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#include "history/view/history_view_sublist_section.h" - -#include "main/main_session.h" -#include "core/application.h" -#include "core/shortcuts.h" -#include "data/data_message_reaction_id.h" -#include "data/data_saved_messages.h" -#include "data/data_saved_sublist.h" -#include "data/data_session.h" -#include "data/data_peer_values.h" -#include "data/data_user.h" -#include "history/view/controls/history_view_compose_search.h" -#include "history/view/history_view_top_bar_widget.h" -#include "history/view/history_view_translate_bar.h" -#include "history/view/history_view_list_widget.h" -#include "history/history.h" -#include "history/history_item.h" -#include "history/history_view_swipe_back_session.h" -#include "lang/lang_keys.h" -#include "ui/chat/chat_style.h" -#include "ui/widgets/buttons.h" -#include "ui/widgets/scroll_area.h" -#include "ui/widgets/shadow.h" -#include "ui/ui_utility.h" -#include "window/window_session_controller.h" -#include "styles/style_chat.h" -#include "styles/style_chat_helpers.h" -#include "styles/style_window.h" - -namespace HistoryView { -namespace { - -} // namespace - -SublistMemento::SublistMemento(not_null sublist) -: _sublist(sublist) { - const auto selfId = sublist->session().userPeerId(); - _list.setAroundPosition({ - .fullId = FullMsgId(selfId, ShowAtUnreadMsgId), - .date = TimeId(0), - }); -} - -object_ptr SublistMemento::createWidget( - QWidget *parent, - not_null controller, - Window::Column column, - const QRect &geometry) { - if (column == Window::Column::Third) { - return nullptr; - } - auto result = object_ptr( - parent, - controller, - _sublist); - result->setInternalState(geometry, this); - return result; -} - -SublistWidget::SublistWidget( - QWidget *parent, - not_null controller, - not_null sublist) -: Window::SectionWidget(parent, controller, sublist->peer()) -, WindowListDelegate(controller) -, _sublist(sublist) -, _history(sublist->owner().history(sublist->session().user())) -, _topBar(this, controller) -, _topBarShadow(this) -, _translateBar(std::make_unique(this, controller, _history)) -, _scroll(std::make_unique( - this, - controller->chatStyle()->value(lifetime(), st::historyScroll), - false)) -, _cornerButtons( - _scroll.get(), - controller->chatStyle(), - static_cast(this)) { - controller->chatStyle()->paletteChanged( - ) | rpl::start_with_next([=] { - _scroll->updateBars(); - }, _scroll->lifetime()); - - setupOpenChatButton(); - setupAboutHiddenAuthor(); - - Window::ChatThemeValueFromPeer( - controller, - sublist->peer() - ) | rpl::start_with_next([=](std::shared_ptr &&theme) { - _theme = std::move(theme); - controller->setChatStyleTheme(_theme); - }, lifetime()); - - _topBar->setActiveChat( - TopBarWidget::ActiveChat{ - .key = sublist, - .section = Dialogs::EntryState::Section::SavedSublist, - }, - nullptr); - - _topBar->move(0, 0); - _topBar->resizeToWidth(width()); - _topBar->show(); - - _topBar->deleteSelectionRequest( - ) | rpl::start_with_next([=] { - confirmDeleteSelected(); - }, _topBar->lifetime()); - _topBar->forwardSelectionRequest( - ) | rpl::start_with_next([=] { - confirmForwardSelected(); - }, _topBar->lifetime()); - _topBar->clearSelectionRequest( - ) | rpl::start_with_next([=] { - clearSelected(); - }, _topBar->lifetime()); - _topBar->searchRequest( - ) | rpl::start_with_next([=] { - searchInSublist(); - }, _topBar->lifetime()); - - _translateBar->raise(); - _topBarShadow->raise(); - controller->adaptive().value( - ) | rpl::start_with_next([=] { - updateAdaptiveLayout(); - }, lifetime()); - - _inner = _scroll->setOwnedWidget(object_ptr( - this, - &controller->session(), - static_cast(this))); - _scroll->move(0, _topBar->height()); - _scroll->show(); - _scroll->scrolls( - ) | rpl::start_with_next([=] { - onScroll(); - }, lifetime()); - - setupShortcuts(); - setupTranslateBar(); - Window::SetupSwipeBackSection(this, _scroll.get(), _inner); -} - -SublistWidget::~SublistWidget() = default; - -void SublistWidget::setupOpenChatButton() { - if (_sublist->peer()->isSavedHiddenAuthor()) { - return; - } - _openChatButton = std::make_unique( - this, - (_sublist->peer()->isBroadcast() - ? tr::lng_saved_open_channel(tr::now) - : _sublist->peer()->isUser() - ? tr::lng_saved_open_chat(tr::now) - : tr::lng_saved_open_group(tr::now)), - st::historyComposeButton); - - _openChatButton->setClickedCallback([=] { - controller()->showPeerHistory( - _sublist->peer(), - Window::SectionShow::Way::Forward); - }); -} - -void SublistWidget::setupAboutHiddenAuthor() { - if (!_sublist->peer()->isSavedHiddenAuthor()) { - return; - } - _aboutHiddenAuthor = std::make_unique(this); - _aboutHiddenAuthor->paintRequest() | rpl::start_with_next([=] { - auto p = QPainter(_aboutHiddenAuthor.get()); - auto rect = _aboutHiddenAuthor->rect(); - - p.fillRect(rect, st::historyReplyBg); - - p.setFont(st::normalFont); - p.setPen(st::windowSubTextFg); - p.drawText( - rect.marginsRemoved( - QMargins(st::historySendPadding, 0, st::historySendPadding, 0)), - tr::lng_saved_about_hidden(tr::now), - style::al_center); - }, _aboutHiddenAuthor->lifetime()); -} - -void SublistWidget::setupTranslateBar() { - controller()->adaptive().oneColumnValue( - ) | rpl::start_with_next([=, raw = _translateBar.get()](bool one) { - raw->setShadowGeometryPostprocess([=](QRect geometry) { - if (!one) { - geometry.setLeft(geometry.left() + st::lineWidth); - } - return geometry; - }); - }, _translateBar->lifetime()); - - _translateBarHeight = 0; - _translateBar->heightValue( - ) | rpl::start_with_next([=](int height) { - if (const auto delta = height - _translateBarHeight) { - _translateBarHeight = height; - setGeometryWithTopMoved(geometry(), delta); - } - }, _translateBar->lifetime()); - - _translateBar->finishAnimating(); -} - -void SublistWidget::cornerButtonsShowAtPosition( - Data::MessagePosition position) { - showAtPosition(position); -} - -Data::Thread *SublistWidget::cornerButtonsThread() { - return nullptr; -} - -FullMsgId SublistWidget::cornerButtonsCurrentId() { - return _lastShownAt; -} - -bool SublistWidget::cornerButtonsIgnoreVisibility() { - return animatingShow(); -} - -std::optional SublistWidget::cornerButtonsDownShown() { - const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; - if (top < _scroll->scrollTopMax() || _cornerButtons.replyReturn()) { - return true; - } else if (_inner->loadedAtBottomKnown()) { - return !_inner->loadedAtBottom(); - } - return std::nullopt; -} - -bool SublistWidget::cornerButtonsUnreadMayBeShown() { - return _inner->loadedAtBottomKnown(); -} - -bool SublistWidget::cornerButtonsHas(CornerButtonType type) { - return (type == CornerButtonType::Down); -} - -void SublistWidget::showAtPosition( - Data::MessagePosition position, - FullMsgId originId) { - showAtPosition(position, originId, {}); -} - -void SublistWidget::showAtPosition( - Data::MessagePosition position, - FullMsgId originItemId, - const Window::SectionShow ¶ms) { - _lastShownAt = position.fullId; - controller()->setActiveChatEntry(activeChat()); - _inner->showAtPosition( - position, - params, - _cornerButtons.doneJumpFrom(position.fullId, originItemId)); -} -void SublistWidget::updateAdaptiveLayout() { - _topBarShadow->moveToLeft( - controller()->adaptive().isOneColumn() ? 0 : st::lineWidth, - _topBar->height()); -} - -not_null SublistWidget::sublist() const { - return _sublist; -} - -Dialogs::RowDescriptor SublistWidget::activeChat() const { - const auto messageId = _lastShownAt - ? _lastShownAt - : FullMsgId(_history->peer->id, ShowAtUnreadMsgId); - return { _sublist, messageId }; -} - -QPixmap SublistWidget::grabForShowAnimation( - const Window::SectionSlideParams ¶ms) { - _topBar->updateControlsVisibility(); - if (params.withTopBarShadow) _topBarShadow->hide(); - auto result = Ui::GrabWidget(this); - if (params.withTopBarShadow) _topBarShadow->show(); - _translateBar->hide(); - return result; -} - -void SublistWidget::checkActivation() { - _inner->checkActivation(); -} - -void SublistWidget::doSetInnerFocus() { - if (_composeSearch) { - _composeSearch->setInnerFocus(); - } else { - _inner->setFocus(); - } -} - -bool SublistWidget::showInternal( - not_null memento, - const Window::SectionShow ¶ms) { - if (auto logMemento = dynamic_cast(memento.get())) { - if (logMemento->getSublist() == sublist()) { - restoreState(logMemento); - return true; - } - } - return false; -} - -bool SublistWidget::sameTypeAs(not_null memento) { - return dynamic_cast(memento.get()) != nullptr; -} - -void SublistWidget::setInternalState( - const QRect &geometry, - not_null memento) { - setGeometry(geometry); - Ui::SendPendingMoveResizeEvents(this); - restoreState(memento); -} - -bool SublistWidget::searchInChatEmbedded( - QString query, - Dialogs::Key chat, - PeerData *searchFrom) { - const auto sublist = chat.sublist(); - if (!sublist || sublist != _sublist) { - return false; - } else if (_composeSearch) { - _composeSearch->setQuery(query); - _composeSearch->setInnerFocus(); - return true; - } - _composeSearch = std::make_unique( - this, - controller(), - _history, - sublist->peer(), - query); - - updateControlsGeometry(); - setInnerFocus(); - - _composeSearch->activations( - ) | rpl::start_with_next([=](ComposeSearch::Activation activation) { - const auto item = activation.item; - auto params = ::Window::SectionShow( - ::Window::SectionShow::Way::ClearStack); - params.highlightPart = { activation.query }; - params.highlightPartOffsetHint = kSearchQueryOffsetHint; - controller()->showPeerHistory( - item->history()->peer->id, - params, - item->fullId().msg); - }, _composeSearch->lifetime()); - - _composeSearch->destroyRequests( - ) | rpl::take( - 1 - ) | rpl::start_with_next([=] { - _composeSearch = nullptr; - - updateControlsGeometry(); - setInnerFocus(); - }, _composeSearch->lifetime()); - - return true; -} - -std::shared_ptr SublistWidget::createMemento() { - auto result = std::make_shared(sublist()); - saveState(result.get()); - return result; -} - -bool SublistWidget::showMessage( - PeerId peerId, - const Window::SectionShow ¶ms, - MsgId messageId) { - const auto id = FullMsgId(_history->peer->id, messageId); - const auto message = _history->owner().message(id); - if (!message || message->savedSublist() != _sublist) { - return false; - } - const auto originMessage = [&]() -> HistoryItem* { - using OriginMessage = Window::SectionShow::OriginMessage; - if (const auto origin = std::get_if(¶ms.origin)) { - if (const auto returnTo = session().data().message(origin->id)) { - if (returnTo->savedSublist() == _sublist) { - return returnTo; - } - } - } - return nullptr; - }(); - const auto currentReplyReturn = _cornerButtons.replyReturn(); - const auto originItemId = !originMessage - ? FullMsgId() - : (currentReplyReturn != originMessage) - ? originMessage->fullId() - : FullMsgId(); - showAtPosition(message->position(), originItemId, params); - return true; -} - -void SublistWidget::saveState(not_null memento) { - _inner->saveState(memento->list()); -} - -void SublistWidget::restoreState(not_null memento) { - _inner->restoreState(memento->list()); -} - -void SublistWidget::resizeEvent(QResizeEvent *e) { - if (!width() || !height()) { - return; - } - recountChatWidth(); - updateControlsGeometry(); -} - -void SublistWidget::recountChatWidth() { - auto layout = (width() < st::adaptiveChatWideWidth) - ? Window::Adaptive::ChatLayout::Normal - : Window::Adaptive::ChatLayout::Wide; - controller()->adaptive().setChatLayout(layout); -} - -void SublistWidget::updateControlsGeometry() { - const auto contentWidth = width(); - - const auto newScrollTop = _scroll->isHidden() - ? std::nullopt - : base::make_optional(_scroll->scrollTop() + topDelta()); - _topBar->resizeToWidth(contentWidth); - _topBarShadow->resize(contentWidth, st::lineWidth); - - auto bottom = height(); - if (_openChatButton) { - _openChatButton->resizeToWidth(width()); - bottom -= _openChatButton->height(); - _openChatButton->move(0, bottom); - } - if (_aboutHiddenAuthor) { - _aboutHiddenAuthor->resize(width(), st::historyUnblock.height); - bottom -= _aboutHiddenAuthor->height(); - _aboutHiddenAuthor->move(0, bottom); - } - const auto controlsHeight = 0; - auto top = _topBar->height(); - _translateBar->move(0, top); - _translateBar->resizeToWidth(contentWidth); - top += _translateBarHeight; - const auto scrollHeight = bottom - top - controlsHeight; - const auto scrollSize = QSize(contentWidth, scrollHeight); - if (_scroll->size() != scrollSize) { - _skipScrollEvent = true; - _scroll->resize(scrollSize); - _inner->resizeToWidth(scrollSize.width(), _scroll->height()); - _skipScrollEvent = false; - } - _scroll->move(0, top); - if (!_scroll->isHidden()) { - if (newScrollTop) { - _scroll->scrollToY(*newScrollTop); - } - updateInnerVisibleArea(); - } - - _cornerButtons.updatePositions(); -} - -void SublistWidget::paintEvent(QPaintEvent *e) { - if (animatingShow()) { - SectionWidget::paintEvent(e); - return; - } else if (controller()->contentOverlapped(this, e)) { - return; - } - - const auto aboveHeight = _topBar->height(); - const auto bg = e->rect().intersected( - QRect(0, aboveHeight, width(), height() - aboveHeight)); - SectionWidget::PaintBackground(controller(), _theme.get(), this, bg); -} - -void SublistWidget::onScroll() { - if (_skipScrollEvent) { - return; - } - updateInnerVisibleArea(); -} - -void SublistWidget::updateInnerVisibleArea() { - const auto scrollTop = _scroll->scrollTop(); - _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); - _cornerButtons.updateJumpDownVisibility(); - _cornerButtons.updateUnreadThingsVisibility(); -} - -void SublistWidget::showAnimatedHook( - const Window::SectionSlideParams ¶ms) { - _topBar->setAnimatingMode(true); - if (params.withTopBarShadow) { - _topBarShadow->show(); - } -} - -void SublistWidget::showFinishedHook() { - _topBar->setAnimatingMode(false); - _inner->showFinished(); - _translateBar->show(); -} - -bool SublistWidget::floatPlayerHandleWheelEvent(QEvent *e) { - return _scroll->viewportEvent(e); -} - -QRect SublistWidget::floatPlayerAvailableRect() { - return mapToGlobal(_scroll->geometry()); -} - -Context SublistWidget::listContext() { - return Context::SavedSublist; -} - -bool SublistWidget::listScrollTo(int top, bool syntetic) { - top = std::clamp(top, 0, _scroll->scrollTopMax()); - if (_scroll->scrollTop() == top) { - updateInnerVisibleArea(); - return false; - } - _scroll->scrollToY(top); - return true; -} - -void SublistWidget::listCancelRequest() { - if (_inner && !_inner->getSelectedIds().empty()) { - clearSelected(); - return; - } - controller()->showBackFromStack(); -} - -void SublistWidget::listDeleteRequest() { - confirmDeleteSelected(); -} - -void SublistWidget::listTryProcessKeyInput(not_null e) { -} - -rpl::producer SublistWidget::listSource( - Data::MessagePosition aroundId, - int limitBefore, - int limitAfter) { - const auto messageId = aroundId.fullId.msg - ? aroundId.fullId.msg - : (ServerMaxMsgId - 1); - return [=](auto consumer) { - const auto pushSlice = [=] { - auto result = Data::MessagesSlice(); - result.fullCount = _sublist->fullCount(); - _topBar->setCustomTitle(result.fullCount - ? tr::lng_forum_messages( - tr::now, - lt_count_decimal, - *result.fullCount) - : tr::lng_contacts_loading(tr::now)); - const auto &messages = _sublist->messages(); - const auto i = ranges::lower_bound( - messages, - messageId, - ranges::greater(), - [](not_null item) { return item->id; }); - const auto before = int(end(messages) - i); - const auto useBefore = std::min(before, limitBefore); - const auto after = int(i - begin(messages)); - const auto useAfter = std::min(after, limitAfter); - const auto from = i - useAfter; - const auto till = i + useBefore; - auto nearestDistance = std::numeric_limits::max(); - result.ids.reserve(useAfter + useBefore); - for (auto j = till; j != from;) { - const auto item = *--j; - result.ids.push_back(item->fullId()); - const auto distance = std::abs((messageId - item->id).bare); - if (nearestDistance > distance) { - nearestDistance = distance; - result.nearestToAround = result.ids.back(); - } - } - result.skippedAfter = after - useAfter; - result.skippedBefore = result.fullCount - ? (*result.fullCount - after - useBefore) - : std::optional(); - if (!result.fullCount || useBefore < limitBefore) { - _sublist->parent()->loadMore(_sublist); - } - consumer.put_next(std::move(result)); - }; - auto lifetime = rpl::lifetime(); - _sublist->changes() | rpl::start_with_next(pushSlice, lifetime); - pushSlice(); - return lifetime; - }; -} - -bool SublistWidget::listAllowsMultiSelect() { - return true; -} - -bool SublistWidget::listIsItemGoodForSelection( - not_null item) { - return item->isRegular() && !item->isService(); -} - -bool SublistWidget::listIsLessInOrder( - not_null first, - not_null second) { - return first->id < second->id; -} - -void SublistWidget::listSelectionChanged(SelectedItems &&items) { - HistoryView::TopBarWidget::SelectedState state; - state.count = items.size(); - for (const auto &item : items) { - if (item.canDelete) { - ++state.canDeleteCount; - } - if (item.canForward) { - ++state.canForwardCount; - } - } - _topBar->showSelected(state); - if ((state.count > 0) && _composeSearch) { - _composeSearch->hideAnimated(); - } -} - -void SublistWidget::listMarkReadTill(not_null item) { -} - -void SublistWidget::listMarkContentsRead( - const base::flat_set> &items) { -} - -MessagesBarData SublistWidget::listMessagesBar( - const std::vector> &elements) { - return {}; -} - -void SublistWidget::listContentRefreshed() { -} - -void SublistWidget::listUpdateDateLink( - ClickHandlerPtr &link, - not_null view) { -} - -bool SublistWidget::listElementHideReply(not_null view) { - return false; -} - -bool SublistWidget::listElementShownUnread(not_null view) { - return view->data()->unread(view->data()->history()); -} - -bool SublistWidget::listIsGoodForAroundPosition( - not_null view) { - return view->data()->isRegular(); -} - -void SublistWidget::listSendBotCommand( - const QString &command, - const FullMsgId &context) { -} - -void SublistWidget::listSearch( - const QString &query, - const FullMsgId &context) { - const auto inChat = Data::SearchTagFromQuery(query) - ? Dialogs::Key(_sublist) - : Dialogs::Key(); - controller()->searchMessages(query, inChat); -} - -void SublistWidget::listHandleViaClick(not_null bot) { -} - -not_null SublistWidget::listChatTheme() { - return _theme.get(); -} - -CopyRestrictionType SublistWidget::listCopyRestrictionType( - HistoryItem *item) { - return CopyRestrictionTypeFor(_history->peer, item); -} - -CopyRestrictionType SublistWidget::listCopyMediaRestrictionType( - not_null item) { - return CopyMediaRestrictionTypeFor(_history->peer, item); -} - -CopyRestrictionType SublistWidget::listSelectRestrictionType() { - return SelectRestrictionTypeFor(_history->peer); -} - -auto SublistWidget::listAllowedReactionsValue() --> rpl::producer { - return Data::PeerAllowedReactionsValue(_history->peer); -} - -void SublistWidget::listShowPremiumToast(not_null document) { -} - -void SublistWidget::listOpenPhoto( - not_null photo, - FullMsgId context) { - controller()->openPhoto(photo, { context }); -} - -void SublistWidget::listOpenDocument( - not_null document, - FullMsgId context, - bool showInMediaView) { - controller()->openDocument(document, showInMediaView, { context }); -} - -void SublistWidget::listPaintEmpty( - Painter &p, - const Ui::ChatPaintContext &context) { -} - -QString SublistWidget::listElementAuthorRank(not_null view) { - return {}; -} - -bool SublistWidget::listElementHideTopicButton( - not_null view) { - return true; -} - -History *SublistWidget::listTranslateHistory() { - return _history; -} - -void SublistWidget::listAddTranslatedItems( - not_null tracker) { -} - -void SublistWidget::confirmDeleteSelected() { - ConfirmDeleteSelectedItems(_inner); -} - -void SublistWidget::confirmForwardSelected() { - ConfirmForwardSelectedItems(_inner); -} - -void SublistWidget::clearSelected() { - _inner->cancelSelection(); -} - -void SublistWidget::setupShortcuts() { - Shortcuts::Requests( - ) | rpl::filter([=] { - return Ui::AppInFocus() - && Ui::InFocusChain(this) - && !controller()->isLayerShown() - && (Core::App().activeWindow() == &controller()->window()); - }) | rpl::start_with_next([=](not_null request) { - using Command = Shortcuts::Command; - request->check(Command::Search, 1) && request->handle([=] { - searchInSublist(); - return true; - }); - }, lifetime()); -} - -void SublistWidget::searchInSublist() { - controller()->searchInChat(_sublist); -} - -} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_sublist_section.h b/Telegram/SourceFiles/history/view/history_view_sublist_section.h deleted file mode 100644 index 33b655720e..0000000000 --- a/Telegram/SourceFiles/history/view/history_view_sublist_section.h +++ /dev/null @@ -1,237 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#pragma once - -#include "window/section_widget.h" -#include "window/section_memento.h" -#include "history/view/history_view_list_widget.h" -#include "history/view/history_view_corner_buttons.h" -#include "data/data_messages.h" -#include "base/weak_ptr.h" -#include "base/timer.h" - -class History; - -namespace Ui { -class ScrollArea; -class PlainShadow; -class FlatButton; -} // namespace Ui - -namespace Profile { -class BackButton; -} // namespace Profile - -namespace HistoryView { - -class Element; -class TopBarWidget; -class SublistMemento; -class TranslateBar; -class ComposeSearch; - -class SublistWidget final - : public Window::SectionWidget - , private WindowListDelegate - , private CornerButtonsDelegate { -public: - SublistWidget( - QWidget *parent, - not_null controller, - not_null sublist); - ~SublistWidget(); - - [[nodiscard]] not_null sublist() const; - Dialogs::RowDescriptor activeChat() const override; - - bool hasTopBarShadow() const override { - return true; - } - - QPixmap grabForShowAnimation( - const Window::SectionSlideParams ¶ms) override; - - bool showInternal( - not_null memento, - const Window::SectionShow ¶ms) override; - bool sameTypeAs(not_null memento) override; - - std::shared_ptr createMemento() override; - bool showMessage( - PeerId peerId, - const Window::SectionShow ¶ms, - MsgId messageId) override; - - void setInternalState( - const QRect &geometry, - not_null memento); - - Window::SectionActionResult sendBotCommand( - Bot::SendCommandRequest request) override { - return Window::SectionActionResult::Fallback; - } - - bool searchInChatEmbedded( - QString query, - Dialogs::Key chat, - PeerData *searchFrom = nullptr) override; - - // Float player interface. - bool floatPlayerHandleWheelEvent(QEvent *e) override; - QRect floatPlayerAvailableRect() override; - - // ListDelegate interface. - Context listContext() override; - bool listScrollTo(int top, bool syntetic = true) override; - void listCancelRequest() override; - void listDeleteRequest() override; - void listTryProcessKeyInput(not_null e) override; - rpl::producer listSource( - Data::MessagePosition aroundId, - int limitBefore, - int limitAfter) override; - bool listAllowsMultiSelect() override; - bool listIsItemGoodForSelection(not_null item) override; - bool listIsLessInOrder( - not_null first, - not_null second) override; - void listSelectionChanged(SelectedItems &&items) override; - void listMarkReadTill(not_null item) override; - void listMarkContentsRead( - const base::flat_set> &items) override; - MessagesBarData listMessagesBar( - const std::vector> &elements) override; - void listContentRefreshed() override; - void listUpdateDateLink( - ClickHandlerPtr &link, - not_null view) override; - bool listElementHideReply(not_null view) override; - bool listElementShownUnread(not_null view) override; - bool listIsGoodForAroundPosition(not_null view) override; - void listSendBotCommand( - const QString &command, - const FullMsgId &context) override; - void listSearch( - const QString &query, - const FullMsgId &context) override; - void listHandleViaClick(not_null bot) override; - not_null listChatTheme() override; - CopyRestrictionType listCopyRestrictionType(HistoryItem *item) override; - CopyRestrictionType listCopyMediaRestrictionType( - not_null item) override; - CopyRestrictionType listSelectRestrictionType() override; - auto listAllowedReactionsValue() - -> rpl::producer override; - void listShowPremiumToast(not_null document) override; - void listOpenPhoto( - not_null photo, - FullMsgId context) override; - void listOpenDocument( - not_null document, - FullMsgId context, - bool showInMediaView) override; - void listPaintEmpty( - Painter &p, - const Ui::ChatPaintContext &context) override; - QString listElementAuthorRank(not_null view) override; - bool listElementHideTopicButton(not_null view) override; - History *listTranslateHistory() override; - void listAddTranslatedItems( - not_null tracker) override; - - // CornerButtonsDelegate delegate. - void cornerButtonsShowAtPosition( - Data::MessagePosition position) override; - Data::Thread *cornerButtonsThread() override; - FullMsgId cornerButtonsCurrentId() override; - bool cornerButtonsIgnoreVisibility() override; - std::optional cornerButtonsDownShown() override; - bool cornerButtonsUnreadMayBeShown() override; - bool cornerButtonsHas(CornerButtonType type) override; - -private: - void resizeEvent(QResizeEvent *e) override; - void paintEvent(QPaintEvent *e) override; - - void showAnimatedHook( - const Window::SectionSlideParams ¶ms) override; - void showFinishedHook() override; - void doSetInnerFocus() override; - void checkActivation() override; - - void onScroll(); - void updateInnerVisibleArea(); - void updateControlsGeometry(); - void updateAdaptiveLayout(); - void saveState(not_null memento); - void restoreState(not_null memento); - void showAtPosition( - Data::MessagePosition position, - FullMsgId originId = {}); - void showAtPosition( - Data::MessagePosition position, - FullMsgId originItemId, - const Window::SectionShow ¶ms); - - void setupOpenChatButton(); - void setupAboutHiddenAuthor(); - void setupTranslateBar(); - void setupShortcuts(); - - void confirmDeleteSelected(); - void confirmForwardSelected(); - void clearSelected(); - void recountChatWidth(); - void searchInSublist(); - - const not_null _sublist; - const not_null _history; - std::shared_ptr _theme; - QPointer _inner; - object_ptr _topBar; - object_ptr _topBarShadow; - - std::unique_ptr _translateBar; - int _translateBarHeight = 0; - - bool _skipScrollEvent = false; - std::unique_ptr _scroll; - std::unique_ptr _openChatButton; - std::unique_ptr _aboutHiddenAuthor; - std::unique_ptr _composeSearch; - - FullMsgId _lastShownAt; - CornerButtons _cornerButtons; - -}; - -class SublistMemento : public Window::SectionMemento { -public: - explicit SublistMemento(not_null sublist); - - object_ptr createWidget( - QWidget *parent, - not_null controller, - Window::Column column, - const QRect &geometry) override; - - [[nodiscard]] not_null getSublist() const { - return _sublist; - } - - [[nodiscard]] not_null list() { - return &_list; - } - -private: - const not_null _sublist; - ListMemento _list; - -}; - -} // namespace HistoryView diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.cpp b/Telegram/SourceFiles/info/media/info_media_buttons.cpp index c15b1c8f1a..9f53a17e2b 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.cpp +++ b/Telegram/SourceFiles/info/media/info_media_buttons.cpp @@ -12,10 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "data/data_channel.h" #include "data/data_saved_messages.h" +#include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_stories_ids.h" #include "data/data_user.h" -#include "history/view/history_view_sublist_section.h" +#include "history/view/history_view_chat_section.h" #include "history/history.h" #include "info/info_controller.h" #include "info/info_memento.h" @@ -270,9 +271,13 @@ not_null AddSavedSublistButton( }, tracker)->entity(); result->addClickHandler([=] { + using namespace HistoryView; + const auto sublist = peer->owner().savedMessages().sublist(peer); navigation->showSection( - std::make_shared( - peer->owner().savedMessages().sublist(peer))); + std::make_shared(ChatViewId{ + .history = sublist->parentHistory(), + .sublist = sublist, + })); }); return result; } diff --git a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp index dbd6557888..3afead749b 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp @@ -8,10 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/saved/info_saved_sublists_widget.h" // #include "data/data_saved_messages.h" +#include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_user.h" #include "dialogs/dialogs_inner_widget.h" -#include "history/view/history_view_sublist_section.h" +#include "history/view/history_view_chat_section.h" #include "info/media/info_media_buttons.h" #include "info/profile/info_profile_icon.h" #include "info/info_controller.h" @@ -63,10 +64,14 @@ SublistsWidget::SublistsWidget( _list->chosenRow() | rpl::start_with_next([=](Dialogs::ChosenRow row) { if (const auto sublist = row.key.sublist()) { using namespace Window; + using namespace HistoryView; auto params = SectionShow(SectionShow::Way::Forward); params.dropSameFromStack = true; controller->showSection( - std::make_shared(sublist), + std::make_shared(ChatViewId{ + .history = sublist->parentHistory(), + .sublist = sublist, + }), params); } }, _list->lifetime()); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index d3cbed09a0..3c33394661 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_web_page.h" #include "data/data_game.h" #include "data/data_peer_values.h" +#include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_changes.h" #include "data/data_folder.h" @@ -54,8 +55,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_widget.h" #include "history/history_item_helpers.h" // GetErrorForSending. #include "history/view/media/history_view_media.h" +#include "history/view/history_view_chat_section.h" #include "history/view/history_view_service_message.h" -#include "history/view/history_view_sublist_section.h" #include "lang/lang_keys.h" #include "lang/lang_cloud_manager.h" #include "inline_bots/inline_bot_layout_item.h" @@ -776,8 +777,12 @@ void MainWidget::searchMessages( } } else { if (const auto sublist = inChat.sublist()) { + using namespace HistoryView; controller()->showSection( - std::make_shared(sublist)); + std::make_shared(ChatViewId{ + .history = sublist->parentHistory(), + .sublist = sublist, + })); } else if (!tags.empty()) { inChat = controller()->session().data().history( controller()->session().user()); diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index d8950d56c5..2cb230d6c8 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -27,13 +27,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL //#include "history/view/reactions/history_view_reactions_button.h" #include "history/view/history_view_chat_section.h" #include "history/view/history_view_scheduled_section.h" -#include "history/view/history_view_sublist_section.h" #include "media/player/media_player_instance.h" #include "media/view/media_view_open_common.h" #include "data/stickers/data_custom_emoji.h" #include "data/data_document_resolver.h" #include "data/data_download_manager.h" #include "data/data_saved_messages.h" +#include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_file_origin.h" #include "data/data_folder.h" @@ -1343,8 +1343,12 @@ void SessionNavigation::showByInitialId( break; } case SeparateType::SavedSublist: + using namespace HistoryView; showSection( - std::make_shared(id.sublist()), + std::make_shared(ChatViewId{ + .history = id.sublist()->parentHistory(), + .sublist = id.sublist(), + }), instant); break; }