Prepare dialogs to open feeds.

This commit is contained in:
John Preston 2018-01-07 15:04:34 +03:00
parent 782e70b171
commit f0b2e445f6
9 changed files with 285 additions and 198 deletions

View File

@ -139,6 +139,11 @@ reversion_wrapper<Container> reversed(Container &&container) {
return { container }; return { container };
} }
template <typename Value, typename From, typename Till>
inline bool in_range(Value &&value, From &&from, Till &&till) {
return (value >= from) && (value < till);
}
} // namespace base } // namespace base
// using for_const instead of plain range-based for loop to ensure usage of const_iterator // using for_const instead of plain range-based for loop to ensure usage of const_iterator

View File

@ -13,30 +13,14 @@ namespace Data {
FeedPosition::FeedPosition(const MTPFeedPosition &position) FeedPosition::FeedPosition(const MTPFeedPosition &position)
: date(position.c_feedPosition().vdate.v) : date(position.c_feedPosition().vdate.v)
, peerId(peerFromMTP(position.c_feedPosition().vpeer)) , msgId(
, msgId(position.c_feedPosition().vid.v) { peerToChannel(peerFromMTP(position.c_feedPosition().vpeer)),
position.c_feedPosition().vid.v) {
} }
FeedPosition::FeedPosition(not_null<HistoryItem*> item) FeedPosition::FeedPosition(not_null<HistoryItem*> item)
: date(toServerTime(item->date.toTime_t()).v) : date(toServerTime(item->date.toTime_t()).v)
, peerId(item->history()->peer->id) , msgId(item->fullId()) {
, msgId(item->id) {
}
bool FeedPosition::operator<(const FeedPosition &other) const {
if (date < other.date) {
return true;
} else if (other.date < date) {
return false;
}
const auto peer = peerToBareInt(peerId);
const auto otherPeer = peerToBareInt(other.peerId);
if (peer < otherPeer) {
return true;
} else if (otherPeer < peer) {
return false;
}
return (msgId < other.msgId);
} }
Feed::Feed(FeedId id) Feed::Feed(FeedId id)

View File

@ -15,14 +15,23 @@ namespace Data {
struct FeedPosition { struct FeedPosition {
FeedPosition() = default; FeedPosition() = default;
FeedPosition(const MTPFeedPosition &position); explicit FeedPosition(const MTPFeedPosition &position);
FeedPosition(not_null<HistoryItem*> item); explicit FeedPosition(not_null<HistoryItem*> item);
FeedPosition(TimeId date, FullMsgId msgId) : date(date), msgId(msgId) {
explicit operator bool() const {
return (msgId != 0);
} }
bool operator<(const FeedPosition &other) const; explicit operator bool() const {
return (msgId.msg != 0);
}
inline bool operator<(const FeedPosition &other) const {
if (date < other.date) {
return true;
} else if (other.date < date) {
return false;
}
return (msgId < other.msgId);
}
inline bool operator>(const FeedPosition &other) const { inline bool operator>(const FeedPosition &other) const {
return other < *this; return other < *this;
} }
@ -34,7 +43,6 @@ struct FeedPosition {
} }
inline bool operator==(const FeedPosition &other) const { inline bool operator==(const FeedPosition &other) const {
return (date == other.date) return (date == other.date)
&& (peerId == other.peerId)
&& (msgId == other.msgId); && (msgId == other.msgId);
} }
inline bool operator!=(const FeedPosition &other) const { inline bool operator!=(const FeedPosition &other) const {
@ -42,8 +50,7 @@ struct FeedPosition {
} }
TimeId date = 0; TimeId date = 0;
PeerId peerId = 0; FullMsgId msgId;
MsgId msgId = 0;
}; };

View File

@ -149,9 +149,12 @@ inline bool operator!=(const FullMsgId &a, const FullMsgId &b) {
return !(a == b); return !(a == b);
} }
inline bool operator<(const FullMsgId &a, const FullMsgId &b) { inline bool operator<(const FullMsgId &a, const FullMsgId &b) {
if (a.msg < b.msg) return true; if (a.channel < b.channel) {
if (a.msg > b.msg) return false; return true;
return a.channel < b.channel; } else if (a.channel > b.channel) {
return false;
}
return a.msg < b.msg;
} }
using MessageIdsList = std::vector<FullMsgId>; using MessageIdsList = std::vector<FullMsgId>;

View File

@ -93,8 +93,14 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> contro
lifetime()); lifetime());
Auth().data().itemRepaintRequest( Auth().data().itemRepaintRequest(
) | rpl::start_with_next([this](auto item) { ) | rpl::start_with_next([this](auto item) {
if (item->history()->lastMsg == item) { const auto history = item->history();
item->history()->updateChatListEntry(); if (history->textCachedFor == item) {
history->updateChatListEntry();
}
if (const auto feed = history->peer->feed()) {
if (feed->textCachedFor == item) {
feed->updateChatListEntry();
}
} }
}, lifetime()); }, lifetime());
subscribe(App::histories().sendActionAnimationUpdated(), [this](const Histories::SendActionAnimationUpdate &update) { subscribe(App::histories().sendActionAnimationUpdated(), [this](const Histories::SendActionAnimationUpdate &update) {
@ -174,7 +180,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
} }
auto fullWidth = getFullWidth(); auto fullWidth = getFullWidth();
auto ms = getms(); auto ms = getms();
if (_state == DefaultState) { if (_state == State::Default) {
_a_pinnedShifting.step(ms, false); _a_pinnedShifting.step(ms, false);
auto rows = shownDialogs(); auto rows = shownDialogs();
@ -256,7 +262,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
p.drawText(QRect(0, 0, fullWidth, st::noContactsHeight - (Auth().data().contactsLoaded().value() ? st::noContactsFont->height : 0)), lang(Auth().data().contactsLoaded().value() ? lng_no_chats : lng_contacts_loading), style::al_center); p.drawText(QRect(0, 0, fullWidth, st::noContactsHeight - (Auth().data().contactsLoaded().value() ? st::noContactsFont->height : 0)), lang(Auth().data().contactsLoaded().value() ? lng_no_chats : lng_contacts_loading), style::al_center);
} }
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
if (!_hashtagResults.empty()) { if (!_hashtagResults.empty()) {
auto from = floorclamp(r.y(), st::mentionHeight, 0, _hashtagResults.size()); auto from = floorclamp(r.y(), st::mentionHeight, 0, _hashtagResults.size());
auto to = ceilclamp(r.y() + r.height(), st::mentionHeight, 0, _hashtagResults.size()); auto to = ceilclamp(r.y() + r.height(), st::mentionHeight, 0, _hashtagResults.size());
@ -374,7 +380,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
if (_searchInPeer) { if (_searchInPeer) {
paintSearchInPeer(p, fullWidth, paintingOther, ms); paintSearchInPeer(p, fullWidth, paintingOther, ms);
p.translate(0, searchInPeerSkip()); p.translate(0, searchInPeerSkip());
if (_state == FilteredState && _searchResults.empty()) { if (_waitingForSearch && _searchResults.empty()) {
p.fillRect(0, 0, fullWidth, st::searchedBarHeight, st::searchedBarBg); p.fillRect(0, 0, fullWidth, st::searchedBarHeight, st::searchedBarBg);
if (!paintingOther) { if (!paintingOther) {
p.setFont(st::searchedBarFont); p.setFont(st::searchedBarFont);
@ -385,8 +391,12 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
} }
} }
if (_state == SearchedState || !_searchResults.empty()) { if (!_waitingForSearch || !_searchResults.empty()) {
auto text = _searchResults.empty() ? lang(lng_search_no_results) : lng_search_found_results(lt_count, _searchedMigratedCount + _searchedCount); const auto text = _searchResults.empty()
? lang(lng_search_no_results)
: lng_search_found_results(
lt_count,
_searchedMigratedCount + _searchedCount);
p.fillRect(0, 0, fullWidth, st::searchedBarHeight, st::searchedBarBg); p.fillRect(0, 0, fullWidth, st::searchedBarHeight, st::searchedBarBg);
if (!paintingOther) { if (!paintingOther) {
p.setFont(st::searchedBarFont); p.setFont(st::searchedBarFont);
@ -606,7 +616,7 @@ void DialogsInner::mouseMoveEvent(QMouseEvent *e) {
} }
void DialogsInner::clearIrrelevantState() { void DialogsInner::clearIrrelevantState() {
if (_state == DefaultState) { if (_state == State::Default) {
_hashtagSelected = -1; _hashtagSelected = -1;
setHashtagPressed(-1); setHashtagPressed(-1);
_hashtagDeleteSelected = _hashtagDeletePressed = false; _hashtagDeleteSelected = _hashtagDeletePressed = false;
@ -616,7 +626,7 @@ void DialogsInner::clearIrrelevantState() {
setPeerSearchPressed(-1); setPeerSearchPressed(-1);
_searchedSelected = -1; _searchedSelected = -1;
setSearchedPressed(-1); setSearchedPressed(-1);
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
_importantSwitchSelected = false; _importantSwitchSelected = false;
setImportantSwitchPressed(false); setImportantSwitchPressed(false);
_selected = nullptr; _selected = nullptr;
@ -635,7 +645,7 @@ void DialogsInner::updateSelected(QPoint localPos) {
int w = width(), mouseY = localPos.y(); int w = width(), mouseY = localPos.y();
clearIrrelevantState(); clearIrrelevantState();
if (_state == DefaultState) { if (_state == State::Default) {
auto importantSwitchSelected = (_dialogsImportant && mouseY >= 0 && mouseY < dialogsOffset()); auto importantSwitchSelected = (_dialogsImportant && mouseY >= 0 && mouseY < dialogsOffset());
mouseY -= dialogsOffset(); mouseY -= dialogsOffset();
auto selected = importantSwitchSelected ? nullptr : shownDialogs()->rowAtY(mouseY, st::dialogsRowHeight); auto selected = importantSwitchSelected ? nullptr : shownDialogs()->rowAtY(mouseY, st::dialogsRowHeight);
@ -646,7 +656,7 @@ void DialogsInner::updateSelected(QPoint localPos) {
updateSelectedRow(); updateSelectedRow();
setCursor((_selected || _importantSwitchSelected) ? style::cur_pointer : style::cur_default); setCursor((_selected || _importantSwitchSelected) ? style::cur_pointer : style::cur_default);
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
auto wasSelected = isSelected(); auto wasSelected = isSelected();
if (_hashtagResults.empty()) { if (_hashtagResults.empty()) {
_hashtagSelected = -1; _hashtagSelected = -1;
@ -688,7 +698,7 @@ void DialogsInner::updateSelected(QPoint localPos) {
updateSelectedRow(); updateSelectedRow();
} }
} }
if (_state == SearchedState && !_searchResults.empty()) { if (!_waitingForSearch && !_searchResults.empty()) {
auto skip = searchedOffset(); auto skip = searchedOffset();
auto searchedSelected = (mouseY >= skip) ? ((mouseY - skip) / st::dialogsRowHeight) : -1; auto searchedSelected = (mouseY >= skip) ? ((mouseY - skip) / st::dialogsRowHeight) : -1;
if (searchedSelected < 0 || searchedSelected >= _searchResults.size()) { if (searchedSelected < 0 || searchedSelected >= _searchResults.size()) {
@ -730,26 +740,26 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) {
} }
}); });
_dragStart = e->pos(); _dragStart = e->pos();
} else if (_hashtagPressed >= 0 && _hashtagPressed < _hashtagResults.size() && !_hashtagDeletePressed) { } else if (base::in_range(_hashtagPressed, 0, _hashtagResults.size()) && !_hashtagDeletePressed) {
auto row = &_hashtagResults[_hashtagPressed]->row; auto row = &_hashtagResults[_hashtagPressed]->row;
row->addRipple(e->pos(), QSize(getFullWidth(), st::mentionHeight), [this, index = _hashtagPressed] { row->addRipple(e->pos(), QSize(getFullWidth(), st::mentionHeight), [this, index = _hashtagPressed] {
update(0, index * st::mentionHeight, getFullWidth(), st::mentionHeight); update(0, index * st::mentionHeight, getFullWidth(), st::mentionHeight);
}); });
} else if (_filteredPressed >= 0 && _filteredPressed < _filterResults.size()) { } else if (base::in_range(_filteredPressed, 0, _filterResults.size())) {
const auto row = _filterResults[_filteredPressed]; const auto row = _filterResults[_filteredPressed];
const auto list = Global::DialogsMode(); const auto list = Global::DialogsMode();
row->addRipple( row->addRipple(
e->pos() - QPoint(0, filteredOffset() + _filteredPressed * st::dialogsRowHeight), e->pos() - QPoint(0, filteredOffset() + _filteredPressed * st::dialogsRowHeight),
QSize(getFullWidth(), st::dialogsRowHeight), QSize(getFullWidth(), st::dialogsRowHeight),
[=] { dlgUpdated(list, row); }); [=] { dlgUpdated(list, row); });
} else if (_peerSearchPressed >= 0 && _peerSearchPressed < _peerSearchResults.size()) { } else if (base::in_range(_peerSearchPressed, 0, _peerSearchResults.size())) {
auto &result = _peerSearchResults[_peerSearchPressed]; auto &result = _peerSearchResults[_peerSearchPressed];
auto row = &result->row; auto row = &result->row;
row->addRipple( row->addRipple(
e->pos() - QPoint(0, peerSearchOffset() + _peerSearchPressed * st::dialogsRowHeight), e->pos() - QPoint(0, peerSearchOffset() + _peerSearchPressed * st::dialogsRowHeight),
QSize(getFullWidth(), st::dialogsRowHeight), QSize(getFullWidth(), st::dialogsRowHeight),
[this, peer = result->peer] { updateSearchResult(peer); }); [this, peer = result->peer] { updateSearchResult(peer); });
} else if (_searchedPressed >= 0 && _searchedPressed < _searchResults.size()) { } else if (base::in_range(_searchedPressed, 0, _searchResults.size())) {
auto &row = _searchResults[_searchedPressed]; auto &row = _searchResults[_searchedPressed];
row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * st::dialogsRowHeight), QSize(getFullWidth(), st::dialogsRowHeight), [this, index = _searchedPressed] { row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * st::dialogsRowHeight), QSize(getFullWidth(), st::dialogsRowHeight), [this, index = _searchedPressed] {
rtlupdate(0, searchedOffset() + index * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); rtlupdate(0, searchedOffset() + index * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight);
@ -758,7 +768,7 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) {
} }
void DialogsInner::checkReorderPinnedStart(QPoint localPosition) { void DialogsInner::checkReorderPinnedStart(QPoint localPosition) {
if (_pressed != nullptr && !_dragging && _state == DefaultState) { if (_pressed != nullptr && !_dragging && _state == State::Default) {
if (qAbs(localPosition.y() - _dragStart.y()) >= convertScale(kStartReorderThreshold)) { if (qAbs(localPosition.y() - _dragStart.y()) >= convertScale(kStartReorderThreshold)) {
_dragging = _pressed; _dragging = _pressed;
if (updateReorderIndexGetCount() < 2) { if (updateReorderIndexGetCount() < 2) {
@ -946,7 +956,7 @@ void DialogsInner::step_pinnedShifting(TimeMs ms, bool timer) {
auto top = _dialogsImportant ? st::dialogsImportantBarHeight : 0; auto top = _dialogsImportant ? st::dialogsImportantBarHeight : 0;
auto updateFrom = top + st::dialogsRowHeight * (updateMin - 1); auto updateFrom = top + st::dialogsRowHeight * (updateMin - 1);
auto updateHeight = st::dialogsRowHeight * (updateMax - updateMin + 3); auto updateHeight = st::dialogsRowHeight * (updateMax - updateMin + 3);
if (_aboveIndex >= 0 && _aboveIndex < _pinnedRows.size()) { if (base::in_range(_aboveIndex, 0, _pinnedRows.size())) {
// Always include currently dragged chat in its current and old positions. // Always include currently dragged chat in its current and old positions.
auto aboveRowBottom = top + (_aboveIndex + 1) * st::dialogsRowHeight; auto aboveRowBottom = top + (_aboveIndex + 1) * st::dialogsRowHeight;
auto aboveTopShift = qCeil(_pinnedRows[_aboveIndex].yadd.current()); auto aboveTopShift = qCeil(_pinnedRows[_aboveIndex].yadd.current());
@ -1002,17 +1012,17 @@ void DialogsInner::mousePressReleased(Qt::MouseButton button) {
updateSelectedRow(); updateSelectedRow();
if (!wasDragging && button == Qt::LeftButton) { if (!wasDragging && button == Qt::LeftButton) {
if (importantSwitchPressed && importantSwitchPressed == _importantSwitchSelected) { if (importantSwitchPressed && importantSwitchPressed == _importantSwitchSelected) {
choosePeer(); chooseRow();
} else if (pressed && pressed == _selected) { } else if (pressed && pressed == _selected) {
choosePeer(); chooseRow();
} else if (hashtagPressed >= 0 && hashtagPressed == _hashtagSelected && hashtagDeletePressed == _hashtagDeleteSelected) { } else if (hashtagPressed >= 0 && hashtagPressed == _hashtagSelected && hashtagDeletePressed == _hashtagDeleteSelected) {
choosePeer(); chooseRow();
} else if (filteredPressed >= 0 && filteredPressed == _filteredSelected) { } else if (filteredPressed >= 0 && filteredPressed == _filteredSelected) {
choosePeer(); chooseRow();
} else if (peerSearchPressed >= 0 && peerSearchPressed == _peerSearchSelected) { } else if (peerSearchPressed >= 0 && peerSearchPressed == _peerSearchSelected) {
choosePeer(); chooseRow();
} else if (searchedPressed >= 0 && searchedPressed == _searchedSelected) { } else if (searchedPressed >= 0 && searchedPressed == _searchedSelected) {
choosePeer(); chooseRow();
} }
} }
} }
@ -1036,28 +1046,28 @@ void DialogsInner::setPressed(Dialogs::Row *pressed) {
} }
void DialogsInner::setHashtagPressed(int pressed) { void DialogsInner::setHashtagPressed(int pressed) {
if (_hashtagPressed >= 0 && _hashtagPressed < _hashtagResults.size()) { if (base::in_range(_hashtagPressed, 0, _hashtagResults.size())) {
_hashtagResults[_hashtagPressed]->row.stopLastRipple(); _hashtagResults[_hashtagPressed]->row.stopLastRipple();
} }
_hashtagPressed = pressed; _hashtagPressed = pressed;
} }
void DialogsInner::setFilteredPressed(int pressed) { void DialogsInner::setFilteredPressed(int pressed) {
if (_filteredPressed >= 0 && _filteredPressed < _filterResults.size()) { if (base::in_range(_filteredPressed, 0, _filterResults.size())) {
_filterResults[_filteredPressed]->stopLastRipple(); _filterResults[_filteredPressed]->stopLastRipple();
} }
_filteredPressed = pressed; _filteredPressed = pressed;
} }
void DialogsInner::setPeerSearchPressed(int pressed) { void DialogsInner::setPeerSearchPressed(int pressed) {
if (_peerSearchPressed >= 0 && _peerSearchPressed < _peerSearchResults.size()) { if (base::in_range(_peerSearchPressed, 0, _peerSearchResults.size())) {
_peerSearchResults[_peerSearchPressed]->row.stopLastRipple(); _peerSearchResults[_peerSearchPressed]->row.stopLastRipple();
} }
_peerSearchPressed = pressed; _peerSearchPressed = pressed;
} }
void DialogsInner::setSearchedPressed(int pressed) { void DialogsInner::setSearchedPressed(int pressed) {
if (_searchedPressed >= 0 && _searchedPressed < _searchResults.size()) { if (base::in_range(_searchedPressed, 0, _searchResults.size())) {
_searchResults[_searchedPressed]->stopLastRipple(); _searchResults[_searchedPressed]->stopLastRipple();
} }
_searchedPressed = pressed; _searchedPressed = pressed;
@ -1071,8 +1081,8 @@ void DialogsInner::resizeEvent(QResizeEvent *e) {
} }
void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) { void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) {
if (_state == FilteredState || _state == SearchedState) { if (_state == State::Filtered) {
for (FilteredDialogs::iterator i = _filterResults.begin(); i != _filterResults.end();) { for (auto i = _filterResults.begin(); i != _filterResults.end();) {
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts! if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
if (newRow) { if (newRow) {
*i = newRow; *i = newRow;
@ -1158,7 +1168,7 @@ void DialogsInner::createDialog(Dialogs::Key key) {
if (creating) { if (creating) {
refresh(); refresh();
} else if (_state == DefaultState && changed.movedFrom != changed.movedTo) { } else if (_state == State::Default && changed.movedFrom != changed.movedTo) {
update(0, qMin(from, to), getFullWidth(), qAbs(from - to) + st::dialogsRowHeight); update(0, qMin(from, to), getFullWidth(), qAbs(from - to) + st::dialogsRowHeight);
} }
} }
@ -1200,16 +1210,16 @@ void DialogsInner::removeDialog(Dialogs::Key key) {
void DialogsInner::dlgUpdated( void DialogsInner::dlgUpdated(
Dialogs::Mode list, Dialogs::Mode list,
not_null<Dialogs::Row*> row) { not_null<Dialogs::Row*> row) {
if (_state == DefaultState) { if (_state == State::Default) {
if (Global::DialogsMode() == list) { if (Global::DialogsMode() == list) {
auto position = row->pos(); auto position = row->pos();
auto top = dialogsOffset(); auto top = dialogsOffset();
if (position >= 0 && position < _pinnedRows.size()) { if (base::in_range(position, 0, _pinnedRows.size())) {
top += qRound(_pinnedRows[position].yadd.current()); top += qRound(_pinnedRows[position].yadd.current());
} }
update(0, top + position * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); update(0, top + position * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight);
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
if (list == Dialogs::Mode::All) { if (list == Dialogs::Mode::All) {
for (auto i = 0, l = _filterResults.size(); i != l; ++i) { for (auto i = 0, l = _filterResults.size(); i != l; ++i) {
if (_filterResults[i]->key() == row->key()) { if (_filterResults[i]->key() == row->key()) {
@ -1233,7 +1243,7 @@ void DialogsInner::dlgUpdated(not_null<History*> history, MsgId msgId) {
} }
void DialogsInner::updateSearchResult(not_null<PeerData*> peer) { void DialogsInner::updateSearchResult(not_null<PeerData*> peer) {
if (_state == FilteredState || _state == SearchedState) { if (_state == State::Filtered) {
if (!_peerSearchResults.empty()) { if (!_peerSearchResults.empty()) {
auto index = 0, add = peerSearchOffset(); auto index = 0, add = peerSearchOffset();
for_const (auto &result, _peerSearchResults) { for_const (auto &result, _peerSearchResults) {
@ -1255,18 +1265,18 @@ void DialogsInner::updateDialogRow(
auto updateRow = [this, updateRect](int rowTop) { auto updateRow = [this, updateRect](int rowTop) {
rtlupdate(updateRect.x(), rowTop + updateRect.y(), updateRect.width(), updateRect.height()); rtlupdate(updateRect.x(), rowTop + updateRect.y(), updateRect.width(), updateRect.height());
}; };
if (_state == DefaultState) { if (_state == State::Default) {
if (sections & UpdateRowSection::Default) { if (sections & UpdateRowSection::Default) {
if (const auto row = shownDialogs()->getRow(history)) { if (const auto row = shownDialogs()->getRow(history)) {
auto position = row->pos(); auto position = row->pos();
auto top = dialogsOffset(); auto top = dialogsOffset();
if (position >= 0 && position < _pinnedRows.size()) { if (base::in_range(position, 0, _pinnedRows.size())) {
top += qRound(_pinnedRows[position].yadd.current()); top += qRound(_pinnedRows[position].yadd.current());
} }
updateRow(top + position * st::dialogsRowHeight); updateRow(top + position * st::dialogsRowHeight);
} }
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
if ((sections & UpdateRowSection::Filtered) && !_filterResults.isEmpty()) { if ((sections & UpdateRowSection::Filtered) && !_filterResults.isEmpty()) {
auto index = 0, add = filteredOffset(); auto index = 0, add = filteredOffset();
for_const (auto row, _filterResults) { for_const (auto row, _filterResults) {
@ -1307,7 +1317,7 @@ void DialogsInner::enterEventHook(QEvent *e) {
} }
void DialogsInner::updateSelectedRow(Dialogs::Key key) { void DialogsInner::updateSelectedRow(Dialogs::Key key) {
if (_state == DefaultState) { if (_state == State::Default) {
if (key) { if (key) {
const auto entry = key.entry(); const auto entry = key.entry();
if (!entry->inChatList(Global::DialogsMode())) { if (!entry->inChatList(Global::DialogsMode())) {
@ -1315,7 +1325,7 @@ void DialogsInner::updateSelectedRow(Dialogs::Key key) {
} }
auto position = entry->posInChatList(Global::DialogsMode()); auto position = entry->posInChatList(Global::DialogsMode());
auto top = dialogsOffset(); auto top = dialogsOffset();
if (position >= 0 && position < _pinnedRows.size()) { if (base::in_range(position, 0, _pinnedRows.size())) {
top += qRound(_pinnedRows[position].yadd.current()); top += qRound(_pinnedRows[position].yadd.current());
} }
update(0, top + position * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); update(0, top + position * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight);
@ -1324,7 +1334,7 @@ void DialogsInner::updateSelectedRow(Dialogs::Key key) {
} else if (_importantSwitchSelected) { } else if (_importantSwitchSelected) {
update(0, 0, getFullWidth(), st::dialogsImportantBarHeight); update(0, 0, getFullWidth(), st::dialogsImportantBarHeight);
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
if (key) { if (key) {
for (auto i = 0, l = _filterResults.size(); i != l; ++i) { for (auto i = 0, l = _filterResults.size(); i != l; ++i) {
if (_filterResults[i]->key() == key) { if (_filterResults[i]->key() == key) {
@ -1356,7 +1366,12 @@ void DialogsInner::dragLeft() {
void DialogsInner::clearSelection() { void DialogsInner::clearSelection() {
_mouseSelection = false; _mouseSelection = false;
if (_importantSwitchSelected || _selected || _filteredSelected >= 0 || _hashtagSelected >= 0 || _peerSearchSelected >= 0 || _searchedSelected >= 0) { if (_importantSwitchSelected
|| _selected
|| _filteredSelected >= 0
|| _hashtagSelected >= 0
|| _peerSearchSelected >= 0
|| _searchedSelected >= 0) {
updateSelectedRow(); updateSelectedRow();
_importantSwitchSelected = false; _importantSwitchSelected = false;
_selected = nullptr; _selected = nullptr;
@ -1374,12 +1389,12 @@ void DialogsInner::contextMenuEvent(QContextMenuEvent *e) {
} }
const auto key = [&]() -> Dialogs::Key { const auto key = [&]() -> Dialogs::Key {
if (_state == DefaultState) { if (_state == State::Default) {
if (_selected) { if (_selected) {
return _selected->key(); return _selected->key();
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
if (_filteredSelected >= 0 && _filteredSelected < _filterResults.size()) { if (base::in_range(_filteredSelected, 0, _filterResults.size())) {
return _filterResults[_filteredSelected]->key(); return _filterResults[_filteredSelected]->key();
} }
} }
@ -1456,7 +1471,8 @@ void DialogsInner::onFilterUpdate(QString newFilter, bool force) {
} else { } else {
QStringList::const_iterator fb = words.cbegin(), fe = words.cend(), fi; QStringList::const_iterator fb = words.cbegin(), fe = words.cend(), fi;
_state = FilteredState; _state = State::Filtered;
_waitingForSearch = true;
_filterResults.clear(); _filterResults.clear();
if (!_searchInPeer && !words.isEmpty()) { if (!_searchInPeer && !words.isEmpty()) {
const Dialogs::List *toFilter = nullptr; const Dialogs::List *toFilter = nullptr;
@ -1536,7 +1552,7 @@ void DialogsInner::onFilterUpdate(QString newFilter, bool force) {
} }
setMouseSelection(false, true); setMouseSelection(false, true);
} }
if (_state != DefaultState) { if (_state != State::Default) {
emit searchMessages(); emit searchMessages();
} }
} }
@ -1592,14 +1608,14 @@ PeerData *DialogsInner::updateFromParentDrag(QPoint globalPos) {
} }
return nullptr; return nullptr;
}; };
if (_state == DefaultState) { if (_state == State::Default) {
return getPeerFromRow(_selected); return getPeerFromRow(_selected);
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
if (_filteredSelected >= 0 && _filteredSelected < _filterResults.size()) { if (base::in_range(_filteredSelected, 0, _filterResults.size())) {
return getPeerFromRow(_filterResults[_filteredSelected]); return getPeerFromRow(_filterResults[_filteredSelected]);
} else if (_peerSearchSelected >= 0 && _peerSearchSelected < _peerSearchResults.size()) { } else if (base::in_range(_peerSearchSelected, 0, _peerSearchResults.size())) {
return _peerSearchResults[_peerSearchSelected]->peer; return _peerSearchResults[_peerSearchSelected]->peer;
} else if (_searchedSelected >= 0 && _searchedSelected < _searchResults.size()) { } else if (base::in_range(_searchedSelected, 0, _searchResults.size())) {
return _searchResults[_searchedSelected]->item()->history()->peer; return _searchResults[_searchedSelected]->item()->history()->peer;
} }
} }
@ -1742,7 +1758,10 @@ void DialogsInner::addAllSavedPeers() {
addSavedPeersAfter(QDateTime()); addSavedPeersAfter(QDateTime());
} }
bool DialogsInner::searchReceived(const QVector<MTPMessage> &messages, DialogsSearchRequestType type, int32 fullCount) { bool DialogsInner::searchReceived(
const QVector<MTPMessage> &messages,
DialogsSearchRequestType type,
int32 fullCount) {
if (type == DialogsSearchFromStart || type == DialogsSearchPeerFromStart) { if (type == DialogsSearchFromStart || type == DialogsSearchPeerFromStart) {
clearSearchResults(false); clearSearchResults(false);
} }
@ -1780,8 +1799,12 @@ bool DialogsInner::searchReceived(const QVector<MTPMessage> &messages, DialogsSe
} else { } else {
_searchedCount = fullCount; _searchedCount = fullCount;
} }
if (_state == FilteredState && (!_searchResults.empty() || !_searchInMigrated || type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset)) { if (_waitingForSearch
_state = SearchedState; && (!_searchResults.empty()
|| !_searchInMigrated
|| type == DialogsSearchMigratedFromStart
|| type == DialogsSearchMigratedFromOffset)) {
_waitingForSearch = false;
} }
refresh(); refresh();
return lastDateFound != 0; return lastDateFound != 0;
@ -1871,7 +1894,7 @@ void DialogsInner::notify_historyMuteUpdated(History *history) {
if (creating) { if (creating) {
refresh(); refresh();
} else if (_state == DefaultState && changed.movedFrom != changed.movedTo) { } else if (_state == State::Default && changed.movedFrom != changed.movedTo) {
update(0, qMin(from, to), getFullWidth(), qAbs(from - to) + st::dialogsRowHeight); update(0, qMin(from, to), getFullWidth(), qAbs(from - to) + st::dialogsRowHeight);
} }
} }
@ -1879,7 +1902,7 @@ void DialogsInner::notify_historyMuteUpdated(History *history) {
void DialogsInner::refresh(bool toTop) { void DialogsInner::refresh(bool toTop) {
int32 h = 0; int32 h = 0;
if (_state == DefaultState) { if (_state == State::Default) {
if (shownDialogs()->isEmpty()) { if (shownDialogs()->isEmpty()) {
h = st::noContactsHeight; h = st::noContactsHeight;
if (Auth().data().contactsLoaded().value()) { if (Auth().data().contactsLoaded().value()) {
@ -1891,11 +1914,11 @@ void DialogsInner::refresh(bool toTop) {
h = dialogsOffset() + shownDialogs()->size() * st::dialogsRowHeight; h = dialogsOffset() + shownDialogs()->size() * st::dialogsRowHeight;
if (!_addContactLnk->isHidden()) _addContactLnk->hide(); if (!_addContactLnk->isHidden()) _addContactLnk->hide();
} }
} else { } else if (_state == State::Filtered) {
if (!_addContactLnk->isHidden()) _addContactLnk->hide(); if (!_addContactLnk->isHidden()) _addContactLnk->hide();
if (_state == FilteredState) { if (_waitingForSearch) {
h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight) + ((_searchResults.empty() && !_searchInPeer) ? -st::searchedBarHeight : 0); h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight) + ((_searchResults.empty() && !_searchInPeer) ? -st::searchedBarHeight : 0);
} else if (_state == SearchedState) { } else {
h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight); h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight);
} }
} }
@ -1912,30 +1935,19 @@ void DialogsInner::refresh(bool toTop) {
void DialogsInner::setMouseSelection(bool mouseSelection, bool toTop) { void DialogsInner::setMouseSelection(bool mouseSelection, bool toTop) {
_mouseSelection = mouseSelection; _mouseSelection = mouseSelection;
if (!_mouseSelection && toTop) { if (!_mouseSelection && toTop) {
if (_state == DefaultState) { if (_state == State::Default) {
_selected = nullptr; _selected = nullptr;
_importantSwitchSelected = false; _importantSwitchSelected = false;
} else if (_state == FilteredState || _state == SearchedState) { // don't select first elem in search } else if (_state == State::Filtered) {
_filteredSelected = _peerSearchSelected = _searchedSelected = _hashtagSelected = -1; _filteredSelected
setCursor(style::cur_default); = _peerSearchSelected
= _searchedSelected
= _hashtagSelected = -1;
} }
setCursor(style::cur_default);
} }
} }
void DialogsInner::setState(State newState) {
_state = newState;
clearIrrelevantState();
if (_state == DefaultState) {
clearSearchResults();
} else if (_state == FilteredState || _state == SearchedState) {
_hashtagResults.clear();
_hashtagSelected = -1;
_filterResults.clear();
_filteredSelected = -1;
}
onFilterUpdate(_filter, true);
}
DialogsInner::State DialogsInner::state() const { DialogsInner::State DialogsInner::state() const {
return _state; return _state;
} }
@ -1976,11 +1988,12 @@ void DialogsInner::searchInPeer(PeerData *peer, UserData *from) {
} }
void DialogsInner::clearFilter() { void DialogsInner::clearFilter() {
if (_state == FilteredState || _state == SearchedState || _searchInPeer) { if (_state == State::Filtered || _searchInPeer) {
if (_searchInPeer) { if (_searchInPeer) {
_state = FilteredState; _state = State::Filtered;
_waitingForSearch = true;
} else { } else {
_state = DefaultState; _state = State::Default;
} }
_hashtagResults.clear(); _hashtagResults.clear();
_filterResults.clear(); _filterResults.clear();
@ -1995,7 +2008,7 @@ void DialogsInner::clearFilter() {
} }
void DialogsInner::selectSkip(int32 direction) { void DialogsInner::selectSkip(int32 direction) {
if (_state == DefaultState) { if (_state == State::Default) {
if (_importantSwitchSelected) { if (_importantSwitchSelected) {
if (!shownDialogs()->isEmpty() && direction > 0) { if (!shownDialogs()->isEmpty() && direction > 0) {
_selected = *shownDialogs()->cbegin(); _selected = *shownDialogs()->cbegin();
@ -2029,7 +2042,7 @@ void DialogsInner::selectSkip(int32 direction) {
int fromY = _importantSwitchSelected ? 0 : (dialogsOffset() + _selected->pos() * st::dialogsRowHeight); int fromY = _importantSwitchSelected ? 0 : (dialogsOffset() + _selected->pos() * st::dialogsRowHeight);
emit mustScrollTo(fromY, fromY + st::dialogsRowHeight); emit mustScrollTo(fromY, fromY + st::dialogsRowHeight);
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
if (_hashtagResults.empty() && _filterResults.isEmpty() && _peerSearchResults.empty() && _searchResults.empty()) return; if (_hashtagResults.empty() && _filterResults.isEmpty() && _peerSearchResults.empty() && _searchResults.empty()) return;
if ((_hashtagSelected < 0 || _hashtagSelected >= _hashtagResults.size()) && if ((_hashtagSelected < 0 || _hashtagSelected >= _hashtagResults.size()) &&
(_filteredSelected < 0 || _filteredSelected >= _filterResults.size()) && (_filteredSelected < 0 || _filteredSelected >= _filterResults.size()) &&
@ -2045,7 +2058,13 @@ void DialogsInner::selectSkip(int32 direction) {
_hashtagSelected = 0; _hashtagSelected = 0;
} }
} else { } else {
int32 cur = (_hashtagSelected >= 0 && _hashtagSelected < _hashtagResults.size()) ? _hashtagSelected : ((_filteredSelected >= 0 && _filteredSelected < _filterResults.size()) ? (_hashtagResults.size() + _filteredSelected) : ((_peerSearchSelected >= 0 && _peerSearchSelected < _peerSearchResults.size()) ? (_peerSearchSelected + _filterResults.size() + _hashtagResults.size()) : (_searchedSelected + _peerSearchResults.size() + _filterResults.size() + _hashtagResults.size()))); int32 cur = base::in_range(_hashtagSelected, 0, _hashtagResults.size())
? _hashtagSelected
: (base::in_range(_filteredSelected, 0, _filterResults.size())
? (_hashtagResults.size() + _filteredSelected)
: (base::in_range(_peerSearchSelected, 0, _peerSearchResults.size())
? (_peerSearchSelected + _filterResults.size() + _hashtagResults.size())
: (_searchedSelected + _peerSearchResults.size() + _filterResults.size() + _hashtagResults.size())));
cur = snap(cur + direction, 0, static_cast<int>(_hashtagResults.size() + _filterResults.size() + _peerSearchResults.size() + _searchResults.size()) - 1); cur = snap(cur + direction, 0, static_cast<int>(_hashtagResults.size() + _filterResults.size() + _peerSearchResults.size() + _searchResults.size()) - 1);
if (cur < _hashtagResults.size()) { if (cur < _hashtagResults.size()) {
_hashtagSelected = cur; _hashtagSelected = cur;
@ -2061,11 +2080,11 @@ void DialogsInner::selectSkip(int32 direction) {
_searchedSelected = cur - _hashtagResults.size() - _filterResults.size() - _peerSearchResults.size(); _searchedSelected = cur - _hashtagResults.size() - _filterResults.size() - _peerSearchResults.size();
} }
} }
if (_hashtagSelected >= 0 && _hashtagSelected < _hashtagResults.size()) { if (base::in_range(_hashtagSelected, 0, _hashtagResults.size())) {
emit mustScrollTo(_hashtagSelected * st::mentionHeight, (_hashtagSelected + 1) * st::mentionHeight); emit mustScrollTo(_hashtagSelected * st::mentionHeight, (_hashtagSelected + 1) * st::mentionHeight);
} else if (_filteredSelected >= 0 && _filteredSelected < _filterResults.size()) { } else if (base::in_range(_filteredSelected, 0, _filterResults.size())) {
emit mustScrollTo(filteredOffset() + _filteredSelected * st::dialogsRowHeight, filteredOffset() + (_filteredSelected + 1) * st::dialogsRowHeight); emit mustScrollTo(filteredOffset() + _filteredSelected * st::dialogsRowHeight, filteredOffset() + (_filteredSelected + 1) * st::dialogsRowHeight);
} else if (_peerSearchSelected >= 0 && _peerSearchSelected < _peerSearchResults.size()) { } else if (base::in_range(_peerSearchSelected, 0, _peerSearchResults.size())) {
emit mustScrollTo(peerSearchOffset() + _peerSearchSelected * st::dialogsRowHeight + (_peerSearchSelected ? 0 : -st::searchedBarHeight), peerSearchOffset() + (_peerSearchSelected + 1) * st::dialogsRowHeight); emit mustScrollTo(peerSearchOffset() + _peerSearchSelected * st::dialogsRowHeight + (_peerSearchSelected ? 0 : -st::searchedBarHeight), peerSearchOffset() + (_peerSearchSelected + 1) * st::dialogsRowHeight);
} else { } else {
emit mustScrollTo(searchedOffset() + _searchedSelected * st::dialogsRowHeight + (_searchedSelected ? 0 : -st::searchedBarHeight), searchedOffset() + (_searchedSelected + 1) * st::dialogsRowHeight); emit mustScrollTo(searchedOffset() + _searchedSelected * st::dialogsRowHeight + (_searchedSelected ? 0 : -st::searchedBarHeight), searchedOffset() + (_searchedSelected + 1) * st::dialogsRowHeight);
@ -2076,11 +2095,11 @@ void DialogsInner::selectSkip(int32 direction) {
void DialogsInner::scrollToPeer(not_null<History*> history, MsgId msgId) { void DialogsInner::scrollToPeer(not_null<History*> history, MsgId msgId) {
int32 fromY = -1; int32 fromY = -1;
if (_state == DefaultState) { if (_state == State::Default) {
if (auto row = shownDialogs()->getRow(history)) { if (auto row = shownDialogs()->getRow(history)) {
fromY = dialogsOffset() + row->pos() * st::dialogsRowHeight; fromY = dialogsOffset() + row->pos() * st::dialogsRowHeight;
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
if (msgId) { if (msgId) {
for (int32 i = 0, c = _searchResults.size(); i < c; ++i) { for (int32 i = 0, c = _searchResults.size(); i < c; ++i) {
if (_searchResults[i]->item()->history() == history && _searchResults[i]->item()->id == msgId) { if (_searchResults[i]->item()->history() == history && _searchResults[i]->item()->id == msgId) {
@ -2105,7 +2124,7 @@ void DialogsInner::scrollToPeer(not_null<History*> history, MsgId msgId) {
void DialogsInner::selectSkipPage(int32 pixels, int32 direction) { void DialogsInner::selectSkipPage(int32 pixels, int32 direction) {
int toSkip = pixels / int(st::dialogsRowHeight); int toSkip = pixels / int(st::dialogsRowHeight);
if (_state == DefaultState) { if (_state == State::Default) {
if (!_selected) { if (!_selected) {
if (direction > 0 && !shownDialogs()->isEmpty()) { if (direction > 0 && !shownDialogs()->isEmpty()) {
_selected = *shownDialogs()->cbegin(); _selected = *shownDialogs()->cbegin();
@ -2143,7 +2162,7 @@ void DialogsInner::loadPeerPhotos() {
auto yFrom = _visibleTop; auto yFrom = _visibleTop;
auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1); auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1);
Auth().downloader().clearPriorities(); Auth().downloader().clearPriorities();
if (_state == DefaultState) { if (_state == State::Default) {
auto otherStart = shownDialogs()->size() * st::dialogsRowHeight; auto otherStart = shownDialogs()->size() * st::dialogsRowHeight;
if (yFrom < otherStart) { if (yFrom < otherStart) {
for (auto i = shownDialogs()->cfind(yFrom, st::dialogsRowHeight), end = shownDialogs()->cend(); i != end; ++i) { for (auto i = shownDialogs()->cfind(yFrom, st::dialogsRowHeight), end = shownDialogs()->cend(); i != end; ++i) {
@ -2157,7 +2176,7 @@ void DialogsInner::loadPeerPhotos() {
yFrom -= otherStart; yFrom -= otherStart;
} }
yTo -= otherStart; yTo -= otherStart;
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == State::Filtered) {
int32 from = (yFrom - filteredOffset()) / st::dialogsRowHeight; int32 from = (yFrom - filteredOffset()) / st::dialogsRowHeight;
if (from < 0) from = 0; if (from < 0) from = 0;
if (from < _filterResults.size()) { if (from < _filterResults.size()) {
@ -2192,71 +2211,115 @@ void DialogsInner::loadPeerPhotos() {
} }
} }
bool DialogsInner::choosePeer() { bool DialogsInner::switchImportantChats() {
History *history = nullptr; if (!_importantSwitchSelected
MsgId msgId = ShowAtUnreadMsgId; || !_dialogsImportant
if (_state == DefaultState) { || (_state != State::Default)) {
if (_importantSwitchSelected && _dialogsImportant) { return false;
clearSelection(); }
if (Global::DialogsMode() == Dialogs::Mode::All) { clearSelection();
Global::SetDialogsMode(Dialogs::Mode::Important); if (Global::DialogsMode() == Dialogs::Mode::All) {
} else { Global::SetDialogsMode(Dialogs::Mode::Important);
Global::SetDialogsMode(Dialogs::Mode::All); }
} else {
Local::writeUserSettings(); Global::SetDialogsMode(Dialogs::Mode::All);
refresh(); }
_importantSwitchSelected = true; Local::writeUserSettings();
return true; refresh();
} else if (_selected) { _importantSwitchSelected = true;
// #TODO feeds open return true;
history = _selected->history(); }
}
} else if (_state == FilteredState || _state == SearchedState) {
if (_hashtagSelected >= 0 && _hashtagSelected < _hashtagResults.size()) {
auto &hashtag = _hashtagResults[_hashtagSelected];
if (_hashtagDeleteSelected) {
RecentHashtagPack recent(cRecentSearchHashtags());
for (RecentHashtagPack::iterator i = recent.begin(); i != recent.cend();) {
if (i->first == hashtag->tag) {
i = recent.erase(i);
} else {
++i;
}
}
cSetRecentSearchHashtags(recent);
Local::writeRecentHashtagsAndBots();
emit refreshHashtags();
_mouseSelection = true; bool DialogsInner::chooseHashtag() {
updateSelected(); if (_state != State::Filtered) {
return false;
} else if ((_hashtagSelected < 0)
|| (_hashtagSelected >= _hashtagResults.size())) {
return false;
}
const auto &hashtag = _hashtagResults[_hashtagSelected];
if (_hashtagDeleteSelected) {
auto recent = cRecentSearchHashtags();
for (auto i = recent.begin(); i != recent.cend();) {
if (i->first == hashtag->tag) {
i = recent.erase(i);
} else { } else {
saveRecentHashtags('#' + hashtag->tag); ++i;
emit completeHashtag(hashtag->tag);
} }
return true;
} }
// #TODO feeds open cSetRecentSearchHashtags(recent);
if (_filteredSelected >= 0 && _filteredSelected < _filterResults.size()) { Local::writeRecentHashtagsAndBots();
history = _filterResults[_filteredSelected]->history(); emit refreshHashtags();
} else if (_peerSearchSelected >= 0 && _peerSearchSelected < _peerSearchResults.size()) {
history = App::history(_peerSearchResults[_peerSearchSelected]->peer->id); _mouseSelection = true;
} else if (_searchedSelected >= 0 && _searchedSelected < _searchResults.size()) { updateSelected();
history = _searchResults[_searchedSelected]->item()->history(); } else {
msgId = _searchResults[_searchedSelected]->item()->id; saveRecentHashtags('#' + hashtag->tag);
emit completeHashtag(hashtag->tag);
}
return true;
}
DialogsInner::ChosenRow DialogsInner::computeChosenRow() const {
auto msgId = ShowAtUnreadMsgId;
if (_state == State::Default) {
if (_selected) {
return {
_selected->key(),
ShowAtUnreadMsgId
};
}
} else if (_state == State::Filtered) {
if (base::in_range(_filteredSelected, 0, _filterResults.size())) {
return {
_filterResults[_filteredSelected]->key(),
ShowAtUnreadMsgId
};
} else if (base::in_range(_peerSearchSelected, 0, _peerSearchResults.size())) {
return {
App::history(_peerSearchResults[_peerSearchSelected]->peer),
ShowAtUnreadMsgId
};
} else if (base::in_range(_searchedSelected, 0, _searchResults.size())) {
return {
_searchResults[_searchedSelected]->item()->history(),
_searchResults[_searchedSelected]->item()->id
};
} }
} }
if (history) { return ChosenRow();
if (msgId > 0) { }
bool DialogsInner::chooseRow() {
if (switchImportantChats()) {
return true;
} else if (chooseHashtag()) {
return true;
}
const auto chosen = computeChosenRow();
if (chosen.key) {
if (chosen.messageId > 0) {
saveRecentHashtags(_filter); saveRecentHashtags(_filter);
} }
bool chosen = (!App::main()->selectingPeer(true) && (_state == FilteredState || _state == SearchedState) && _filteredSelected >= 0 && _filteredSelected < _filterResults.size()); const auto openSearchResult = !App::main()->selectingPeer(true)
App::main()->choosePeer(history->peer->id, msgId); && (_state == State::Filtered)
if (chosen) { && base::in_range(_filteredSelected, 0, _filterResults.size());
if (const auto history = chosen.key.history()) {
App::main()->choosePeer(history->peer->id, chosen.messageId);
} else if (const auto feed = chosen.key.feed()) {
// #TODO feeds open
// _controller->showSection(HistoryFeed::Memento(feed));
}
if (openSearchResult) {
emit searchResultChosen(); emit searchResultChosen();
} }
updateSelectedRow(); updateSelectedRow();
_selected = nullptr; _selected = nullptr;
_hashtagSelected = _filteredSelected = _peerSearchSelected = _searchedSelected = -1; _hashtagSelected
= _filteredSelected
= _peerSearchSelected
= _searchedSelected
= -1;
return true; return true;
} }
return false; return false;
@ -2313,7 +2376,7 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryBefore(
if (!which.key) { if (!which.key) {
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
if (_state == DefaultState) { if (_state == State::Default) {
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()) {
@ -2390,7 +2453,7 @@ Dialogs::RowDescriptor DialogsInner::chatListEntryAfter(
if (!which.key) { if (!which.key) {
return Dialogs::RowDescriptor(); return Dialogs::RowDescriptor();
} }
if (_state == DefaultState) { if (_state == State::Default) {
if (const auto row = shownDialogs()->getRow(which.key)) { if (const auto row = shownDialogs()->getRow(which.key)) {
const auto i = shownDialogs()->cfind(row) + 1; const auto i = shownDialogs()->cfind(row) + 1;
if (i != shownDialogs()->cend()) { if (i != shownDialogs()->cend()) {

View File

@ -55,7 +55,7 @@ public:
void clearFilter(); void clearFilter();
void refresh(bool toTop = false); void refresh(bool toTop = false);
bool choosePeer(); bool chooseRow();
void saveRecentHashtags(const QString &text); void saveRecentHashtags(const QString &text);
void destroyData(); void destroyData();
@ -78,13 +78,14 @@ public:
void setMouseSelection(bool mouseSelection, bool toTop = false); void setMouseSelection(bool mouseSelection, bool toTop = false);
enum State { enum class State {
DefaultState = 0, Default,
FilteredState = 1, Filtered,
SearchedState = 2,
}; };
void setState(State newState);
State state() const; State state() const;
bool waitingForSearch() const {
return _waitingForSearch;
}
bool hasFilteredResults() const; bool hasFilteredResults() const;
void searchInPeer(PeerData *peer, UserData *from); void searchInPeer(PeerData *peer, UserData *from);
@ -142,6 +143,14 @@ private:
struct PeerSearchResult; struct PeerSearchResult;
using PeerSearchResults = std::vector<std::unique_ptr<PeerSearchResult>>; using PeerSearchResults = std::vector<std::unique_ptr<PeerSearchResult>>;
struct ChosenRow {
Dialogs::Key key;
MsgId messageId = 0;
};
bool switchImportantChats();
bool chooseHashtag();
ChosenRow computeChosenRow() const;
void userIsContactUpdated(not_null<UserData*> user); void userIsContactUpdated(not_null<UserData*> user);
void mousePressReleased(Qt::MouseButton button); void mousePressReleased(Qt::MouseButton button);
void clearIrrelevantState(); void clearIrrelevantState();
@ -296,6 +305,8 @@ private:
int _filteredSelected = -1; int _filteredSelected = -1;
int _filteredPressed = -1; int _filteredPressed = -1;
bool _waitingForSearch = false;
QString _peerSearchQuery; QString _peerSearchQuery;
PeerSearchResults _peerSearchResults; PeerSearchResults _peerSearchResults;
int _peerSearchSelected = -1; int _peerSearchSelected = -1;
@ -312,7 +323,7 @@ private:
MsgId _lastSearchId = 0; MsgId _lastSearchId = 0;
MsgId _lastSearchMigratedId = 0; MsgId _lastSearchMigratedId = 0;
State _state = DefaultState; State _state = State::Default;
object_ptr<Ui::LinkButton> _addContactLnk; object_ptr<Ui::LinkButton> _addContactLnk;
object_ptr<Ui::IconButton> _cancelSearchInPeer; object_ptr<Ui::IconButton> _cancelSearchInPeer;

View File

@ -145,7 +145,12 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchMessages())); connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchMessages()));
_inner->setLoadMoreCallback([this] { _inner->setLoadMoreCallback([this] {
if (_inner->state() == DialogsInner::SearchedState || (_inner->state() == DialogsInner::FilteredState && _searchInMigrated && _searchFull && !_searchFullMigrated)) { using State = DialogsInner::State;
const auto state = _inner->state();
if (state == State::Filtered && (!_inner->waitingForSearch()
|| (_searchInMigrated
&& _searchFull
&& !_searchFullMigrated))) {
onSearchMore(); onSearchMore();
} else { } else {
loadDialogs(); loadDialogs();
@ -513,7 +518,7 @@ void DialogsWidget::onNeedSearchMessages() {
} }
void DialogsWidget::onChooseByDrag() { void DialogsWidget::onChooseByDrag() {
_inner->choosePeer(); _inner->chooseRow();
} }
void DialogsWidget::showMainMenu() { void DialogsWidget::showMainMenu() {
@ -595,7 +600,9 @@ void DialogsWidget::loadPinnedDialogs() {
} }
void DialogsWidget::searchReceived(DialogsSearchRequestType type, const MTPmessages_Messages &result, mtpRequestId req) { void DialogsWidget::searchReceived(DialogsSearchRequestType type, const MTPmessages_Messages &result, mtpRequestId req) {
if (_inner->state() == DialogsInner::FilteredState || _inner->state() == DialogsInner::SearchedState) { using State = DialogsInner::State;
const auto state = _inner->state();
if (state == State::Filtered) {
if (type == DialogsSearchFromStart || type == DialogsSearchPeerFromStart) { if (type == DialogsSearchFromStart || type == DialogsSearchPeerFromStart) {
auto i = _searchQueries.find(req); auto i = _searchQueries.find(req);
if (i != _searchQueries.cend()) { if (i != _searchQueries.cend()) {
@ -671,8 +678,10 @@ void DialogsWidget::searchReceived(DialogsSearchRequestType type, const MTPmessa
} }
void DialogsWidget::peerSearchReceived(const MTPcontacts_Found &result, mtpRequestId req) { void DialogsWidget::peerSearchReceived(const MTPcontacts_Found &result, mtpRequestId req) {
using State = DialogsInner::State;
const auto state = _inner->state();
auto q = _peerSearchQuery; auto q = _peerSearchQuery;
if (_inner->state() == DialogsInner::FilteredState || _inner->state() == DialogsInner::SearchedState) { if (state == State::Filtered) {
auto i = _peerSearchQueries.find(req); auto i = _peerSearchQueries.find(req);
if (i != _peerSearchQueries.cend()) { if (i != _peerSearchQueries.cend()) {
q = i.value(); q = i.value();
@ -1025,10 +1034,14 @@ void DialogsWidget::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) { if (e->key() == Qt::Key_Escape) {
e->ignore(); e->ignore();
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
if (!_inner->choosePeer()) { if (!_inner->chooseRow()) {
if (_inner->state() == DialogsInner::DefaultState || _inner->state() == DialogsInner::SearchedState || (_inner->state() == DialogsInner::FilteredState && _inner->hasFilteredResults())) { using State = DialogsInner::State;
const auto state = _inner->state();
if (state == State::Default
|| (state == State::Filtered
&& (!_inner->waitingForSearch() || _inner->hasFilteredResults()))) {
_inner->selectSkip(1); _inner->selectSkip(1);
_inner->choosePeer(); _inner->chooseRow();
} else { } else {
onSearchMessages(); onSearchMessages();
} }

View File

@ -285,7 +285,8 @@ public:
void gameUpdated(GameData *game); void gameUpdated(GameData *game);
void updateMutedIn(TimeMs delay); void updateMutedIn(TimeMs delay);
void choosePeer(PeerId peerId, MsgId showAtMsgId); // does offerPeer or showPeerHistory // Does offerPeer or showPeerHistory.
void choosePeer(PeerId peerId, MsgId showAtMsgId);
void clearBotStartToken(PeerData *peer); void clearBotStartToken(PeerData *peer);
void ptsWaiterStartTimerFor(ChannelData *channel, int32 ms); // ms <= 0 - stop timer void ptsWaiterStartTimerFor(ChannelData *channel, int32 ms); // ms <= 0 - stop timer

View File

@ -10,10 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Storage { namespace Storage {
SparseIdsList::Slice::Slice( SparseIdsList::Slice::Slice(
base::flat_set<MsgId> &&messages, base::flat_set<MsgId> &&messages,
MsgRange range) MsgRange range)
: messages(std::move(messages)) : messages(std::move(messages))
, range(range) { , range(range) {
} }
template <typename Range> template <typename Range>