Support search in feed + scroll to search result.

This commit is contained in:
John Preston 2018-02-16 18:46:24 +03:00
parent bc171f625a
commit 07528be1e6
16 changed files with 225 additions and 98 deletions

View File

@ -1044,6 +1044,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_view_profile" = "View profile"; "lng_context_view_profile" = "View profile";
"lng_context_view_group" = "View group info"; "lng_context_view_group" = "View group info";
"lng_context_view_channel" = "View channel 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_pin_to_top" = "Pin to top";
"lng_context_unpin_from_top" = "Unpin from top"; "lng_context_unpin_from_top" = "Unpin from top";

View File

@ -76,19 +76,20 @@ struct MessagesRange {
}; };
constexpr auto MinDate = TimeId(0);
constexpr auto MaxDate = std::numeric_limits<TimeId>::max(); constexpr auto MaxDate = std::numeric_limits<TimeId>::max();
constexpr auto MinMessagePosition = MessagePosition( constexpr auto MinMessagePosition = MessagePosition(
TimeId(0), MinDate,
FullMsgId(0, 1)); FullMsgId(NoChannel, 1));
constexpr auto MaxMessagePosition = MessagePosition( constexpr auto MaxMessagePosition = MessagePosition(
MaxDate, MaxDate,
FullMsgId(0, ServerMaxMsgId - 1)); FullMsgId(NoChannel, ServerMaxMsgId - 1));
constexpr auto FullMessagesRange = MessagesRange( constexpr auto FullMessagesRange = MessagesRange(
MinMessagePosition, MinMessagePosition,
MaxMessagePosition); MaxMessagePosition);
constexpr auto UnreadMessagePosition = MessagePosition( constexpr auto UnreadMessagePosition = MessagePosition(
TimeId(0), MinDate,
FullMsgId(0, 0));; FullMsgId(NoChannel, ShowAtUnreadMsgId));
struct MessagesSlice { struct MessagesSlice {
std::vector<FullMsgId> ids; std::vector<FullMsgId> ids;

View File

@ -109,7 +109,7 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> contro
subscribe(App::histories().sendActionAnimationUpdated(), [this](const Histories::SendActionAnimationUpdate &update) { subscribe(App::histories().sendActionAnimationUpdated(), [this](const Histories::SendActionAnimationUpdate &update) {
auto updateRect = Dialogs::Layout::RowPainter::sendActionAnimationRect(update.width, update.height, getFullWidth(), update.textUpdated); auto updateRect = Dialogs::Layout::RowPainter::sendActionAnimationRect(update.width, update.height, getFullWidth(), update.textUpdated);
updateDialogRow( updateDialogRow(
Dialogs::RowDescriptor(update.history, MsgId(0)), Dialogs::RowDescriptor(update.history, FullMsgId()),
updateRect, updateRect,
UpdateRowSection::Default | UpdateRowSection::Filtered); UpdateRowSection::Default | UpdateRowSection::Filtered);
}); });
@ -145,7 +145,7 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> contro
Auth().data().feedUpdated( Auth().data().feedUpdated(
) | rpl::start_with_next([=](const Data::FeedUpdate &update) { ) | rpl::start_with_next([=](const Data::FeedUpdate &update) {
updateDialogRow( updateDialogRow(
Dialogs::RowDescriptor(update.feed, MsgId(0)), Dialogs::RowDescriptor(update.feed, FullMsgId()),
QRect(0, 0, getFullWidth(), st::dialogsRowHeight)); QRect(0, 0, getFullWidth(), st::dialogsRowHeight));
}, lifetime()); }, lifetime());
@ -340,7 +340,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
const auto row = _filterResults[from]; const auto row = _filterResults[from];
const auto key = row->key(); const auto key = row->key();
const auto active = (activeEntry.key == key) const auto active = (activeEntry.key == key)
&& !activeEntry.msgId; && !activeEntry.fullId;
const auto selected = _menuKey const auto selected = _menuKey
? (key == _menuKey) ? (key == _menuKey)
: (from == (isPressed() : (from == (isPressed()
@ -377,7 +377,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
for (; from < to; ++from) { for (; from < to; ++from) {
const auto &result = _peerSearchResults[from]; const auto &result = _peerSearchResults[from];
const auto peer = result->peer; const auto peer = result->peer;
const auto active = !activeEntry.msgId const auto active = !activeEntry.fullId
&& activePeer && activePeer
&& ((peer == activePeer) && ((peer == activePeer)
|| (peer->migrateTo() == activePeer)); || (peer->migrateTo() == activePeer));
@ -437,11 +437,10 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
const auto &result = _searchResults[from]; const auto &result = _searchResults[from];
const auto item = result->item(); const auto item = result->item();
const auto peer = item->history()->peer; const auto peer = item->history()->peer;
const auto active = (peer == activePeer const auto active = (item->fullId() == activeEntry.fullId)
&& item->id == activeEntry.msgId)
|| (peer->migrateTo() || (peer->migrateTo()
&& peer->migrateTo() == activePeer && (peer->migrateTo()->bareId() == activeEntry.fullId.channel)
&& item->id == -activeEntry.msgId); && (item->id == -activeEntry.fullId.msg));
const auto selected = (from == (isPressed() const auto selected = (from == (isPressed()
? _searchedPressed ? _searchedPressed
: _searchedSelected)); : _searchedSelected));
@ -1302,7 +1301,9 @@ void DialogsInner::repaintDialogRow(
not_null<History*> history, not_null<History*> history,
MsgId messageId) { MsgId messageId) {
updateDialogRow( updateDialogRow(
Dialogs::RowDescriptor(history, messageId), Dialogs::RowDescriptor(
history,
FullMsgId(history->channelId(), messageId)),
QRect(0, 0, getFullWidth(), st::dialogsRowHeight)); QRect(0, 0, getFullWidth(), st::dialogsRowHeight));
} }
@ -1325,11 +1326,13 @@ void DialogsInner::updateDialogRow(
Dialogs::RowDescriptor row, Dialogs::RowDescriptor row,
QRect updateRect, QRect updateRect,
UpdateRowSections sections) { UpdateRowSections sections) {
if (IsServerMsgId(-row.msgId)) { if (IsServerMsgId(-row.fullId.msg)) {
if (const auto peer = row.key.peer()) { if (const auto peer = row.key.peer()) {
if (const auto from = peer->migrateFrom()) { if (const auto from = peer->migrateFrom()) {
if (const auto migrated = App::historyLoaded(from)) { 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) if ((sections & UpdateRowSection::MessageSearch)
&& !_searchResults.empty()) { && !_searchResults.empty()) {
if (const auto history = row.key.history()) { const auto add = searchedOffset();
const auto add = searchedOffset(); auto index = 0;
auto index = 0; for (const auto &result : _searchResults) {
for (const auto &result : _searchResults) { auto item = result->item();
auto item = result->item(); if (item->fullId() == row.fullId) {
if (item->history() == history updateRow(add + index * st::dialogsRowHeight);
&& item->id == row.msgId) { break;
updateRow(add + index * st::dialogsRowHeight);
break;
}
++index;
} }
++index;
} }
} }
} }
@ -2402,25 +2402,33 @@ DialogsInner::ChosenRow DialogsInner::computeChosenRow() const {
if (_selected) { if (_selected) {
return { return {
_selected->key(), _selected->key(),
ShowAtUnreadMsgId Data::UnreadMessagePosition
}; };
} }
} else if (_state == State::Filtered) { } else if (_state == State::Filtered) {
if (base::in_range(_filteredSelected, 0, _filterResults.size())) { if (base::in_range(_filteredSelected, 0, _filterResults.size())) {
return { return {
_filterResults[_filteredSelected]->key(), _filterResults[_filteredSelected]->key(),
ShowAtUnreadMsgId Data::UnreadMessagePosition
}; };
} else if (base::in_range(_peerSearchSelected, 0, _peerSearchResults.size())) { } else if (base::in_range(_peerSearchSelected, 0, _peerSearchResults.size())) {
return { return {
App::history(_peerSearchResults[_peerSearchSelected]->peer), App::history(_peerSearchResults[_peerSearchSelected]->peer),
ShowAtUnreadMsgId Data::UnreadMessagePosition
}; };
} else if (base::in_range(_searchedSelected, 0, _searchResults.size())) { } else if (base::in_range(_searchedSelected, 0, _searchResults.size())) {
return { const auto result = _searchResults[_searchedSelected].get();
_searchResults[_searchedSelected]->item()->history(), if (const auto feed = result->searchInChat().feed()) {
_searchResults[_searchedSelected]->item()->id return {
}; feed,
result->item()->position()
};
} else {
return {
result->item()->history(),
result->item()->position()
};
}
} }
} }
return ChosenRow(); return ChosenRow();
@ -2434,17 +2442,19 @@ bool DialogsInner::chooseRow() {
} }
const auto chosen = computeChosenRow(); const auto chosen = computeChosenRow();
if (chosen.key) { if (chosen.key) {
if (chosen.messageId > 0) { if (IsServerMsgId(chosen.message.fullId.msg)) {
saveRecentHashtags(_filter); saveRecentHashtags(_filter);
} }
const auto openSearchResult = !App::main()->selectingPeer(true) const auto openSearchResult = !App::main()->selectingPeer(true)
&& (_state == State::Filtered) && (_state == State::Filtered)
&& base::in_range(_filteredSelected, 0, _filterResults.size()); && base::in_range(_filteredSelected, 0, _filterResults.size());
if (const auto history = chosen.key.history()) { 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()) { } else if (const auto feed = chosen.key.feed()) {
_controller->showSection( _controller->showSection(
HistoryFeed::Memento(feed), HistoryFeed::Memento(feed, chosen.message),
Window::SectionShow::Way::ClearStack); Window::SectionShow::Way::ClearStack);
} }
if (openSearchResult) { if (openSearchResult) {
@ -2518,57 +2528,57 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryBefore(
if (const auto row = shownDialogs()->getRow(which.key)) { if (const auto row = shownDialogs()->getRow(which.key)) {
const auto i = shownDialogs()->cfind(row); const auto i = shownDialogs()->cfind(row);
if (i != shownDialogs()->cbegin()) { if (i != shownDialogs()->cbegin()) {
return Dialogs::RowDescriptor((*(i - 1))->key(), return Dialogs::RowDescriptor(
ShowAtUnreadMsgId); (*(i - 1))->key(),
FullMsgId(NoChannel, ShowAtUnreadMsgId));
} }
} }
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
const auto whichHistory = which.key.history(); const auto whichHistory = which.key.history();
const auto whichMsgId = which.msgId; const auto whichFullId = which.fullId;
if (!whichHistory) { if (!whichHistory) {
return Dialogs::RowDescriptor(); 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) { for (auto b = _searchResults.cbegin(), i = b + 1, e = _searchResults.cend(); i != e; ++i) {
if ((*i)->item()->history() == whichHistory if ((*i)->item()->fullId() == whichFullId) {
&& (*i)->item()->id == whichMsgId) {
const auto j = i - 1; const auto j = i - 1;
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
(*j)->item()->history(), (*j)->item()->history(),
(*j)->item()->id); (*j)->item()->fullId());
} }
} }
if (_searchResults[0]->item()->history() == whichHistory if (_searchResults[0]->item()->fullId() == whichFullId) {
&& _searchResults[0]->item()->id == whichMsgId) {
if (_peerSearchResults.empty()) { if (_peerSearchResults.empty()) {
if (_filterResults.isEmpty()) { if (_filterResults.isEmpty()) {
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
_filterResults.back()->key(), _filterResults.back()->key(),
ShowAtUnreadMsgId); FullMsgId(NoChannel, ShowAtUnreadMsgId));
} }
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
App::history(_peerSearchResults.back()->peer), 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()) { if (_filterResults.isEmpty()) {
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
_filterResults.back()->key(), _filterResults.back()->key(),
ShowAtUnreadMsgId); FullMsgId(NoChannel, ShowAtUnreadMsgId));
} }
if (!_peerSearchResults.empty()) { if (!_peerSearchResults.empty()) {
for (auto b = _peerSearchResults.cbegin(), i = b + 1, e = _peerSearchResults.cend(); i != e; ++i) { for (auto b = _peerSearchResults.cbegin(), i = b + 1, e = _peerSearchResults.cend(); i != e; ++i) {
if ((*i)->peer == whichHistory->peer) { if ((*i)->peer == whichHistory->peer) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
App::history((*(i - 1))->peer), App::history((*(i - 1))->peer),
ShowAtUnreadMsgId); FullMsgId(NoChannel, ShowAtUnreadMsgId));
} }
} }
} }
@ -2580,7 +2590,7 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryBefore(
if ((*i)->key() == which.key) { if ((*i)->key() == which.key) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
(*(i - 1))->key(), (*(i - 1))->key(),
ShowAtUnreadMsgId); FullMsgId(NoChannel, ShowAtUnreadMsgId));
} }
} }
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
@ -2597,25 +2607,24 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryAfter(
if (i != shownDialogs()->cend()) { if (i != shownDialogs()->cend()) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
(*i)->key(), (*i)->key(),
ShowAtUnreadMsgId); FullMsgId(NoChannel, ShowAtUnreadMsgId));
} }
} }
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
const auto whichHistory = which.key.history(); const auto whichHistory = which.key.history();
const auto whichMsgId = which.msgId; const auto whichFullId = which.fullId;
if (!whichHistory) { if (!whichHistory) {
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
if (whichMsgId) { if (whichFullId) {
for (auto i = _searchResults.cbegin(), e = _searchResults.cend(); i != e; ++i) { for (auto i = _searchResults.cbegin(), e = _searchResults.cend(); i != e; ++i) {
if ((*i)->item()->history() == whichHistory if ((*i)->item()->fullId() == whichFullId) {
&& (*i)->item()->id == whichMsgId) {
if (++i != e) { if (++i != e) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
(*i)->item()->history(), (*i)->item()->history(),
(*i)->item()->id); (*i)->item()->fullId());
} }
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
@ -2627,11 +2636,11 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryAfter(
if (i != e) { if (i != e) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
App::history((*i)->peer), App::history((*i)->peer),
ShowAtUnreadMsgId); FullMsgId(NoChannel, ShowAtUnreadMsgId));
} else if (!_searchResults.empty()) { } else if (!_searchResults.empty()) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
_searchResults.front()->item()->history(), _searchResults.front()->item()->history(),
_searchResults.front()->item()->id); _searchResults.front()->item()->fullId());
} }
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
@ -2642,15 +2651,15 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryAfter(
if (i != e) { if (i != e) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
(*i)->key(), (*i)->key(),
ShowAtUnreadMsgId); FullMsgId(NoChannel, ShowAtUnreadMsgId));
} else if (!_peerSearchResults.empty()) { } else if (!_peerSearchResults.empty()) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
App::history(_peerSearchResults.front()->peer), App::history(_peerSearchResults.front()->peer),
ShowAtUnreadMsgId); FullMsgId(NoChannel, ShowAtUnreadMsgId));
} else if (!_searchResults.empty()) { } else if (!_searchResults.empty()) {
return Dialogs::RowDescriptor( return Dialogs::RowDescriptor(
_searchResults.front()->item()->history(), _searchResults.front()->item()->history(),
_searchResults.front()->item()->id); _searchResults.front()->item()->fullId());
} }
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/dialogs_widget.h" #include "dialogs/dialogs_widget.h"
#include "dialogs/dialogs_key.h" #include "dialogs/dialogs_key.h"
#include "data/data_messages.h"
#include "base/flags.h" #include "base/flags.h"
namespace Dialogs { namespace Dialogs {
@ -151,7 +152,7 @@ private:
struct ChosenRow { struct ChosenRow {
Dialogs::Key key; Dialogs::Key key;
MsgId messageId = 0; Data::MessagePosition message;
}; };
bool switchImportantChats(); bool switchImportantChats();
bool chooseHashtag(); bool chooseHashtag();

View File

@ -76,16 +76,16 @@ private:
struct RowDescriptor { struct RowDescriptor {
RowDescriptor() = default; RowDescriptor() = default;
RowDescriptor(Key key, MsgId msgId) : key(key), msgId(msgId) { RowDescriptor(Key key, FullMsgId fullId) : key(key), fullId(fullId) {
} }
Key key; Key key;
MsgId msgId = 0; FullMsgId fullId;
}; };
inline bool operator==(const RowDescriptor &a, const RowDescriptor &b) { 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) { 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) { } else if (a.key > b.key) {
return false; return false;
} }
return a.msgId < b.msgId; return a.fullId < b.fullId;
} }
inline bool operator>(const RowDescriptor &a, const RowDescriptor &b) { inline bool operator>(const RowDescriptor &a, const RowDescriptor &b) {

View File

@ -280,7 +280,10 @@ not_null<ChannelData*> Widget::channel() const {
} }
Dialogs::RowDescriptor Widget::activeChat() 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 &params) { QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams &params) {

View File

@ -40,9 +40,10 @@ namespace HistoryFeed {
Memento::Memento( Memento::Memento(
not_null<Data::Feed*> feed, not_null<Data::Feed*> feed,
Data::MessagePosition aroundPosition) Data::MessagePosition position)
: _feed(feed) : _feed(feed)
, _list(std::make_unique<HistoryView::ListMemento>(aroundPosition)) { , _position(position)
, _list(std::make_unique<HistoryView::ListMemento>(position)) {
} }
Memento::~Memento() = default; Memento::~Memento() = default;
@ -153,6 +154,7 @@ void Widget::setupScrollDownButton() {
} }
void Widget::scrollDownClicked() { void Widget::scrollDownClicked() {
_currentMessageId = Data::MaxMessagePosition.fullId;
showAtPosition(Data::MaxMessagePosition); showAtPosition(Data::MaxMessagePosition);
} }
@ -246,7 +248,7 @@ void Widget::checkForSingleChannelFeed() {
} }
Dialogs::RowDescriptor Widget::activeChat() const { Dialogs::RowDescriptor Widget::activeChat() const {
return Dialogs::RowDescriptor(_feed, MsgId(0)); return Dialogs::RowDescriptor(_feed, _currentMessageId);
} }
void Widget::updateAdaptiveLayout() { void Widget::updateAdaptiveLayout() {
@ -444,6 +446,10 @@ void Widget::restoreState(not_null<Memento*> memento) {
} }
_undefinedAroundPosition = !list->aroundPosition(); _undefinedAroundPosition = !list->aroundPosition();
_inner->restoreState(memento->list()); _inner->restoreState(memento->list());
if (const auto position = memento->position()) {
_currentMessageId = position.fullId;
showAtPosition(position);
}
} }
void Widget::resizeEvent(QResizeEvent *e) { void Widget::resizeEvent(QResizeEvent *e) {

View File

@ -128,6 +128,7 @@ private:
std::unique_ptr<HistoryItem, HistoryItem::Destroyer> _emptyTextItem; std::unique_ptr<HistoryItem, HistoryItem::Destroyer> _emptyTextItem;
std::unique_ptr<HistoryView::Element> _emptyTextView; std::unique_ptr<HistoryView::Element> _emptyTextView;
FullMsgId _currentMessageId;
base::optional<Data::MessagePosition> _nextAnimatedScrollPosition; base::optional<Data::MessagePosition> _nextAnimatedScrollPosition;
int _nextAnimatedScrollDelta = 0; int _nextAnimatedScrollDelta = 0;
@ -142,7 +143,7 @@ class Memento : public Window::SectionMemento {
public: public:
explicit Memento( explicit Memento(
not_null<Data::Feed*> feed, not_null<Data::Feed*> feed,
Data::MessagePosition aroundPosition = Data::UnreadMessagePosition); Data::MessagePosition position = Data::UnreadMessagePosition);
~Memento(); ~Memento();
object_ptr<Window::SectionWidget> createWidget( object_ptr<Window::SectionWidget> createWidget(
@ -154,12 +155,16 @@ public:
not_null<Data::Feed*> feed() const { not_null<Data::Feed*> feed() const {
return _feed; return _feed;
} }
Data::MessagePosition position() const {
return _position;
}
not_null<HistoryView::ListMemento*> list() const { not_null<HistoryView::ListMemento*> list() const {
return _list.get(); return _list.get();
} }
private: private:
not_null<Data::Feed*> _feed; not_null<Data::Feed*> _feed;
Data::MessagePosition _position;
std::unique_ptr<HistoryView::ListMemento> _list; std::unique_ptr<HistoryView::ListMemento> _list;
}; };

View File

@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_drag_area.h" #include "history/history_drag_area.h"
#include "history/history_inner_widget.h" #include "history/history_inner_widget.h"
#include "history/history_item_components.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_service_message.h"
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
#include "profile/profile_block_group_members.h" #include "profile/profile_block_group_members.h"
@ -1441,12 +1442,19 @@ bool HistoryWidget::cmd_next_chat() {
return false; return false;
} }
const auto next = App::main()->chatListEntryAfter( 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()) { if (const auto history = next.key.history()) {
Ui::showPeerHistory(history, next.msgId); Ui::showPeerHistory(history, next.fullId.msg);
return true; 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; return false;
} }
@ -1455,12 +1463,19 @@ bool HistoryWidget::cmd_previous_chat() {
return false; return false;
} }
const auto next = App::main()->chatListEntryBefore( 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()) { if (const auto history = next.key.history()) {
Ui::showPeerHistory(history, next.msgId); Ui::showPeerHistory(history, next.fullId.msg);
return true; 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; return false;
} }
@ -1840,7 +1855,9 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
updateOverStates(mapFromGlobal(QCursor::pos())); updateOverStates(mapFromGlobal(QCursor::pos()));
if (_history) { if (_history) {
controller()->setActiveChatEntry({ _history, _showAtMsgId }); controller()->setActiveChatEntry({
_history,
FullMsgId(_history->channelId(), _showAtMsgId) });
} }
update(); update();
@ -3046,7 +3063,9 @@ void HistoryWidget::setMsgId(MsgId showAtMsgId) {
auto wasMsgId = _showAtMsgId; auto wasMsgId = _showAtMsgId;
_showAtMsgId = showAtMsgId; _showAtMsgId = showAtMsgId;
if (_history) { if (_history) {
controller()->setActiveChatEntry({ _history, _showAtMsgId }); controller()->setActiveChatEntry({
_history,
FullMsgId(_history->channelId(), _showAtMsgId) });
} }
} }
} }

