Support feeds search display in dialogs list.

This commit is contained in:
John Preston 2018-02-14 22:38:01 +03:00
parent 98fb874b29
commit 0f775e1e66
16 changed files with 393 additions and 201 deletions

View File

@ -12,6 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
namespace Data {
namespace {
constexpr auto kMaxItemsInGroup = 10;
} // namespace
Groups::Groups(not_null<Session*> data) : _data(data) {
}
@ -30,9 +35,11 @@ void Groups::registerMessage(not_null<HistoryItem*> item) {
}
const auto i = _groups.emplace(item->groupId(), Group()).first;
auto &items = i->second.items;
items.insert(findPositionForItem(items, item), item);
if (items.size() > 1) {
refreshViews(items);
if (items.size() < kMaxItemsInGroup) {
items.insert(findPositionForItem(items, item), item);
if (items.size() > 1) {
refreshViews(items);
}
}
}

View File

@ -73,7 +73,9 @@ PeerClickHandler::PeerClickHandler(not_null<PeerData*> peer)
void PeerClickHandler::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton && App::wnd()) {
auto controller = App::wnd()->controller();
if (_peer && _peer->isChannel() && controller->historyPeer.current() != _peer) {
if (_peer
&& _peer->isChannel()
&& controller->activeChatCurrent().peer() != _peer) {
if (!_peer->asChannel()->isPublic() && !_peer->asChannel()->amIn()) {
Ui::show(Box<InformBox>(lang(_peer->isMegagroup()
? lng_group_not_accessible

View File

@ -69,7 +69,7 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> contro
, _contacts(std::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Name))
, _a_pinnedShifting(animation(this, &DialogsInner::step_pinnedShifting))
, _addContactLnk(this, lang(lng_add_contact_button))
, _cancelSearchInPeer(this, st::dialogsCancelSearchInPeer)
, _cancelSearchInChat(this, st::dialogsCancelSearchInPeer)
, _cancelSearchFromUser(this, st::dialogsCancelSearchInPeer) {
#ifdef OS_MAC_OLD
@ -83,8 +83,8 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> contro
}
connect(main, SIGNAL(dialogRowReplaced(Dialogs::Row*, Dialogs::Row*)), this, SLOT(onDialogRowReplaced(Dialogs::Row*, Dialogs::Row*)));
connect(_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
_cancelSearchInPeer->setClickedCallback([this] { cancelSearchInPeer(); });
_cancelSearchInPeer->hide();
_cancelSearchInChat->setClickedCallback([this] { cancelSearchInChat(); });
_cancelSearchInChat->hide();
_cancelSearchFromUser->setClickedCallback([this] { searchFromUserChanged.notify(nullptr); });
_cancelSearchFromUser->hide();
@ -175,13 +175,13 @@ int DialogsInner::peerSearchOffset() const {
int DialogsInner::searchedOffset() const {
auto result = peerSearchOffset() + (_peerSearchResults.empty() ? 0 : ((_peerSearchResults.size() * st::dialogsRowHeight) + st::searchedBarHeight));
if (_searchInPeer) {
result += searchInPeerSkip();
if (_searchInChat) {
result += searchInChatSkip();
}
return result;
}
int DialogsInner::searchInPeerSkip() const {
int DialogsInner::searchInChatSkip() const {
auto result = st::searchedBarHeight + st::dialogsSearchInHeight;
if (_searchFromUser) {
result += st::lineWidth + st::dialogsSearchInHeight;
@ -390,15 +390,24 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
}
}
if (_searchInPeer) {
paintSearchInPeer(p, fullWidth, paintingOther, ms);
p.translate(0, searchInPeerSkip());
if (_searchInChat) {
paintSearchInChat(p, fullWidth, paintingOther, ms);
p.translate(0, searchInChatSkip());
if (_waitingForSearch && _searchResults.empty()) {
p.fillRect(0, 0, fullWidth, st::searchedBarHeight, st::searchedBarBg);
p.fillRect(
0,
0,
fullWidth,
st::searchedBarHeight,
st::searchedBarBg);
if (!paintingOther) {
p.setFont(st::searchedBarFont);
p.setPen(st::searchedBarFg);
p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), lang(lng_dlg_search_for_messages));
p.drawTextLeft(
st::searchedBarPosition.x(),
st::searchedBarPosition.y(),
width(),
lang(lng_dlg_search_for_messages));
}
p.translate(0, st::searchedBarHeight);
}
@ -537,12 +546,12 @@ void DialogsInner::paintPeerSearchResult(
peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
}
void DialogsInner::paintSearchInPeer(
void DialogsInner::paintSearchInChat(
Painter &p,
int fullWidth,
bool onlyBackground,
TimeMs ms) const {
auto height = searchInPeerSkip();
auto height = searchInChatSkip();
auto top = st::searchedBarHeight;
p.fillRect(0, 0, fullWidth, top, st::searchedBarBg);
@ -560,44 +569,39 @@ void DialogsInner::paintSearchInPeer(
if (onlyBackground) return;
p.setPen(st::dialogsNameFg);
if (_searchInPeer->isSelf()) {
paintSearchInFilter(p, nullptr, top, fullWidth, _searchInSavedText);
if (const auto peer = _searchInChat.peer()) {
if (peer->isSelf()) {
paintSearchInSaved(p, top, fullWidth, _searchInChatText);
} else {
paintSearchInPeer(p, peer, top, fullWidth, _searchInChatText);
}
} else if (const auto feed = _searchInChat.feed()) {
paintSearchInFeed(p, feed, top, fullWidth, _searchInChatText);
} else {
paintSearchInFilter(p, _searchInPeer, top, fullWidth, _searchInPeer->nameText);
Unexpected("Empty Dialogs::Key in paintSearchInChat.");
}
if (_searchFromUser) {
if (const auto from = _searchFromUser) {
top += st::dialogsSearchInHeight + st::lineWidth;
p.setPen(st::dialogsTextFg);
p.setTextPalette(st::dialogsSearchFromPalette);
paintSearchInFilter(p, _searchFromUser, top, fullWidth, _searchFromUserText);
paintSearchInPeer(p, from, top, fullWidth, _searchFromUserText);
p.restoreTextPalette();
}
}
template <typename PaintUserpic>
void DialogsInner::paintSearchInFilter(
Painter &p,
PeerData *peer,
PaintUserpic paintUserpic,
int top,
int fullWidth,
const style::icon *icon,
const Text &text) const {
const auto savedPen = p.pen();
const auto userpicLeft = st::dialogsPadding.x();
const auto userpicTop = top
+ (st::dialogsSearchInHeight - st::dialogsSearchInPhotoSize) / 2;
if (peer) {
peer->paintUserpicLeft(
p,
st::dialogsPadding.x(),
userpicTop,
getFullWidth(),
st::dialogsSearchInPhotoSize);
} else {
Ui::EmptyUserpic::PaintSavedMessages(
p,
st::dialogsPadding.x(),
userpicTop,
getFullWidth(),
st::dialogsSearchInPhotoSize);
}
paintUserpic(p, userpicLeft, userpicTop, st::dialogsSearchInPhotoSize);
const auto nameleft = st::dialogsPadding.x()
+ st::dialogsSearchInPhotoSize
+ st::dialogsSearchInPhotoPadding;
@ -610,7 +614,7 @@ void DialogsInner::paintSearchInFilter(
top + (st::dialogsSearchInHeight - st::msgNameFont->height) / 2,
namewidth,
st::msgNameFont->height);
if (auto icon = Dialogs::Layout::ChatTypeIcon(peer, false, false)) {
if (icon) {
icon->paint(p, rectForName.topLeft(), fullWidth);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
}
@ -623,6 +627,44 @@ void DialogsInner::paintSearchInFilter(
getFullWidth());
}
void DialogsInner::paintSearchInPeer(
Painter &p,
not_null<PeerData*> peer,
int top,
int fullWidth,
const Text &text) const {
const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
peer->paintUserpicLeft(p, x, y, fullWidth, size);
};
const auto icon = Dialogs::Layout::ChatTypeIcon(peer, false, false);
paintSearchInFilter(p, paintUserpic, top, fullWidth, icon, text);
}
void DialogsInner::paintSearchInSaved(
Painter &p,
int top,
int fullWidth,
const Text &text) const {
const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, fullWidth, size);
};
paintSearchInFilter(p, paintUserpic, top, fullWidth, nullptr, text);
}
void DialogsInner::paintSearchInFeed(
Painter &p,
not_null<Data::Feed*> feed,
int top,
int fullWidth,
const Text &text) const {
const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
feed->paintUserpicLeft(p, x, y, fullWidth, size);
};
const auto icon = nullptr;
paintSearchInFilter(p, paintUserpic, top, fullWidth, icon, text);
}
void DialogsInner::activate() {
}
@ -1095,7 +1137,7 @@ void DialogsInner::setSearchedPressed(int pressed) {
void DialogsInner::resizeEvent(QResizeEvent *e) {
_addContactLnk->move((width() - _addContactLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2);
auto widthForCancelButton = qMax(width() + otherWidth(), st::columnMinimalWidthLeft);
_cancelSearchInPeer->moveToLeft(widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInPeer->width(), st::searchedBarHeight + (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2);
_cancelSearchInChat->moveToLeft(widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInChat->width(), st::searchedBarHeight + (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2);
_cancelSearchFromUser->moveToLeft(widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchFromUser->width(), st::searchedBarHeight + st::dialogsSearchInHeight + st::lineWidth + (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2);
}
@ -1532,7 +1574,7 @@ void DialogsInner::onFilterUpdate(QString newFilter, bool force) {
_waitingForSearch = true;
_filterResults.clear();
_filterResultsGlobal.clear();
if (!_searchInPeer && !words.isEmpty()) {
if (!_searchInChat && !words.isEmpty()) {
const Dialogs::List *toFilter = nullptr;
if (!_dialogs->isEmpty()) {
for (fi = fb; fi != fe; ++fi) {
@ -1612,7 +1654,7 @@ void DialogsInner::onFilterUpdate(QString newFilter, bool force) {
}
void DialogsInner::onHashtagFilterUpdate(QStringRef newFilter) {
if (newFilter.isEmpty() || newFilter.at(0) != '#' || _searchInPeer) {
if (newFilter.isEmpty() || newFilter.at(0) != '#' || _searchInChat) {
_hashtagFilter = QString();
if (!_hashtagResults.empty()) {
_hashtagResults.clear();
@ -1694,7 +1736,7 @@ void DialogsInner::itemRemoved(not_null<const HistoryItem*> item) {
for (auto i = _searchResults.begin(); i != _searchResults.end();) {
if ((*i)->item() == item) {
i = _searchResults.erase(i);
if (item->history()->peer == _searchInMigrated) {
if (item->history() == _searchInMigrated) {
if (_searchedMigratedCount > 0) --_searchedMigratedCount;
} else {
if (_searchedCount > 0) --_searchedCount;
@ -1791,7 +1833,10 @@ bool DialogsInner::searchReceived(
if (auto peer = App::peerLoaded(peerId)) {
if (lastDate) {
auto item = App::histories().addNewMessage(message, NewMessageExisting);
_searchResults.push_back(std::make_unique<Dialogs::FakeRow>(_searchInPeer, item));
_searchResults.push_back(
std::make_unique<Dialogs::FakeRow>(
_searchInChat,
item));
lastDateFound = lastDate;
if (isGlobalSearch) {
_lastSearchDate = lastDateFound;
@ -1973,7 +2018,7 @@ void DialogsInner::refresh(bool toTop) {
} else if (_state == State::Filtered) {
if (!_addContactLnk->isHidden()) _addContactLnk->hide();
if (_waitingForSearch) {
h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight) + ((_searchResults.empty() && !_searchInPeer) ? -st::searchedBarHeight : 0);
h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight) + ((_searchResults.empty() && !_searchInChat) ? -st::searchedBarHeight : 0);
} else {
h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight);
}
@ -1984,7 +2029,9 @@ void DialogsInner::refresh(bool toTop) {
emit mustScrollTo(0, 0);
loadPeerPhotos();
}
_controller->dialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true);
_controller->dialogsListDisplayForced().set(
_searchInChat || !_filter.isEmpty(),
true);
update();
}
@ -2012,40 +2059,72 @@ bool DialogsInner::hasFilteredResults() const {
return !_filterResults.isEmpty() && _hashtagResults.empty();
}
void DialogsInner::searchInPeer(PeerData *peer, UserData *from) {
_searchInPeer = peer ? (peer->migrateTo() ? peer->migrateTo() : peer) : nullptr;
_searchInMigrated = _searchInPeer ? _searchInPeer->migrateFrom() : nullptr;
_searchFromUser = from;
if (_searchInPeer) {
onHashtagFilterUpdate(QStringRef());
_cancelSearchInPeer->show();
if (_searchInPeer->isSelf()) {
_searchInSavedText.setText(
st::msgNameStyle,
lang(lng_saved_messages),
Ui::DialogTextOptions());
void DialogsInner::searchInChat(Dialogs::Key key, UserData *from) {
_searchInMigrated = nullptr;
if (const auto peer = key.peer()) {
if (const auto migrateTo = peer->migrateTo()) {
return searchInChat(App::history(migrateTo), from);
} else if (const auto migrateFrom = peer->migrateFrom()) {
_searchInMigrated = App::history(migrateFrom);
}
}
_searchInChat = key;
_searchFromUser = from;
if (_searchInChat) {
onHashtagFilterUpdate(QStringRef());
_cancelSearchInChat->show();
refreshSearchInChatLabel();
} else {
_cancelSearchInPeer->hide();
_cancelSearchInChat->hide();
}
if (_searchFromUser) {
auto fromUserText = lng_dlg_search_from(
lt_user,
textcmdLink(1, App::peerName(_searchFromUser)));
_searchFromUserText.setText(
st::dialogsSearchFromStyle,
fromUserText,
Ui::DialogTextOptions());
_cancelSearchFromUser->show();
} else {
_cancelSearchFromUser->hide();
}
_controller->dialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true);
_controller->dialogsListDisplayForced().set(
_searchInChat || !_filter.isEmpty(),
true);
}
void DialogsInner::refreshSearchInChatLabel() {
const auto dialog = [&] {
if (const auto peer = _searchInChat.peer()) {
if (peer->isSelf()) {
return lang(lng_saved_messages);
}
return peer->name;
} else if (const auto feed = _searchInChat.feed()) {
return feed->chatsListName();
}
return QString();
}();
if (!dialog.isEmpty()) {
_searchInChatText.setText(
st::msgNameStyle,
dialog,
Ui::DialogTextOptions());
}
const auto from = [&] {
if (const auto from = _searchFromUser) {
return App::peerName(from);
}
return QString();
}();
if (!from.isEmpty()) {
const auto fromUserText = lng_dlg_search_from(
lt_user,
textcmdLink(1, from));
_searchFromUserText.setText(
st::dialogsSearchFromStyle,
fromUserText,
Ui::DialogTextOptions());
}
}
void DialogsInner::clearFilter() {
if (_state == State::Filtered || _searchInPeer) {
if (_searchInPeer) {
if (_state == State::Filtered || _searchInChat) {
if (_searchInChat) {
_state = State::Filtered;
_waitingForSearch = true;
} else {

View File

@ -94,7 +94,7 @@ public:
}
bool hasFilteredResults() const;
void searchInPeer(PeerData *peer, UserData *from);
void searchInChat(Dialogs::Key key, UserData *from);
void onFilterUpdate(QString newFilter, bool force = false);
void onHashtagFilterUpdate(QStringRef newFilter);
@ -121,7 +121,7 @@ signals:
void dialogMoved(int movedFrom, int movedTo);
void searchMessages();
void searchResultChosen();
void cancelSearchInPeer();
void cancelSearchInChat();
void completeHashtag(QString tag);
void refreshHashtags();
@ -215,7 +215,7 @@ private:
int filteredOffset() const;
int peerSearchOffset() const;
int searchedOffset() const;
int searchInPeerSkip() const;
int searchInChatSkip() const;
void paintDialog(
Painter &p,
@ -233,17 +233,37 @@ private:
bool selected,
bool onlyBackground,
TimeMs ms) const;
void paintSearchInPeer(
void paintSearchInChat(
Painter &p,
int fullWidth,
bool onlyBackground,
TimeMs ms) const;
void paintSearchInFilter(
void paintSearchInPeer(
Painter &p,
PeerData *peer,
not_null<PeerData*> peer,
int top,
int fullWidth,
const Text &text) const;
void paintSearchInSaved(
Painter &p,
int top,
int fullWidth,
const Text &text) const;
void paintSearchInFeed(
Painter &p,
not_null<Data::Feed*> feed,
int top,
int fullWidth,
const Text &text) const;
template <typename PaintUserpic>
void paintSearchInFilter(
Painter &p,
PaintUserpic paintUserpic,
int top,
int fullWidth,
const style::icon *icon,
const Text &text) const;
void refreshSearchInChatLabel();
void clearSelection();
void clearSearchResults(bool clearPeerSearchResults = true);
@ -332,14 +352,14 @@ private:
State _state = State::Default;
object_ptr<Ui::LinkButton> _addContactLnk;
object_ptr<Ui::IconButton> _cancelSearchInPeer;
object_ptr<Ui::IconButton> _cancelSearchInChat;
object_ptr<Ui::IconButton> _cancelSearchFromUser;
PeerData *_searchInPeer = nullptr;
PeerData *_searchInMigrated = nullptr;
Dialogs::Key _searchInChat;
History *_searchInMigrated = nullptr;
UserData *_searchFromUser = nullptr;
Text _searchInChatText;
Text _searchFromUserText;
Text _searchInSavedText;
Dialogs::Key _menuKey;
base::lambda<void()> _loadMoreCallback;

View File

@ -49,11 +49,12 @@ void paintRowDate(Painter &p, QDateTime date, QRect &rectForName, bool active, b
}
enum class Flag {
Active = 0x01,
Selected = 0x02,
OnlyBackground = 0x04,
SearchResult = 0x08,
SavedMessages = 0x10,
Active = 0x01,
Selected = 0x02,
OnlyBackground = 0x04,
SearchResult = 0x08,
SavedMessages = 0x10,
FeedSearchResult = 0x20,
};
inline constexpr bool is_flag_type(Flag) { return true; }
@ -130,7 +131,7 @@ void paintRow(
namewidth,
st::msgNameFont->height);
if (from) {
if (from && !(flags & Flag::FeedSearchResult)) {
if (auto chatTypeIcon = ChatTypeIcon(from, active, selected)) {
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
@ -534,11 +535,13 @@ void RowPainter::paint(
auto history = item->history();
auto cloudDraft = nullptr;
const auto from = [&] {
if (auto searchPeer = row->searchInPeer()) {
if (searchPeer->isSelf()) {
return item->senderOriginal().get();
} else if (!searchPeer->isChannel() || searchPeer->isMegagroup()) {
return item->from().get();
if (const auto searchChat = row->searchInChat()) {
if (const auto peer = searchChat.peer()) {
if (peer->isSelf()) {
return item->senderOriginal().get();
} else if (!peer->isChannel() || peer->isMegagroup()) {
return item->from().get();
}
}
}
return history->peer->migrateTo()
@ -546,9 +549,11 @@ void RowPainter::paint(
: history->peer.get();
}();
const auto drawInDialogWay = [&] {
if (auto searchPeer = row->searchInPeer()) {
if (!searchPeer->isChannel() || searchPeer->isMegagroup()) {
return HistoryItem::DrawInDialog::WithoutSender;
if (const auto searchChat = row->searchInChat()) {
if (const auto peer = searchChat.peer()) {
if (!peer->isChannel() || peer->isMegagroup()) {
return HistoryItem::DrawInDialog::WithoutSender;
}
}
}
return HistoryItem::DrawInDialog::Normal;
@ -567,12 +572,13 @@ void RowPainter::paint(
};
const auto paintCounterCallback = [] {};
const auto showSavedMessages = history->peer->isSelf()
&& !row->searchInPeer();
&& !row->searchInChat();
const auto flags = (active ? Flag::Active : Flag(0))
| (selected ? Flag::Selected : Flag(0))
| (onlyBackground ? Flag::OnlyBackground : Flag(0))
| Flag::SearchResult
| (showSavedMessages ? Flag::SavedMessages : Flag(0));
| (showSavedMessages ? Flag::SavedMessages : Flag(0))
| (row->searchInChat().feed() ? Flag::FeedSearchResult : Flag(0));
paintRow(
p,
row,

View File

@ -44,8 +44,8 @@ uint64 Row::sortKey() const {
return _id.entry()->sortKeyInChatList();
}
FakeRow::FakeRow(PeerData *searchInPeer, not_null<HistoryItem*> item)
: _searchInPeer(searchInPeer)
FakeRow::FakeRow(Key searchInChat, not_null<HistoryItem*> item)
: _searchInChat(searchInChat)
, _item(item)
, _cache(st::dialogsTextWidthMin) {
}

View File

@ -81,10 +81,10 @@ private:
class FakeRow : public RippleRow {
public:
FakeRow(PeerData *searchInPeer, not_null<HistoryItem*> item);
FakeRow(Key searchInChat, not_null<HistoryItem*> item);
PeerData *searchInPeer() const {
return _searchInPeer;
Key searchInChat() const {
return _searchInChat;
}
not_null<HistoryItem*> item() const {
return _item;
@ -93,7 +93,7 @@ public:
private:
friend class Layout::RowPainter;
PeerData *_searchInPeer = nullptr;
Key _searchInChat;
not_null<HistoryItem*> _item;
mutable const HistoryItem *_cacheFor = nullptr;
mutable Text _cache;

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/dialogs_key.h"
#include "dialogs/dialogs_entry.h"
#include "history/history.h"
#include "history/feed/history_feed_section.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/wrap/fade_wrap.h"
@ -106,9 +107,9 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
connect(_inner, SIGNAL(searchResultChosen()), this, SLOT(onCancel()));
connect(_inner, SIGNAL(completeHashtag(QString)), this, SLOT(onCompleteHashtag(QString)));
connect(_inner, SIGNAL(refreshHashtags()), this, SLOT(onFilterCursorMoved()));
connect(_inner, SIGNAL(cancelSearchInPeer()), this, SLOT(onCancelSearchInPeer()));
connect(_inner, SIGNAL(cancelSearchInChat()), this, SLOT(onCancelSearchInChat()));
subscribe(_inner->searchFromUserChanged, [this](UserData *user) {
setSearchInPeer(_searchInPeer, user);
setSearchInChat(_searchInChat, user);
onFilterUpdate(true);
});
connect(_scroll, SIGNAL(geometryChanged()), _inner, SLOT(onParentGeometryChanged()));
@ -127,7 +128,11 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
subscribe(Adaptive::Changed(), [this] { updateForwardBar(); });
_cancelSearch->setClickedCallback([this] { onCancelSearch(); });
_jumpToDate->entity()->setClickedCallback([this] { if (_searchInPeer) this->controller()->showJumpToDate(_searchInPeer, QDate()); });
_jumpToDate->entity()->setClickedCallback([this] {
if (const auto peer = _searchInChat.peer()) {
this->controller()->showJumpToDate(peer, QDate());
}
});
_chooseFromUser->entity()->setClickedCallback([this] { showSearchFrom(); });
_lockUnlock->setVisible(Global::LocalPasscode());
subscribe(Global::RefLocalPasscodeChanged(), [this] { updateLockUnlockVisibility(); });
@ -310,7 +315,7 @@ void DialogsWidget::animationCallback() {
}
void DialogsWidget::onCancel() {
if (!onCancelSearch() || (!_searchInPeer && !App::main()->selectingPeer())) {
if (!onCancelSearch() || (!_searchInChat && !App::main()->selectingPeer())) {
emit cancelled();
}
}
@ -481,7 +486,7 @@ bool DialogsWidget::onSearchMessages(bool searchCache) {
_searchFull = _searchFullMigrated = false;
MTP::cancel(base::take(_searchRequest));
searchReceived(
_searchInPeer
_searchInChat
? DialogsSearchPeerFromStart
: DialogsSearchFromStart,
i.value(),
@ -493,14 +498,14 @@ bool DialogsWidget::onSearchMessages(bool searchCache) {
_searchQueryFrom = _searchFromUser;
_searchFull = _searchFullMigrated = false;
MTP::cancel(base::take(_searchRequest));
if (_searchInPeer) {
if (const auto peer = _searchInChat.peer()) {
const auto flags = _searchQueryFrom
? MTP_flags(MTPmessages_Search::Flag::f_from_id)
: MTP_flags(0);
_searchRequest = MTP::send(
MTPmessages_Search(
flags,
_searchInPeer->input,
peer->input,
MTP_string(_searchQuery),
_searchQueryFrom
? _searchQueryFrom->inputUser
@ -516,6 +521,17 @@ bool DialogsWidget::onSearchMessages(bool searchCache) {
MTP_int(0)),
rpcDone(&DialogsWidget::searchReceived, DialogsSearchPeerFromStart),
rpcFail(&DialogsWidget::searchFailed, DialogsSearchPeerFromStart));
} else if (const auto feed = _searchInChat.feed()) {
_searchRequest = MTP::send(
MTPchannels_SearchFeed(
MTP_int(feed->id()),
MTP_string(_searchQuery),
MTP_int(0),
MTP_inputPeerEmpty(),
MTP_int(0),
MTP_int(SearchPerPage)),
rpcDone(&DialogsWidget::searchReceived, DialogsSearchFromStart),
rpcFail(&DialogsWidget::searchFailed, DialogsSearchFromStart));
} else {
_searchRequest = MTP::send(
MTPmessages_SearchGlobal(
@ -529,7 +545,7 @@ bool DialogsWidget::onSearchMessages(bool searchCache) {
}
_searchQueries.insert(_searchRequest, _searchQuery);
}
if (!_searchInPeer && !q.isEmpty()) {
if (!_searchInChat && !q.isEmpty()) {
if (searchCache) {
auto i = _peerSearchCache.constFind(q);
if (i != _peerSearchCache.cend()) {
@ -567,11 +583,23 @@ void DialogsWidget::showMainMenu() {
App::wnd()->showMainMenu();
}
void DialogsWidget::searchMessages(const QString &query, PeerData *inPeer) {
if ((_filter->getLastText() != query) || (inPeer && inPeer != _searchInPeer && inPeer->migrateTo() != _searchInPeer)) {
if (inPeer) {
void DialogsWidget::searchMessages(
const QString &query,
Dialogs::Key inChat) {
auto inChatChanged = [&] {
if (inChat == _searchInChat) {
return false;
} else if (const auto inPeer = inChat.peer()) {
if (inPeer->migrateTo() == _searchInChat.peer()) {
return false;
}
}
return true;
}();
if ((_filter->getLastText() != query) || inChatChanged) {
if (inChat) {
onCancelSearch();
setSearchInPeer(inPeer);
setSearchInChat(inChat);
}
_filter->setText(query);
_filter->updatePlaceholder();
@ -589,12 +617,14 @@ void DialogsWidget::onSearchMore() {
auto offsetDate = _inner->lastSearchDate();
auto offsetPeer = _inner->lastSearchPeer();
auto offsetId = _inner->lastSearchId();
if (_searchInPeer) {
auto flags = _searchQueryFrom ? MTP_flags(MTPmessages_Search::Flag::f_from_id) : MTP_flags(0);
if (const auto peer = _searchInChat.peer()) {
auto flags = _searchQueryFrom
? MTP_flags(MTPmessages_Search::Flag::f_from_id)
: MTP_flags(0);
_searchRequest = MTP::send(
MTPmessages_Search(
flags,
_searchInPeer->input,
peer->input,
MTP_string(_searchQuery),
_searchQueryFrom
? _searchQueryFrom->inputUser
@ -610,6 +640,19 @@ void DialogsWidget::onSearchMore() {
MTP_int(0)),
rpcDone(&DialogsWidget::searchReceived, offsetId ? DialogsSearchPeerFromOffset : DialogsSearchPeerFromStart),
rpcFail(&DialogsWidget::searchFailed, offsetId ? DialogsSearchPeerFromOffset : DialogsSearchPeerFromStart));
} else if (const auto feed = _searchInChat.feed()) {
_searchRequest = MTP::send(
MTPchannels_SearchFeed(
MTP_int(feed->id()),
MTP_string(_searchQuery),
MTP_int(offsetDate),
offsetPeer
? offsetPeer->input
: MTP_inputPeerEmpty(),
MTP_int(offsetId),
MTP_int(SearchPerPage)),
rpcDone(&DialogsWidget::searchReceived, offsetId ? DialogsSearchFromOffset : DialogsSearchFromStart),
rpcFail(&DialogsWidget::searchFailed, offsetId ? DialogsSearchFromOffset : DialogsSearchFromStart));
} else {
_searchRequest = MTP::send(
MTPmessages_SearchGlobal(
@ -628,11 +671,13 @@ void DialogsWidget::onSearchMore() {
}
} else if (_searchInMigrated && !_searchFullMigrated) {
auto offsetMigratedId = _inner->lastSearchMigratedId();
auto flags = _searchQueryFrom ? MTP_flags(MTPmessages_Search::Flag::f_from_id) : MTP_flags(0);
auto flags = _searchQueryFrom
? MTP_flags(MTPmessages_Search::Flag::f_from_id)
: MTP_flags(0);
_searchRequest = MTP::send(
MTPmessages_Search(
flags,
_searchInMigrated->input,
_searchInMigrated->peer->input,
MTP_string(_searchQuery),
_searchQueryFrom
? _searchQueryFrom->inputUser
@ -741,10 +786,18 @@ void DialogsWidget::searchReceived(
case mtpc_messages_channelMessages: {
auto &d = result.c_messages_channelMessages();
if (_searchInPeer && _searchInPeer->isChannel()) {
_searchInPeer->asChannel()->ptsReceived(d.vpts.v);
if (const auto peer = _searchInChat.peer()) {
if (const auto channel = peer->asChannel()) {
channel->ptsReceived(d.vpts.v);
} else {
LOG(("API Error: "
"received messages.channelMessages when no channel "
"was passed! (DialogsWidget::searchReceived)"));
}
} else {
LOG(("API Error: received messages.channelMessages when no channel was passed! (DialogsWidget::searchReceived)"));
LOG(("API Error: "
"received messages.channelMessages when no channel "
"was passed! (DialogsWidget::searchReceived)"));
}
if (_searchRequest != 0) {
// Don't apply cached data!
@ -941,26 +994,26 @@ void DialogsWidget::onFilterUpdate(bool force) {
void DialogsWidget::searchInChat(Dialogs::Key chat) {
onCancelSearch();
if (const auto peer = chat.peer()) {
setSearchInPeer(peer);
} else {
// #TODO feeds search
setSearchInPeer(nullptr);
}
setSearchInChat(chat);
onFilterUpdate(true);
}
void DialogsWidget::setSearchInPeer(PeerData *peer, UserData *from) {
auto searchInPeerUpdated = false;
auto newSearchInPeer = peer ? (peer->migrateTo() ? peer->migrateTo() : peer) : nullptr;
_searchInMigrated = newSearchInPeer ? newSearchInPeer->migrateFrom() : nullptr;
searchInPeerUpdated = (newSearchInPeer != _searchInPeer);
void DialogsWidget::setSearchInChat(Dialogs::Key chat, UserData *from) {
_searchInMigrated = nullptr;
if (const auto peer = chat.peer()) {
if (const auto migrateTo = peer->migrateTo()) {
return setSearchInChat(App::history(migrateTo), from);
} else if (const auto migrateFrom = peer->migrateFrom()) {
_searchInMigrated = App::history(migrateFrom);
}
}
const auto searchInPeerUpdated = (_searchInChat != chat);
if (searchInPeerUpdated) {
_searchInPeer = newSearchInPeer;
_searchInChat = chat;
from = nullptr;
controller()->searchInPeer = _searchInPeer;
controller()->searchInChat = _searchInChat;
updateJumpToDateVisibility();
} else if (!_searchInPeer) {
} else if (!_searchInChat) {
from = nullptr;
}
if (_searchFromUser != from || searchInPeerUpdated) {
@ -968,7 +1021,7 @@ void DialogsWidget::setSearchInPeer(PeerData *peer, UserData *from) {
updateSearchFromVisibility();
clearSearchCache();
}
_inner->searchInPeer(_searchInPeer, _searchFromUser);
_inner->searchInChat(_searchInChat, _searchFromUser);
if (_searchFromUser && _lastFilterText == SwitchToChooseFromQuery()) {
onCancelSearch();
}
@ -984,20 +1037,19 @@ void DialogsWidget::clearSearchCache() {
}
void DialogsWidget::showSearchFrom() {
if (!_searchInPeer) {
return;
if (const auto peer = _searchInChat.peer()) {
const auto chat = _searchInChat;
Dialogs::ShowSearchFromBox(
controller(),
peer,
base::lambda_guarded(this, [=](
not_null<UserData*> user) {
Ui::hideLayer();
setSearchInChat(chat, user);
onFilterUpdate(true);
}),
base::lambda_guarded(this, [this] { _filter->setFocus(); }));
}
auto peer = _searchInPeer;
Dialogs::ShowSearchFromBox(
controller(),
peer,
base::lambda_guarded(this, [this, peer](
not_null<UserData*> user) {
Ui::hideLayer();
setSearchInPeer(peer, user);
onFilterUpdate(true);
}),
base::lambda_guarded(this, [this] { _filter->setFocus(); }));
}
void DialogsWidget::onFilterCursorMoved(int from, int to) {
@ -1058,12 +1110,19 @@ void DialogsWidget::updateJumpToDateVisibility(bool fast) {
if (_a_show.animating()) return;
_jumpToDate->toggle(
(_searchInPeer && _filter->getLastText().isEmpty()),
(_searchInChat && _filter->getLastText().isEmpty()),
fast ? anim::type::instant : anim::type::normal);
}
void DialogsWidget::updateSearchFromVisibility(bool fast) {
auto visible = _searchInPeer && (_searchInPeer->isChat() || _searchInPeer->isMegagroup()) && !_searchFromUser;
auto visible = [&] {
if (const auto peer = _searchInChat.peer()) {
if (peer->isChat() || peer->isMegagroup()) {
return !_searchFromUser;
}
}
return false;
}();
auto changed = (visible == !_chooseFromUser->toggled());
_chooseFromUser->toggle(
visible,
@ -1263,11 +1322,17 @@ bool DialogsWidget::onCancelSearch() {
MTP::cancel(_searchRequest);
_searchRequest = 0;
}
if (_searchInPeer && !clearing) {
if (_searchInChat && !clearing) {
if (Adaptive::OneColumn()) {
Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId);
if (const auto peer = _searchInChat.peer()) {
Ui::showPeerHistory(peer, ShowAtUnreadMsgId);
} else if (const auto feed = _searchInChat.feed()) {
controller()->showSection(HistoryFeed::Memento(feed));
} else {
Unexpected("Empty key in onCancelSearch().");
}
}
setSearchInPeer(nullptr);
setSearchInChat(Dialogs::Key());
clearing = true;
}
_inner->clearFilter();
@ -1277,16 +1342,22 @@ bool DialogsWidget::onCancelSearch() {
return clearing;
}
void DialogsWidget::onCancelSearchInPeer() {
void DialogsWidget::onCancelSearchInChat() {
if (_searchRequest) {
MTP::cancel(_searchRequest);
_searchRequest = 0;
}
if (_searchInPeer) {
if (_searchInChat) {
if (Adaptive::OneColumn() && !App::main()->selectingPeer()) {
Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId);
if (const auto peer = _searchInChat.peer()) {
Ui::showPeerHistory(peer, ShowAtUnreadMsgId);
} else if (const auto feed = _searchInChat.feed()) {
controller()->showSection(HistoryFeed::Memento(feed));
} else {
Unexpected("Empty key in onCancelSearchInPeer().");
}
}
setSearchInPeer(nullptr);
setSearchInChat(Dialogs::Key());
}
_inner->clearFilter();
_filter->clear();

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/section_widget.h"
#include "ui/widgets/scroll_area.h"
#include "dialogs/dialogs_key.h"
class DialogsInner;
@ -85,7 +86,7 @@ public:
Dialogs::IndexedList *dialogsList();
Dialogs::IndexedList *contactsNoDialogsList();
void searchMessages(const QString &query, PeerData *inPeer = 0);
void searchMessages(const QString &query, Dialogs::Key inChat = {});
void onSearchMore();
// Float player interface.
@ -105,7 +106,7 @@ public slots:
void activate();
void onFilterUpdate(bool force = false);
bool onCancelSearch();
void onCancelSearchInPeer();
void onCancelSearchInChat();
void onFilterCursorMoved(int from = -1, int to = -1);
void onCompleteHashtag(QString tag);
@ -154,7 +155,7 @@ private:
const QVector<MTPDialog> &dialogs,
const QVector<MTPMessage> &messages);
void setSearchInPeer(PeerData *peer, UserData *from = nullptr);
void setSearchInChat(Dialogs::Key chat, UserData *from = nullptr);
void showSearchFrom();
void showMainMenu();
void clearSearchCache();
@ -196,8 +197,8 @@ private:
Window::SlideDirection _showDirection;
QPixmap _cacheUnder, _cacheOver;
PeerData *_searchInPeer = nullptr;
PeerData *_searchInMigrated = nullptr;
Dialogs::Key _searchInChat;
History *_searchInMigrated = nullptr;
UserData *_searchFromUser = nullptr;
QString _lastFilterText;

View File

@ -149,13 +149,17 @@ void activateBotCommand(
}
void searchByHashtag(const QString &tag, PeerData *inPeer) {
if (MainWidget *m = main()) {
if (const auto m = main()) {
Ui::hideSettingsAndLayer();
Messenger::Instance().hideMediaView();
if (inPeer && (!inPeer->isChannel() || inPeer->isMegagroup())) {
inPeer = nullptr;
}
m->searchMessages(tag + ' ', inPeer);
m->searchMessages(
tag + ' ',
(inPeer
? App::history(inPeer).get()
: nullptr));
}
}

View File

@ -1839,13 +1839,12 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
updateForwarding();
updateOverStates(mapFromGlobal(QCursor::pos()));
crl::on_main(App::wnd(), [] { App::wnd()->setInnerFocus(); });
controller()->historyPeer = _peer;
if (_history) {
controller()->setActiveChatEntry({ _history, _showAtMsgId });
}
update();
crl::on_main(App::wnd(), [] { App::wnd()->setInnerFocus(); });
}
void HistoryWidget::clearDelayedShowAt() {

View File

@ -67,26 +67,26 @@ TopBarWidget::TopBarWidget(
_back->addClickHandler([this] { backClicked(); });
rpl::combine(
_controller->historyPeer.value(),
_controller->searchInPeer.value()
_controller->activeChatValue(),
_controller->searchInChat.value()
) | rpl::combine_previous(
std::make_tuple(nullptr, nullptr)
std::make_tuple(Dialogs::Key(), Dialogs::Key())
) | rpl::map([](
const std::tuple<PeerData*, PeerData*> &previous,
const std::tuple<PeerData*, PeerData*> &current) {
auto peer = std::get<0>(current);
auto searchPeer = std::get<1>(current);
auto peerChanged = (peer != std::get<0>(previous));
auto searchInPeer
= (peer != nullptr) && (peer == searchPeer);
return std::make_tuple(searchInPeer, peerChanged);
const std::tuple<Dialogs::Key, Dialogs::Key> &previous,
const std::tuple<Dialogs::Key, Dialogs::Key> &current) {
auto active = std::get<0>(current);
auto search = std::get<1>(current);
auto activeChanged = (active != std::get<0>(previous));
auto searchInChat
= search && (active == search);
return std::make_tuple(searchInChat, activeChanged);
}) | rpl::start_with_next([this](
bool searchInHistoryPeer,
bool peerChanged) {
auto animated = peerChanged
bool searchInActiveChat,
bool activeChanged) {
auto animated = activeChanged
? anim::type::instant
: anim::type::normal;
_search->setForceRippled(searchInHistoryPeer, animated);
_search->setForceRippled(searchInActiveChat, animated);
}, lifetime());
subscribe(Adaptive::Changed(), [this] { updateAdaptiveLayout(); });

View File

@ -349,9 +349,13 @@ Ui::MultiSlideTracker DetailsFiller::fillUserButtons(
auto window = _controller->parentController();
auto addSendMessageButton = [&] {
auto activePeerValue = window->activeChatValue(
) | rpl::map([](Dialogs::Key key) {
return key.peer();
});
auto sendMessageVisible = rpl::combine(
_controller->wrapValue(),
window->historyPeer.value(),
std::move(activePeerValue),
(_1 != Wrap::Side) || (_2 != user));
auto sendMessage = [window, user] {
window->showPeerHistory(
@ -399,9 +403,13 @@ Ui::MultiSlideTracker DetailsFiller::fillChannelButtons(
Ui::MultiSlideTracker tracker;
auto window = _controller->parentController();
auto activePeerValue = window->activeChatValue(
) | rpl::map([](Dialogs::Key key) {
return key.peer();
});
auto viewChannelVisible = rpl::combine(
_controller->wrapValue(),
window->historyPeer.value(),
std::move(activePeerValue),
(_1 != Wrap::Side) || (_2 != channel));
auto viewChannel = [=] {
window->showPeerHistory(

View File

@ -1406,8 +1406,8 @@ bool MainWidget::insertBotCommand(const QString &cmd) {
return _history->insertBotCommand(cmd);
}
void MainWidget::searchMessages(const QString &query, PeerData *inPeer) {
_dialogs->searchMessages(query, inPeer);
void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
_dialogs->searchMessages(query, inChat);
if (Adaptive::OneColumn()) {
Ui::showChatsList();
} else {
@ -2018,9 +2018,11 @@ void MainWidget::ui_showPeerHistory(
break;
}
}
if (auto historyPeer = _controller->historyPeer.current()) {
if (way == Way::Forward && historyPeer->id == peerId) {
way = Way::ClearStack;
if (const auto activeChat = _controller->activeChatCurrent()) {
if (const auto peer = activeChat.peer()) {
if (way == Way::Forward && peer->id == peerId) {
way = Way::ClearStack;
}
}
}
}

View File

@ -243,7 +243,7 @@ public:
bool insertBotCommand(const QString &cmd);
void jumpToDate(not_null<PeerData*> peer, const QDate &date);
void searchMessages(const QString &query, PeerData *inPeer);
void searchMessages(const QString &query, Dialogs::Key inChat);
void itemEdited(not_null<HistoryItem*> item);
void checkLastUpdate(bool afterSleep);

View File

@ -108,16 +108,9 @@ public:
return _window;
}
// This is needed for History TopBar updating when searchInPeer
// This is needed for History TopBar updating when searchInChat
// is changed in the DialogsWidget of the current window.
rpl::variable<PeerData*> searchInPeer;
// This is needed while we have one HistoryWidget and one TopBarWidget
// for all histories we show in a window. Once each history is shown
// in its own HistoryWidget with its own TopBarWidget this can be removed.
//
// Also used in the Info::Profile to toggle Send Message button.
rpl::variable<PeerData*> historyPeer;
rpl::variable<Dialogs::Key> searchInChat;
void setActiveChatEntry(Dialogs::RowDescriptor row);
void setActiveChatEntry(Dialogs::Key key);