From 07528be1e6fb9518c70c42333d6e92928943b3f2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 16 Feb 2018 18:46:24 +0300 Subject: [PATCH] Support search in feed + scroll to search result. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/data/data_messages.h | 11 +- .../dialogs/dialogs_inner_widget.cpp | 125 ++++++++++-------- .../dialogs/dialogs_inner_widget.h | 3 +- Telegram/SourceFiles/dialogs/dialogs_key.h | 8 +- .../admin_log/history_admin_log_section.cpp | 5 +- .../history/feed/history_feed_section.cpp | 12 +- .../history/feed/history_feed_section.h | 7 +- .../SourceFiles/history/history_widget.cpp | 35 +++-- .../history/view/history_view_list_widget.cpp | 30 ++++- .../history/view/history_view_list_widget.h | 1 + .../feed/info_feed_channels_controllers.cpp | 4 + .../SourceFiles/info/info_wrap_widget.cpp | 33 +++-- Telegram/SourceFiles/mainwidget.cpp | 3 + .../SourceFiles/window/window_controller.cpp | 2 +- .../SourceFiles/window/window_peer_menu.cpp | 43 ++++++ 16 files changed, 225 insertions(+), 98 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 94bba6ca3..0d26daeeb 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1044,6 +1044,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_view_profile" = "View profile"; "lng_context_view_group" = "View group info"; "lng_context_view_channel" = "View channel info"; +"lng_context_view_feed_info" = "View feed info"; "lng_context_pin_to_top" = "Pin to top"; "lng_context_unpin_from_top" = "Unpin from top"; diff --git a/Telegram/SourceFiles/data/data_messages.h b/Telegram/SourceFiles/data/data_messages.h index 10c8ed935..8c511b0b8 100644 --- a/Telegram/SourceFiles/data/data_messages.h +++ b/Telegram/SourceFiles/data/data_messages.h @@ -76,19 +76,20 @@ struct MessagesRange { }; +constexpr auto MinDate = TimeId(0); constexpr auto MaxDate = std::numeric_limits::max(); constexpr auto MinMessagePosition = MessagePosition( - TimeId(0), - FullMsgId(0, 1)); + MinDate, + FullMsgId(NoChannel, 1)); constexpr auto MaxMessagePosition = MessagePosition( MaxDate, - FullMsgId(0, ServerMaxMsgId - 1)); + FullMsgId(NoChannel, ServerMaxMsgId - 1)); constexpr auto FullMessagesRange = MessagesRange( MinMessagePosition, MaxMessagePosition); constexpr auto UnreadMessagePosition = MessagePosition( - TimeId(0), - FullMsgId(0, 0));; + MinDate, + FullMsgId(NoChannel, ShowAtUnreadMsgId)); struct MessagesSlice { std::vector ids; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 96b637482..f5e4b5d90 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -109,7 +109,7 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro subscribe(App::histories().sendActionAnimationUpdated(), [this](const Histories::SendActionAnimationUpdate &update) { auto updateRect = Dialogs::Layout::RowPainter::sendActionAnimationRect(update.width, update.height, getFullWidth(), update.textUpdated); updateDialogRow( - Dialogs::RowDescriptor(update.history, MsgId(0)), + Dialogs::RowDescriptor(update.history, FullMsgId()), updateRect, UpdateRowSection::Default | UpdateRowSection::Filtered); }); @@ -145,7 +145,7 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro Auth().data().feedUpdated( ) | rpl::start_with_next([=](const Data::FeedUpdate &update) { updateDialogRow( - Dialogs::RowDescriptor(update.feed, MsgId(0)), + Dialogs::RowDescriptor(update.feed, FullMsgId()), QRect(0, 0, getFullWidth(), st::dialogsRowHeight)); }, lifetime()); @@ -340,7 +340,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO const auto row = _filterResults[from]; const auto key = row->key(); const auto active = (activeEntry.key == key) - && !activeEntry.msgId; + && !activeEntry.fullId; const auto selected = _menuKey ? (key == _menuKey) : (from == (isPressed() @@ -377,7 +377,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO for (; from < to; ++from) { const auto &result = _peerSearchResults[from]; const auto peer = result->peer; - const auto active = !activeEntry.msgId + const auto active = !activeEntry.fullId && activePeer && ((peer == activePeer) || (peer->migrateTo() == activePeer)); @@ -437,11 +437,10 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO const auto &result = _searchResults[from]; const auto item = result->item(); const auto peer = item->history()->peer; - const auto active = (peer == activePeer - && item->id == activeEntry.msgId) + const auto active = (item->fullId() == activeEntry.fullId) || (peer->migrateTo() - && peer->migrateTo() == activePeer - && item->id == -activeEntry.msgId); + && (peer->migrateTo()->bareId() == activeEntry.fullId.channel) + && (item->id == -activeEntry.fullId.msg)); const auto selected = (from == (isPressed() ? _searchedPressed : _searchedSelected)); @@ -1302,7 +1301,9 @@ void DialogsInner::repaintDialogRow( not_null history, MsgId messageId) { updateDialogRow( - Dialogs::RowDescriptor(history, messageId), + Dialogs::RowDescriptor( + history, + FullMsgId(history->channelId(), messageId)), QRect(0, 0, getFullWidth(), st::dialogsRowHeight)); } @@ -1325,11 +1326,13 @@ void DialogsInner::updateDialogRow( Dialogs::RowDescriptor row, QRect updateRect, UpdateRowSections sections) { - if (IsServerMsgId(-row.msgId)) { + if (IsServerMsgId(-row.fullId.msg)) { if (const auto peer = row.key.peer()) { if (const auto from = peer->migrateFrom()) { if (const auto migrated = App::historyLoaded(from)) { - row = Dialogs::RowDescriptor(migrated, -row.msgId); + row = Dialogs::RowDescriptor( + migrated, + FullMsgId(0, -row.fullId.msg)); } } } @@ -1382,18 +1385,15 @@ void DialogsInner::updateDialogRow( } if ((sections & UpdateRowSection::MessageSearch) && !_searchResults.empty()) { - if (const auto history = row.key.history()) { - const auto add = searchedOffset(); - auto index = 0; - for (const auto &result : _searchResults) { - auto item = result->item(); - if (item->history() == history - && item->id == row.msgId) { - updateRow(add + index * st::dialogsRowHeight); - break; - } - ++index; + const auto add = searchedOffset(); + auto index = 0; + for (const auto &result : _searchResults) { + auto item = result->item(); + if (item->fullId() == row.fullId) { + updateRow(add + index * st::dialogsRowHeight); + break; } + ++index; } } } @@ -2402,25 +2402,33 @@ DialogsInner::ChosenRow DialogsInner::computeChosenRow() const { if (_selected) { return { _selected->key(), - ShowAtUnreadMsgId + Data::UnreadMessagePosition }; } } else if (_state == State::Filtered) { if (base::in_range(_filteredSelected, 0, _filterResults.size())) { return { _filterResults[_filteredSelected]->key(), - ShowAtUnreadMsgId + Data::UnreadMessagePosition }; } else if (base::in_range(_peerSearchSelected, 0, _peerSearchResults.size())) { return { App::history(_peerSearchResults[_peerSearchSelected]->peer), - ShowAtUnreadMsgId + Data::UnreadMessagePosition }; } else if (base::in_range(_searchedSelected, 0, _searchResults.size())) { - return { - _searchResults[_searchedSelected]->item()->history(), - _searchResults[_searchedSelected]->item()->id - }; + const auto result = _searchResults[_searchedSelected].get(); + if (const auto feed = result->searchInChat().feed()) { + return { + feed, + result->item()->position() + }; + } else { + return { + result->item()->history(), + result->item()->position() + }; + } } } return ChosenRow(); @@ -2434,17 +2442,19 @@ bool DialogsInner::chooseRow() { } const auto chosen = computeChosenRow(); if (chosen.key) { - if (chosen.messageId > 0) { + if (IsServerMsgId(chosen.message.fullId.msg)) { saveRecentHashtags(_filter); } const auto openSearchResult = !App::main()->selectingPeer(true) && (_state == State::Filtered) && base::in_range(_filteredSelected, 0, _filterResults.size()); if (const auto history = chosen.key.history()) { - App::main()->choosePeer(history->peer->id, chosen.messageId); + App::main()->choosePeer( + history->peer->id, + chosen.message.fullId.msg); } else if (const auto feed = chosen.key.feed()) { _controller->showSection( - HistoryFeed::Memento(feed), + HistoryFeed::Memento(feed, chosen.message), Window::SectionShow::Way::ClearStack); } if (openSearchResult) { @@ -2518,57 +2528,57 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryBefore( if (const auto row = shownDialogs()->getRow(which.key)) { const auto i = shownDialogs()->cfind(row); if (i != shownDialogs()->cbegin()) { - return Dialogs::RowDescriptor((*(i - 1))->key(), - ShowAtUnreadMsgId); + return Dialogs::RowDescriptor( + (*(i - 1))->key(), + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } } return Dialogs::RowDescriptor(); } const auto whichHistory = which.key.history(); - const auto whichMsgId = which.msgId; + const auto whichFullId = which.fullId; if (!whichHistory) { return Dialogs::RowDescriptor(); } - if (whichMsgId && !_searchResults.empty()) { + if (whichFullId && !_searchResults.empty()) { for (auto b = _searchResults.cbegin(), i = b + 1, e = _searchResults.cend(); i != e; ++i) { - if ((*i)->item()->history() == whichHistory - && (*i)->item()->id == whichMsgId) { + if ((*i)->item()->fullId() == whichFullId) { const auto j = i - 1; return Dialogs::RowDescriptor( (*j)->item()->history(), - (*j)->item()->id); + (*j)->item()->fullId()); } } - if (_searchResults[0]->item()->history() == whichHistory - && _searchResults[0]->item()->id == whichMsgId) { + if (_searchResults[0]->item()->fullId() == whichFullId) { if (_peerSearchResults.empty()) { if (_filterResults.isEmpty()) { return Dialogs::RowDescriptor(); } return Dialogs::RowDescriptor( _filterResults.back()->key(), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } return Dialogs::RowDescriptor( App::history(_peerSearchResults.back()->peer), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } } - if (!_peerSearchResults.empty() && _peerSearchResults[0]->peer == whichHistory->peer) { + if (!_peerSearchResults.empty() + && _peerSearchResults[0]->peer == whichHistory->peer) { if (_filterResults.isEmpty()) { return Dialogs::RowDescriptor(); } return Dialogs::RowDescriptor( _filterResults.back()->key(), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } if (!_peerSearchResults.empty()) { for (auto b = _peerSearchResults.cbegin(), i = b + 1, e = _peerSearchResults.cend(); i != e; ++i) { if ((*i)->peer == whichHistory->peer) { return Dialogs::RowDescriptor( App::history((*(i - 1))->peer), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } } } @@ -2580,7 +2590,7 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryBefore( if ((*i)->key() == which.key) { return Dialogs::RowDescriptor( (*(i - 1))->key(), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } } return Dialogs::RowDescriptor(); @@ -2597,25 +2607,24 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryAfter( if (i != shownDialogs()->cend()) { return Dialogs::RowDescriptor( (*i)->key(), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } } return Dialogs::RowDescriptor(); } const auto whichHistory = which.key.history(); - const auto whichMsgId = which.msgId; + const auto whichFullId = which.fullId; if (!whichHistory) { return Dialogs::RowDescriptor(); } - if (whichMsgId) { + if (whichFullId) { for (auto i = _searchResults.cbegin(), e = _searchResults.cend(); i != e; ++i) { - if ((*i)->item()->history() == whichHistory - && (*i)->item()->id == whichMsgId) { + if ((*i)->item()->fullId() == whichFullId) { if (++i != e) { return Dialogs::RowDescriptor( (*i)->item()->history(), - (*i)->item()->id); + (*i)->item()->fullId()); } return Dialogs::RowDescriptor(); } @@ -2627,11 +2636,11 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryAfter( if (i != e) { return Dialogs::RowDescriptor( App::history((*i)->peer), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } else if (!_searchResults.empty()) { return Dialogs::RowDescriptor( _searchResults.front()->item()->history(), - _searchResults.front()->item()->id); + _searchResults.front()->item()->fullId()); } return Dialogs::RowDescriptor(); } @@ -2642,15 +2651,15 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryAfter( if (i != e) { return Dialogs::RowDescriptor( (*i)->key(), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } else if (!_peerSearchResults.empty()) { return Dialogs::RowDescriptor( App::history(_peerSearchResults.front()->peer), - ShowAtUnreadMsgId); + FullMsgId(NoChannel, ShowAtUnreadMsgId)); } else if (!_searchResults.empty()) { return Dialogs::RowDescriptor( _searchResults.front()->item()->history(), - _searchResults.front()->item()->id); + _searchResults.front()->item()->fullId()); } return Dialogs::RowDescriptor(); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index cf76f317a..67e8b8532 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_widget.h" #include "dialogs/dialogs_key.h" +#include "data/data_messages.h" #include "base/flags.h" namespace Dialogs { @@ -151,7 +152,7 @@ private: struct ChosenRow { Dialogs::Key key; - MsgId messageId = 0; + Data::MessagePosition message; }; bool switchImportantChats(); bool chooseHashtag(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_key.h b/Telegram/SourceFiles/dialogs/dialogs_key.h index 7a3f94af4..7d712a6ec 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_key.h +++ b/Telegram/SourceFiles/dialogs/dialogs_key.h @@ -76,16 +76,16 @@ private: struct RowDescriptor { RowDescriptor() = default; - RowDescriptor(Key key, MsgId msgId) : key(key), msgId(msgId) { + RowDescriptor(Key key, FullMsgId fullId) : key(key), fullId(fullId) { } Key key; - MsgId msgId = 0; + FullMsgId fullId; }; inline bool operator==(const RowDescriptor &a, const RowDescriptor &b) { - return (a.key == b.key) && (a.msgId == b.msgId); + return (a.key == b.key) && (a.fullId == b.fullId); } inline bool operator!=(const RowDescriptor &a, const RowDescriptor &b) { @@ -98,7 +98,7 @@ inline bool operator<(const RowDescriptor &a, const RowDescriptor &b) { } else if (a.key > b.key) { return false; } - return a.msgId < b.msgId; + return a.fullId < b.fullId; } inline bool operator>(const RowDescriptor &a, const RowDescriptor &b) { diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp index 49f00f0bf..b8022e32b 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp @@ -280,7 +280,10 @@ not_null Widget::channel() const { } Dialogs::RowDescriptor Widget::activeChat() const { - return { App::history(channel()), MsgId(0) }; + return { + App::history(channel()), + FullMsgId(channel()->bareId(), ShowAtUnreadMsgId) + }; } QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) { diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.cpp b/Telegram/SourceFiles/history/feed/history_feed_section.cpp index 5a718ee36..cfbda173b 100644 --- a/Telegram/SourceFiles/history/feed/history_feed_section.cpp +++ b/Telegram/SourceFiles/history/feed/history_feed_section.cpp @@ -40,9 +40,10 @@ namespace HistoryFeed { Memento::Memento( not_null feed, - Data::MessagePosition aroundPosition) + Data::MessagePosition position) : _feed(feed) -, _list(std::make_unique(aroundPosition)) { +, _position(position) +, _list(std::make_unique(position)) { } Memento::~Memento() = default; @@ -153,6 +154,7 @@ void Widget::setupScrollDownButton() { } void Widget::scrollDownClicked() { + _currentMessageId = Data::MaxMessagePosition.fullId; showAtPosition(Data::MaxMessagePosition); } @@ -246,7 +248,7 @@ void Widget::checkForSingleChannelFeed() { } Dialogs::RowDescriptor Widget::activeChat() const { - return Dialogs::RowDescriptor(_feed, MsgId(0)); + return Dialogs::RowDescriptor(_feed, _currentMessageId); } void Widget::updateAdaptiveLayout() { @@ -444,6 +446,10 @@ void Widget::restoreState(not_null memento) { } _undefinedAroundPosition = !list->aroundPosition(); _inner->restoreState(memento->list()); + if (const auto position = memento->position()) { + _currentMessageId = position.fullId; + showAtPosition(position); + } } void Widget::resizeEvent(QResizeEvent *e) { diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.h b/Telegram/SourceFiles/history/feed/history_feed_section.h index ea119c9e6..8210d345f 100644 --- a/Telegram/SourceFiles/history/feed/history_feed_section.h +++ b/Telegram/SourceFiles/history/feed/history_feed_section.h @@ -128,6 +128,7 @@ private: std::unique_ptr _emptyTextItem; std::unique_ptr _emptyTextView; + FullMsgId _currentMessageId; base::optional _nextAnimatedScrollPosition; int _nextAnimatedScrollDelta = 0; @@ -142,7 +143,7 @@ class Memento : public Window::SectionMemento { public: explicit Memento( not_null feed, - Data::MessagePosition aroundPosition = Data::UnreadMessagePosition); + Data::MessagePosition position = Data::UnreadMessagePosition); ~Memento(); object_ptr createWidget( @@ -154,12 +155,16 @@ public: not_null feed() const { return _feed; } + Data::MessagePosition position() const { + return _position; + } not_null list() const { return _list.get(); } private: not_null _feed; + Data::MessagePosition _position; std::unique_ptr _list; }; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 7418d2563..f0f151f16 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_drag_area.h" #include "history/history_inner_widget.h" #include "history/history_item_components.h" +#include "history/feed/history_feed_section.h" #include "history/view/history_view_service_message.h" #include "history/view/history_view_element.h" #include "profile/profile_block_group_members.h" @@ -1441,12 +1442,19 @@ bool HistoryWidget::cmd_next_chat() { return false; } const auto next = App::main()->chatListEntryAfter( - Dialogs::RowDescriptor(_history, std::max(_showAtMsgId, 0))); + Dialogs::RowDescriptor( + _history, + FullMsgId(_history->channelId(), std::max(_showAtMsgId, 0)))); if (const auto history = next.key.history()) { - Ui::showPeerHistory(history, next.msgId); + Ui::showPeerHistory(history, next.fullId.msg); return true; + } else if (const auto feed = next.key.feed()) { + if (const auto item = App::histItemById(next.fullId)) { + controller()->showSection(HistoryFeed::Memento(feed, item->position())); + } else { + controller()->showSection(HistoryFeed::Memento(feed)); + } } - // #TODO feeds show return false; } @@ -1455,12 +1463,19 @@ bool HistoryWidget::cmd_previous_chat() { return false; } const auto next = App::main()->chatListEntryBefore( - Dialogs::RowDescriptor(_history, std::max(_showAtMsgId, 0))); + Dialogs::RowDescriptor( + _history, + FullMsgId(_history->channelId(), std::max(_showAtMsgId, 0)))); if (const auto history = next.key.history()) { - Ui::showPeerHistory(history, next.msgId); + Ui::showPeerHistory(history, next.fullId.msg); return true; + } else if (const auto feed = next.key.feed()) { + if (const auto item = App::histItemById(next.fullId)) { + controller()->showSection(HistoryFeed::Memento(feed, item->position())); + } else { + controller()->showSection(HistoryFeed::Memento(feed)); + } } - // #TODO feeds show return false; } @@ -1840,7 +1855,9 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re updateOverStates(mapFromGlobal(QCursor::pos())); if (_history) { - controller()->setActiveChatEntry({ _history, _showAtMsgId }); + controller()->setActiveChatEntry({ + _history, + FullMsgId(_history->channelId(), _showAtMsgId) }); } update(); @@ -3046,7 +3063,9 @@ void HistoryWidget::setMsgId(MsgId showAtMsgId) { auto wasMsgId = _showAtMsgId; _showAtMsgId = showAtMsgId; if (_history) { - controller()->setActiveChatEntry({ _history, _showAtMsgId }); + controller()->setActiveChatEntry({ + _history, + FullMsgId(_history->channelId(), _showAtMsgId) }); } } } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index ebe2e1fd4..569993403 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -334,9 +334,31 @@ base::optional ListWidget::scrollTopForPosition( return height(); } return base::none; + } else if (_items.empty() + || isBelowPosition(position) + || isAbovePosition(position)) { + return base::none; } - // #TODO showAtPosition - return base::none; + const auto index = findNearestItem(position); + const auto view = _items[index]; + return scrollTopForView(_items[index]); +} + +base::optional ListWidget::scrollTopForView( + not_null view) const { + if (view->isHiddenByGroup()) { + if (const auto group = Auth().data().groups().find(view->data())) { + if (const auto leader = viewForItem(group->items.back())) { + if (!leader->isHiddenByGroup()) { + return scrollTopForView(leader); + } + } + } + } + const auto top = view->y(); + const auto height = view->height(); + const auto available = _visibleBottom - _visibleTop; + return top - std::max((available - height) / 2, 0); } void ListWidget::animatedScrollTo( @@ -382,14 +404,14 @@ void ListWidget::scrollToAnimationCallback(FullMsgId attachToId) { } bool ListWidget::isAbovePosition(Data::MessagePosition position) const { - if (_items.empty()) { + if (_items.empty() || loadedAtBottom()) { return false; } return _items.back()->data()->position() < position; } bool ListWidget::isBelowPosition(Data::MessagePosition position) const { - if (_items.empty()) { + if (_items.empty() || loadedAtTop()) { return false; } return _items.front()->data()->position() > position; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index b9a908e8a..5aad08c92 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -137,6 +137,7 @@ public: void restoreState(not_null memento); base::optional scrollTopForPosition( Data::MessagePosition position) const; + base::optional scrollTopForView(not_null view) const; enum class AnimatedScroll { Full, Part, diff --git a/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp b/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp index 86dd43c28..d923fccbd 100644 --- a/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp +++ b/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/popup_menu.h" #include "auth_session.h" #include "mainwidget.h" +#include "apiwrap.h" #include "styles/style_widgets.h" #include "styles/style_info.h" #include "styles/style_boxes.h" @@ -88,6 +89,9 @@ ChannelsController::ChannelsController(not_null controller) : PeerListController() , _controller(controller) , _feed(_controller->key().feed()) { + if (!_feed->channelsLoaded()) { + Auth().api().requestFeedChannels(_feed); + } _controller->setSearchEnabledByContent(false); } diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index 0d5f7cfc8..c4abd4c82 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -199,9 +199,9 @@ Key WrapWidget::key() const { Dialogs::RowDescriptor WrapWidget::activeChat() const { if (const auto peer = key().peer()) { - return Dialogs::RowDescriptor(App::history(peer), MsgId(0)); + return Dialogs::RowDescriptor(App::history(peer), FullMsgId()); } else if (const auto feed = key().feed()) { - return Dialogs::RowDescriptor(feed, MsgId(0)); + return Dialogs::RowDescriptor(feed, FullMsgId()); } Unexpected("Owner in WrapWidget::activeChat()."); } @@ -497,18 +497,27 @@ void WrapWidget::showProfileMenu() { }); _topBarMenuToggle->installEventFilter(_topBarMenu.get()); - // #TODO feeds menu - const auto peer = key().peer(); - if (!peer) { + const auto addAction = [=]( + const QString &text, + base::lambda callback) { + return _topBarMenu->addAction(text, std::move(callback)); + }; + if (const auto peer = key().peer()) { + Window::FillPeerMenu( + _controller->parentController(), + peer, + addAction, + Window::PeerMenuSource::Profile); + } else if (const auto feed = key().feed()) { + Window::FillFeedMenu( + _controller->parentController(), + feed, + addAction, + Window::PeerMenuSource::Profile); + } else { + _topBarMenu = nullptr; return; } - Window::FillPeerMenu( - _controller->parentController(), - peer, - [this](const QString &text, base::lambda callback) { - return _topBarMenu->addAction(text, std::move(callback)); - }, - Window::PeerMenuSource::Profile); auto position = (wrap() == Wrap::Layer) ? st::infoLayerTopBarMenuPosition : st::infoTopBarMenuPosition; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index ac46c8e7a..c0e5497df 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -2184,6 +2184,9 @@ void MainWidget::showSection( if (_mainSection && _mainSection->showInternal( &memento, params)) { + if (const auto entry = _mainSection->activeChat(); entry.key) { + _controller->setActiveChatEntry(entry); + } return; // // Now third section handles only its own showSection() requests. diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 31994a994..065e8887b 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -41,7 +41,7 @@ void Controller::setActiveChatEntry(Dialogs::RowDescriptor row) { } void Controller::setActiveChatEntry(Dialogs::Key key) { - setActiveChatEntry({ key, MsgId(0) }); + setActiveChatEntry({ key, FullMsgId() }); } Dialogs::RowDescriptor Controller::activeChatEntryCurrent() const { diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index c335ec1df..23ebd9c8a 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -25,6 +25,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_boxes.h" #include "history/history.h" #include "window/window_controller.h" +#include "info/info_memento.h" +#include "info/info_controller.h" #include "info/feed/info_feed_channels_controllers.h" #include "data/data_session.h" #include "data/data_feed.h" @@ -69,7 +71,10 @@ public: void fill(); private: + bool showInfo(); void addPinToggle(); + void addInfo(); + void addSearch(); void addNotifications(); not_null _controller; @@ -411,7 +416,28 @@ void FeedFiller::fill() { if (_source == PeerMenuSource::ChatsList) { addPinToggle(); } + if (showInfo()) { + addInfo(); + } addNotifications(); + if (_source == PeerMenuSource::ChatsList) { + addSearch(); + } +} + +bool FeedFiller::showInfo() { + if (_source == PeerMenuSource::Profile) { + return false; + } else if (_controller->activeChatCurrent().feed() != _feed) { + return true; + } else if (!Adaptive::ThreeColumn()) { + return true; + } else if ( + !Auth().settings().thirdSectionInfoEnabled() && + !Auth().settings().tabbedReplacedWithInfo()) { + return true; + } + return false; } void FeedFiller::addPinToggle() { @@ -427,6 +453,16 @@ void FeedFiller::addPinToggle() { }); } +void FeedFiller::addInfo() { + auto controller = _controller; + auto feed = _feed; + _addAction(lang(lng_context_view_feed_info), [=] { + controller->showSection(Info::Memento( + feed, + Info::Section(Info::Section::Type::Profile))); + }); +} + void FeedFiller::addNotifications() { const auto feed = _feed; _addAction(lang(lng_feed_notifications), [=] { @@ -434,6 +470,13 @@ void FeedFiller::addNotifications() { }); } +void FeedFiller::addSearch() { + const auto feed = _feed; + _addAction(lang(lng_profile_search_messages), [=] { + App::main()->searchInChat(feed); + }); +} + } // namespace void PeerMenuDeleteContact(not_null user) {