View File

@ -334,9 +334,31 @@ base::optional<int> ListWidget::scrollTopForPosition(
return height(); return height();
} }
return base::none; return base::none;
} else if (_items.empty()
|| isBelowPosition(position)
|| isAbovePosition(position)) {
return base::none;
} }
// #TODO showAtPosition const auto index = findNearestItem(position);
return base::none; const auto view = _items[index];
return scrollTopForView(_items[index]);
}
base::optional<int> ListWidget::scrollTopForView(
not_null<Element*> 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( void ListWidget::animatedScrollTo(
@ -382,14 +404,14 @@ void ListWidget::scrollToAnimationCallback(FullMsgId attachToId) {
} }
bool ListWidget::isAbovePosition(Data::MessagePosition position) const { bool ListWidget::isAbovePosition(Data::MessagePosition position) const {
if (_items.empty()) { if (_items.empty() || loadedAtBottom()) {
return false; return false;
} }
return _items.back()->data()->position() < position; return _items.back()->data()->position() < position;
} }
bool ListWidget::isBelowPosition(Data::MessagePosition position) const { bool ListWidget::isBelowPosition(Data::MessagePosition position) const {
if (_items.empty()) { if (_items.empty() || loadedAtTop()) {
return false; return false;
} }
return _items.front()->data()->position() > position; return _items.front()->data()->position() > position;

View File

@ -137,6 +137,7 @@ public:
void restoreState(not_null<ListMemento*> memento); void restoreState(not_null<ListMemento*> memento);
base::optional<int> scrollTopForPosition( base::optional<int> scrollTopForPosition(
Data::MessagePosition position) const; Data::MessagePosition position) const;
base::optional<int> scrollTopForView(not_null<Element*> view) const;
enum class AnimatedScroll { enum class AnimatedScroll {
Full, Full,
Part, Part,

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "auth_session.h" #include "auth_session.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "apiwrap.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_info.h" #include "styles/style_info.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
@ -88,6 +89,9 @@ ChannelsController::ChannelsController(not_null<Controller*> controller)
: PeerListController() : PeerListController()
, _controller(controller) , _controller(controller)
, _feed(_controller->key().feed()) { , _feed(_controller->key().feed()) {
if (!_feed->channelsLoaded()) {
Auth().api().requestFeedChannels(_feed);
}
_controller->setSearchEnabledByContent(false); _controller->setSearchEnabledByContent(false);
} }

View File

@ -199,9 +199,9 @@ Key WrapWidget::key() const {
Dialogs::RowDescriptor WrapWidget::activeChat() const { Dialogs::RowDescriptor WrapWidget::activeChat() const {
if (const auto peer = key().peer()) { 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()) { } else if (const auto feed = key().feed()) {
return Dialogs::RowDescriptor(feed, MsgId(0)); return Dialogs::RowDescriptor(feed, FullMsgId());
} }
Unexpected("Owner in WrapWidget::activeChat()."); Unexpected("Owner in WrapWidget::activeChat().");
} }
@ -497,18 +497,27 @@ void WrapWidget::showProfileMenu() {
}); });
_topBarMenuToggle->installEventFilter(_topBarMenu.get()); _topBarMenuToggle->installEventFilter(_topBarMenu.get());
// #TODO feeds menu const auto addAction = [=](
const auto peer = key().peer(); const QString &text,
if (!peer) { base::lambda<void()> 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; return;
} }
Window::FillPeerMenu(
_controller->parentController(),
peer,
[this](const QString &text, base::lambda<void()> callback) {
return _topBarMenu->addAction(text, std::move(callback));
},
Window::PeerMenuSource::Profile);
auto position = (wrap() == Wrap::Layer) auto position = (wrap() == Wrap::Layer)
? st::infoLayerTopBarMenuPosition ? st::infoLayerTopBarMenuPosition
: st::infoTopBarMenuPosition; : st::infoTopBarMenuPosition;

View File

@ -2184,6 +2184,9 @@ void MainWidget::showSection(
if (_mainSection && _mainSection->showInternal( if (_mainSection && _mainSection->showInternal(
&memento, &memento,
params)) { params)) {
if (const auto entry = _mainSection->activeChat(); entry.key) {
_controller->setActiveChatEntry(entry);
}
return; return;
// //
// Now third section handles only its own showSection() requests. // Now third section handles only its own showSection() requests.

View File

@ -41,7 +41,7 @@ void Controller::setActiveChatEntry(Dialogs::RowDescriptor row) {
} }
void Controller::setActiveChatEntry(Dialogs::Key key) { void Controller::setActiveChatEntry(Dialogs::Key key) {
setActiveChatEntry({ key, MsgId(0) }); setActiveChatEntry({ key, FullMsgId() });
} }
Dialogs::RowDescriptor Controller::activeChatEntryCurrent() const { Dialogs::RowDescriptor Controller::activeChatEntryCurrent() const {

View File

@ -25,6 +25,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
#include "history/history.h" #include "history/history.h"
#include "window/window_controller.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 "info/feed/info_feed_channels_controllers.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_feed.h" #include "data/data_feed.h"
@ -69,7 +71,10 @@ public:
void fill(); void fill();
private: private:
bool showInfo();
void addPinToggle(); void addPinToggle();
void addInfo();
void addSearch();
void addNotifications(); void addNotifications();
not_null<Controller*> _controller; not_null<Controller*> _controller;
@ -411,7 +416,28 @@ void FeedFiller::fill() {
if (_source == PeerMenuSource::ChatsList) { if (_source == PeerMenuSource::ChatsList) {
addPinToggle(); addPinToggle();
} }
if (showInfo()) {
addInfo();
}
addNotifications(); 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() { 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() { void FeedFiller::addNotifications() {
const auto feed = _feed; const auto feed = _feed;
_addAction(lang(lng_feed_notifications), [=] { _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 } // namespace
void PeerMenuDeleteContact(not_null<UserData*> user) { void PeerMenuDeleteContact(not_null<UserData*> user) {