Support dialog rows with variable height.

This commit is contained in:
John Preston 2022-11-11 10:23:23 +04:00
parent 248337daf5
commit 37308cde21
26 changed files with 600 additions and 401 deletions

View File

@ -386,7 +386,7 @@ void ApiWrap::checkChatInvite(
void ApiWrap::savePinnedOrder(Data::Folder *folder) {
const auto &order = _session->data().pinnedChatsOrder(folder);
const auto input = [](const Dialogs::Key &key) {
const auto input = [](Dialogs::Key key) {
if (const auto history = key.history()) {
return MTP_inputDialogPeer(history->peer->input);
} else if (const auto folder = key.folder()) {
@ -409,7 +409,7 @@ void ApiWrap::savePinnedOrder(Data::Folder *folder) {
void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
const auto &order = _session->data().pinnedChatsOrder(forum);
const auto input = [](const Dialogs::Key &key) {
const auto input = [](Dialogs::Key key) {
if (const auto topic = key.topic()) {
return MTP_int(topic->rootId().bare);
}

View File

@ -795,7 +795,9 @@ ShareBox::Inner::Chat *ShareBox::Inner::getChatAtIndex(int index) {
}
const auto row = [=] {
if (_filter.isEmpty()) {
return _chatsIndexed->rowAtY(index, 1);
return (index < _chatsIndexed->size())
? (_chatsIndexed->begin() + index)->get()
: nullptr;
}
return (index < _filtered.size())
? _filtered[index].get()
@ -865,9 +867,11 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) {
if (_filter.isEmpty()) {
if (!_chatsIndexed->empty()) {
auto i = _chatsIndexed->cfind(yFrom, _rowHeight);
const auto index = yFrom / _rowHeight;
auto i = _chatsIndexed->begin()
+ std::min(index, _chatsIndexed->size());;
for (auto end = _chatsIndexed->cend(); i != end; ++i) {
if (((*i)->pos() * _rowHeight) >= yTo) {
if (((*i)->index() * _rowHeight) >= yTo) {
break;
}
(*i)->entry()->loadUserpic();
@ -973,7 +977,8 @@ void ShareBox::Inner::paintEvent(QPaintEvent *e) {
auto indexTo = rowTo * _columnCount;
if (_filter.isEmpty()) {
if (!_chatsIndexed->empty()) {
auto i = _chatsIndexed->cfind(indexFrom, 1);
auto i = _chatsIndexed->begin()
+ std::min(indexFrom, _chatsIndexed->size());
for (auto end = _chatsIndexed->cend(); i != end; ++i) {
if (indexFrom >= indexTo) {
break;

View File

@ -1381,8 +1381,8 @@ void Session::setupUserIsContactViewer() {
_contactsNoChatsList.addByName(history);
}
} else if (const auto history = historyLoaded(user)) {
_contactsNoChatsList.del(history);
_contactsList.del(history);
_contactsNoChatsList.remove(history);
_contactsList.remove(history);
}
}, _lifetime);
}
@ -1915,7 +1915,7 @@ MessageIdsList Session::itemOrItsGroup(not_null<HistoryItem*> item) const {
}
void Session::setChatPinned(
const Dialogs::Key &key,
Dialogs::Key key,
FilterId filterId,
bool pinned) {
Expects(key.entry()->folderKnown());
@ -1927,7 +1927,7 @@ void Session::setChatPinned(
notifyPinnedDialogsOrderUpdated();
}
void Session::setPinnedFromEntryList(const Dialogs::Key &key, bool pinned) {
void Session::setPinnedFromEntryList(Dialogs::Key key, bool pinned) {
Expects(key.entry()->folderKnown());
const auto list = chatsListFor(key.entry())->pinned();
@ -2109,8 +2109,8 @@ void Session::clearPinnedChats(Data::Folder *folder) {
void Session::reorderTwoPinnedChats(
FilterId filterId,
const Dialogs::Key &key1,
const Dialogs::Key &key2) {
Dialogs::Key key1,
Dialogs::Key key2) {
Expects(key1.entry()->folderKnown() && key2.entry()->folderKnown());
Expects(filterId || (key1.entry()->folder() == key2.entry()->folder()));
@ -2510,14 +2510,14 @@ bool Session::unreadBadgeMuted() const {
return computeUnreadBadgeMuted(_chatsList.unreadState());
}
int Session::unreadBadgeIgnoreOne(const Dialogs::Key &key) const {
int Session::unreadBadgeIgnoreOne(Dialogs::Key key) const {
const auto remove = (key && key.entry()->inChatList())
? key.entry()->chatListUnreadState()
: Dialogs::UnreadState();
return computeUnreadBadge(_chatsList.unreadState() - remove);
}
bool Session::unreadBadgeMutedIgnoreOne(const Dialogs::Key &key) const {
bool Session::unreadBadgeMutedIgnoreOne(Dialogs::Key key) const {
if (!Core::App().settings().includeMutedCounter()) {
return false;
}
@ -3997,7 +3997,7 @@ void Session::refreshChatListEntry(Dialogs::Key key) {
return;
} else if (event.existenceChanged) {
const auto mainRow = entry->addToChatList(0, mainList);
_contactsNoChatsList.del(key, mainRow);
_contactsNoChatsList.remove(key, mainRow);
} else {
event.moved = entry->adjustByPosInChatList(0, mainList);
}

View File

@ -363,11 +363,8 @@ public:
not_null<Forum*> forum) const;
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
FilterId filterId) const;
void setChatPinned(
const Dialogs::Key &key,
FilterId filterId,
bool pinned);
void setPinnedFromEntryList(const Dialogs::Key &key, bool pinned);
void setChatPinned(Dialogs::Key key, FilterId filterId, bool pinned);
void setPinnedFromEntryList(Dialogs::Key key, bool pinned);
void clearPinnedChats(Folder *folder);
void applyPinnedChats(
Folder *folder,
@ -377,8 +374,8 @@ public:
const QVector<MTPint> &list);
void reorderTwoPinnedChats(
FilterId filterId,
const Dialogs::Key &key1,
const Dialogs::Key &key2);
Dialogs::Key key1,
Dialogs::Key key2);
void setSuggestToGigagroup(not_null<ChannelData*> group, bool suggest);
[[nodiscard]] bool suggestToGigagroup(
@ -474,9 +471,8 @@ public:
[[nodiscard]] int unreadBadge() const;
[[nodiscard]] bool unreadBadgeMuted() const;
[[nodiscard]] int unreadBadgeIgnoreOne(const Dialogs::Key &key) const;
[[nodiscard]] bool unreadBadgeMutedIgnoreOne(
const Dialogs::Key &key) const;
[[nodiscard]] int unreadBadgeIgnoreOne(Dialogs::Key key) const;
[[nodiscard]] bool unreadBadgeMutedIgnoreOne(Dialogs::Key key) const;
[[nodiscard]] int unreadOnlyMutedBadge() const;
[[nodiscard]] rpl::producer<> unreadBadgeChanges() const;
void notifyUnreadBadgeChanged();

View File

@ -71,6 +71,9 @@ defaultDialogRow: DialogRow {
textLeft: 68px;
textTop: 34px;
}
forumDialogRow: DialogRow {
height: 80px;
}
dialogsOnlineBadgeStroke: 2px;
dialogsOnlineBadgeSize: 10px;

View File

@ -300,10 +300,10 @@ PositionChange Entry::adjustByPosInChatList(
not_null<MainList*> list) {
const auto links = chatListLinks(filterId);
Assert(links != nullptr);
const auto from = links->main->pos();
const auto from = links->main->top();
list->indexed()->adjustByDate(*links);
const auto to = links->main->pos();
return { from, to };
const auto to = links->main->top();
return { .from = from, .to = to, .height = links->main->height() };
}
void Entry::setChatListTimeId(TimeId date) {
@ -315,7 +315,7 @@ void Entry::setChatListTimeId(TimeId date) {
}
int Entry::posInChatList(FilterId filterId) const {
return mainChatListLink(filterId)->pos();
return mainChatListLink(filterId)->index();
}
not_null<Row*> Entry::addToChatList(

View File

@ -56,6 +56,7 @@ enum class SortMode {
struct PositionChange {
int from = -1;
int to = -1;
int height = 0;
};
struct UnreadState {

View File

@ -134,7 +134,7 @@ void IndexedList::adjustByName(
}
for (auto ch : toRemove) {
if (auto it = _index.find(ch); it != _index.cend()) {
it->second.del(key, mainRow);
it->second.remove(key, mainRow);
}
}
if (!toAdd.empty()) {
@ -171,7 +171,7 @@ void IndexedList::adjustNames(
history->removeChatListEntryByLetter(filterId, ch);
}
if (auto it = _index.find(ch); it != _index.cend()) {
it->second.del(key, mainRow);
it->second.remove(key, mainRow);
}
}
for (auto ch : toAdd) {
@ -186,11 +186,11 @@ void IndexedList::adjustNames(
}
}
void IndexedList::del(Key key, Row *replacedBy) {
if (_list.del(key, replacedBy)) {
void IndexedList::remove(Key key, Row *replacedBy) {
if (_list.remove(key, replacedBy)) {
for (const auto &ch : key.entry()->chatListFirstLetters()) {
if (auto it = _index.find(ch); it != _index.cend()) {
it->second.del(key, replacedBy);
if (const auto it = _index.find(ch); it != _index.cend()) {
it->second.remove(key, replacedBy);
}
}
}

View File

@ -37,39 +37,48 @@ public:
not_null<PeerData*> peer,
const base::flat_set<QChar> &oldChars);
void del(Key key, Row *replacedBy = nullptr);
void remove(Key key, Row *replacedBy = nullptr);
void clear();
const List &all() const {
[[nodiscard]] const List &all() const {
return _list;
}
const List *filtered(QChar ch) const {
[[nodiscard]] const List *filtered(QChar ch) const {
const auto i = _index.find(ch);
return (i != _index.end()) ? &i->second : nullptr;
}
std::vector<not_null<Row*>> filtered(const QStringList &words) const;
[[nodiscard]] std::vector<not_null<Row*>> filtered(
const QStringList &words) const;
// Part of List interface is duplicated here for all() list.
int size() const { return all().size(); }
bool empty() const { return all().empty(); }
bool contains(Key key) const { return all().contains(key); }
Row *getRow(Key key) const { return all().getRow(key); }
Row *rowAtY(int32 y, int32 h) const { return all().rowAtY(y, h); }
[[nodiscard]] int size() const { return all().size(); }
[[nodiscard]] bool empty() const { return all().empty(); }
[[nodiscard]] int height() const { return all().height(); }
[[nodiscard]] bool contains(Key key) const {
return all().contains(key);
}
[[nodiscard]] Row *getRow(Key key) const { return all().getRow(key); }
[[nodiscard]] Row *rowAtY(int y) const { return all().rowAtY(y); }
using iterator = List::iterator;
using const_iterator = List::const_iterator;
const_iterator cbegin() const { return all().cbegin(); }
const_iterator cend() const { return all().cend(); }
const_iterator begin() const { return all().cbegin(); }
const_iterator end() const { return all().cend(); }
iterator begin() { return all().begin(); }
iterator end() { return all().end(); }
const_iterator cfind(Row *value) const { return all().cfind(value); }
const_iterator find(Row *value) const { return all().cfind(value); }
iterator find(Row *value) { return all().find(value); }
const_iterator cfind(int y, int h) const { return all().cfind(y, h); }
const_iterator find(int y, int h) const { return all().cfind(y, h); }
iterator find(int y, int h) { return all().find(y, h); }
[[nodiscard]] const_iterator cbegin() const { return all().cbegin(); }
[[nodiscard]] const_iterator cend() const { return all().cend(); }
[[nodiscard]] const_iterator begin() const { return all().cbegin(); }
[[nodiscard]] const_iterator end() const { return all().cend(); }
[[nodiscard]] iterator begin() { return all().begin(); }
[[nodiscard]] iterator end() { return all().end(); }
[[nodiscard]] const_iterator cfind(Row *value) const {
return all().cfind(value);
}
[[nodiscard]] const_iterator find(Row *value) const {
return all().cfind(value);
}
[[nodiscard]] iterator find(Row *value) { return all().find(value); }
[[nodiscard]] const_iterator findByY(int y) const {
return all().findByY(y);
}
[[nodiscard]] iterator findByY(int y) { return all().findByY(y); }
private:
void adjustByName(

File diff suppressed because it is too large Load Diff

View File

@ -192,6 +192,19 @@ private:
EmptyForum,
};
struct PinnedRow {
anim::value yadd;
crl::time animStartTime = 0;
};
struct FilterResult {
not_null<Row*> row;
int top = 0;
[[nodiscard]] Key key() const;
[[nodiscard]] int bottom() const;
};
Main::Session &session() const;
void dialogRowReplaced(Row *oldRow, Row *newRow);
@ -220,6 +233,8 @@ private:
void clearIrrelevantState();
void selectByMouse(QPoint globalPosition);
void loadPeerPhotos();
void scrollToItem(int top, int height);
void scrollToDefaultSelected();
void setCollapsedPressed(int pressed);
void setPressed(Row *pressed);
void setHashtagPressed(int pressed);
@ -283,13 +298,18 @@ private:
void fillSupportSearchMenu(not_null<Ui::PopupMenu*> menu);
void fillArchiveSearchMenu(not_null<Ui::PopupMenu*> menu);
int dialogsOffset() const;
int fixedOnTopCount() const;
int pinnedOffset() const;
int filteredOffset() const;
int peerSearchOffset() const;
int searchedOffset() const;
int searchInChatSkip() const;
void refreshShownList();
[[nodiscard]] int skipTopHeight() const;
[[nodiscard]] int dialogsOffset() const;
[[nodiscard]] int shownHeight(int till = -1) const;
[[nodiscard]] int fixedOnTopCount() const;
[[nodiscard]] int pinnedOffset() const;
[[nodiscard]] int filteredOffset() const;
[[nodiscard]] int filteredIndex(int y) const;
[[nodiscard]] int filteredHeight(int till = -1) const;
[[nodiscard]] int peerSearchOffset() const;
[[nodiscard]] int searchedOffset() const;
[[nodiscard]] int searchInChatSkip() const;
void paintCollapsedRows(
Painter &p,
@ -339,13 +359,12 @@ private:
Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row);
Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history);
Row *shownRowByKey(Key key);
void clearSearchResults(bool clearPeerSearchResults = true);
void updateSelectedRow(Key key = Key());
void trackSearchResultsHistory(not_null<History*> history);
void trackSearchResultsForum(Data::Forum *forum);
[[nodiscard]] not_null<IndexedList*> shownDialogs() const;
[[nodiscard]] const std::vector<Key> &pinnedChatsOrder() const;
void checkReorderPinnedStart(QPoint localPosition);
int updateReorderIndexGetCount();
@ -363,6 +382,7 @@ private:
const not_null<Window::SessionController*> _controller;
not_null<IndexedList*> _shownList;
FilterId _filterId = 0;
bool _mouseSelection = false;
std::optional<QPoint> _lastMousePosition;
@ -376,7 +396,7 @@ private:
not_null<const style::DialogRow*> _st;
int _collapsedSelected = -1;
int _collapsedPressed = -1;
int _skipTopDialogs = 0;
bool _skipTopDialog = false;
Row *_selected = nullptr;
Row *_pressed = nullptr;
@ -384,10 +404,6 @@ private:
int _draggingIndex = -1;
int _aboveIndex = -1;
QPoint _dragStart;
struct PinnedRow {
anim::value yadd;
crl::time animStartTime = 0;
};
std::vector<PinnedRow> _pinnedRows;
Ui::Animations::Basic _pinnedShiftAnimation;
base::flat_set<Key> _pinnedOnDragStart;
@ -405,7 +421,7 @@ private:
bool _hashtagDeleteSelected = false;
bool _hashtagDeletePressed = false;
std::vector<not_null<Row*>> _filterResults;
std::vector<FilterResult> _filterResults;
base::flat_map<Key, std::unique_ptr<Row>> _filterResultsGlobal;
int _filteredSelected = -1;
int _filteredPressed = -1;

View File

@ -39,13 +39,13 @@ public:
explicit operator bool() const {
return (_value != nullptr);
}
not_null<Entry*> entry() const;
History *history() const;
Data::Folder *folder() const;
Data::ForumTopic *topic() const;
Data::Thread *thread() const;
History *owningHistory() const;
PeerData *peer() const;
[[nodiscard]] not_null<Entry*> entry() const;
[[nodiscard]] History *history() const;
[[nodiscard]] Data::Folder *folder() const;
[[nodiscard]] Data::ForumTopic *topic() const;
[[nodiscard]] Data::Thread *thread() const;
[[nodiscard]] History *owningHistory() const;
[[nodiscard]] PeerData *peer() const;
friend inline constexpr auto operator<=>(Key, Key) noexcept = default;

View File

@ -21,7 +21,7 @@ List::List(SortMode sortMode, FilterId filterId)
List::const_iterator List::cfind(Row *value) const {
return value
? (cbegin() + value->pos())
? (cbegin() + value->index())
: cend();
}
@ -31,7 +31,7 @@ not_null<Row*> List::addToEnd(Key key) {
}
const auto result = _rowByKey.emplace(
key,
std::make_unique<Row>(key, _rows.size())
std::make_unique<Row>(key, _rows.size(), height())
).first->second.get();
_rows.emplace_back(result);
if (_sortMode == SortMode::Date) {
@ -60,10 +60,10 @@ not_null<Row*> List::addByName(Key key) {
}
void List::adjustByName(not_null<Row*> row) {
Expects(row->pos() >= 0 && row->pos() < _rows.size());
Expects(row->index() >= 0 && row->index() < _rows.size());
const auto &key = row->entry()->chatListNameSortKey();
const auto index = row->pos();
const auto index = row->index();
const auto i = _rows.begin() + index;
const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
return row->entry()->chatListNameSortKey().compare(key) >= 0;
@ -85,7 +85,7 @@ void List::adjustByDate(not_null<Row*> row) {
Expects(_sortMode == SortMode::Date);
const auto key = row->sortKey(_filterId);
const auto index = row->pos();
const auto index = row->index();
const auto i = _rows.begin() + index;
const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
return (row->sortKey(_filterId) <= key);
@ -108,7 +108,7 @@ bool List::moveToTop(Key key) {
if (i == _rowByKey.cend()) {
return false;
}
const auto index = i->second->pos();
const auto index = i->second->index();
const auto begin = _rows.begin();
rotate(begin, begin + index, begin + index + 1);
return true;
@ -118,16 +118,20 @@ void List::rotate(
std::vector<not_null<Row*>>::iterator first,
std::vector<not_null<Row*>>::iterator middle,
std::vector<not_null<Row*>>::iterator last) {
auto top = (*first)->top();
std::rotate(first, middle, last);
auto count = (last - first);
auto index = (first - _rows.begin());
while (count--) {
(*first++)->_pos = index++;
const auto row = *first++;
row->_index = index++;
row->_top = top;
top += row->height();
}
}
bool List::del(Key key, Row *replacedBy) {
bool List::remove(Key key, Row *replacedBy) {
auto i = _rowByKey.find(key);
if (i == _rowByKey.cend()) {
return false;
@ -136,13 +140,34 @@ bool List::del(Key key, Row *replacedBy) {
const auto row = i->second.get();
row->entry()->owner().dialogsRowReplaced({ row, replacedBy });
const auto index = row->pos();
auto top = row->top();
const auto index = row->index();
_rows.erase(_rows.begin() + index);
for (auto i = index, count = int(_rows.size()); i != count; ++i) {
_rows[i]->_pos = i;
const auto row = _rows[i];
row->_index = i;
row->_top = top;
top += row->height();
}
_rowByKey.erase(i);
return true;
}
Row *List::rowAtY(int y) const {
const auto i = findByY(y);
if (i == cend()) {
return nullptr;
}
const auto row = *i;
const auto top = row->top();
const auto bottom = top + row->height();
return (top <= y && bottom > y) ? row.get() : nullptr;
}
List::const_iterator List::findByY(int y) const {
return ranges::lower_bound(_rows, y, ranges::less(), [](const Row *row) {
return row->top() + row->height();
});
}
} // namespace Dialogs

View File

@ -23,52 +23,49 @@ public:
List &operator=(List &&other) = default;
~List() = default;
int size() const {
[[nodiscard]] int size() const {
return _rows.size();
}
bool empty() const {
[[nodiscard]] bool empty() const {
return _rows.empty();
}
bool contains(Key key) const {
[[nodiscard]] int height() const {
return _rows.empty()
? 0
: (_rows.back()->top() + _rows.back()->height());
}
[[nodiscard]] bool contains(Key key) const {
return _rowByKey.find(key) != _rowByKey.end();
}
Row *getRow(Key key) const {
[[nodiscard]] Row *getRow(Key key) const {
const auto i = _rowByKey.find(key);
return (i != _rowByKey.end()) ? i->second.get() : nullptr;
}
Row *rowAtY(int y, int h) const {
const auto i = cfind(y, h);
if (i == cend() || (*i)->pos() != ((y > 0) ? (y / h) : 0)) {
return nullptr;
}
return *i;
}
[[nodiscard]] Row *rowAtY(int y) const;
not_null<Row*> addToEnd(Key key);
Row *adjustByName(Key key);
not_null<Row*> addByName(Key key);
bool moveToTop(Key key);
void adjustByDate(not_null<Row*> row);
bool del(Key key, Row *replacedBy = nullptr);
bool remove(Key key, Row *replacedBy = nullptr);
using const_iterator = std::vector<not_null<Row*>>::const_iterator;
using iterator = const_iterator;
const_iterator cbegin() const { return _rows.cbegin(); }
const_iterator cend() const { return _rows.cend(); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
iterator begin() { return cbegin(); }
iterator end() { return cend(); }
const_iterator cfind(Row *value) const;
const_iterator find(Row *value) const { return cfind(value); }
iterator find(Row *value) { return cfind(value); }
const_iterator cfind(int y, int h) const {
const auto index = std::max(y, 0) / h;
return _rows.begin() + std::min(index, size());
[[nodiscard]] const_iterator cbegin() const { return _rows.cbegin(); }
[[nodiscard]] const_iterator cend() const { return _rows.cend(); }
[[nodiscard]] const_iterator begin() const { return cbegin(); }
[[nodiscard]] const_iterator end() const { return cend(); }
[[nodiscard]] iterator begin() { return cbegin(); }
[[nodiscard]] iterator end() { return cend(); }
[[nodiscard]] const_iterator cfind(Row *value) const;
[[nodiscard]] const_iterator find(Row *value) const {
return cfind(value);
}
const_iterator find(int y, int h) const { return cfind(y, h); }
iterator find(int y, int h) { return cfind(y, h); }
[[nodiscard]] iterator find(Row *value) { return cfind(value); }
[[nodiscard]] const_iterator findByY(int y) const;
[[nodiscard]] iterator findByY(int y) { return findByY(y); }
private:
void adjustByName(not_null<Row*> row);

View File

@ -89,7 +89,7 @@ void MainList::clear() {
_cloudListSize = 0;
}
RowsByLetter MainList::addEntry(const Key &key) {
RowsByLetter MainList::addEntry(Key key) {
const auto result = _all.addToEnd(key);
const auto unread = key.entry()->chatListUnreadState();
@ -99,8 +99,8 @@ RowsByLetter MainList::addEntry(const Key &key) {
return result;
}
void MainList::removeEntry(const Key &key) {
_all.del(key);
void MainList::removeEntry(Key key) {
_all.remove(key);
const auto unread = key.entry()->chatListUnreadState();
unreadEntryChanged(unread, false);

View File

@ -33,8 +33,8 @@ public:
void setAllAreMuted(bool allAreMuted = true);
void clear();
RowsByLetter addEntry(const Key &key);
void removeEntry(const Key &key);
RowsByLetter addEntry(Key key);
void removeEntry(Key key);
void unreadStateChanged(
const UnreadState &wasState,

View File

@ -31,13 +31,13 @@ void PinnedList::setLimit(int limit) {
applyLimit(_limit);
}
void PinnedList::addPinned(const Key &key) {
void PinnedList::addPinned(Key key) {
Expects(key.entry()->folderKnown());
addPinnedGetPosition(key);
}
int PinnedList::addPinnedGetPosition(const Key &key) {
int PinnedList::addPinnedGetPosition(Key key) {
const auto already = ranges::find(_data, key);
if (already != end(_data)) {
return already - begin(_data);
@ -49,7 +49,7 @@ int PinnedList::addPinnedGetPosition(const Key &key) {
return position;
}
void PinnedList::setPinned(const Key &key, bool pinned) {
void PinnedList::setPinned(Key key, bool pinned) {
Expects(key.entry()->folderKnown() || _filterId != 0);
if (pinned) {
@ -128,7 +128,7 @@ void PinnedList::applyList(const std::vector<not_null<History*>> &list) {
}
}
void PinnedList::reorder(const Key &key1, const Key &key2) {
void PinnedList::reorder(Key key1, Key key2) {
const auto index1 = ranges::find(_data, key1) - begin(_data);
const auto index2 = ranges::find(_data, key2) - begin(_data);
Assert(index1 >= 0 && index1 < _data.size());

View File

@ -26,10 +26,10 @@ public:
// Places on the last place in the list otherwise.
// Does nothing if already pinned.
void addPinned(const Key &key);
void addPinned(Key key);
// if (pinned) places on the first place in the list.
void setPinned(const Key &key, bool pinned);
void setPinned(Key key, bool pinned);
void clear();
@ -40,14 +40,14 @@ public:
not_null<Data::Forum*> forum,
const QVector<MTPint> &list);
void applyList(const std::vector<not_null<History*>> &list);
void reorder(const Key &key1, const Key &key2);
void reorder(Key key1, Key key2);
const std::vector<Key> &order() const {
return _data;
}
private:
int addPinnedGetPosition(const Key &key);
int addPinnedGetPosition(Key key);
void applyLimit(int limit);
FilterId _filterId = 0;

View File

@ -143,9 +143,14 @@ void BasicRow::paintUserpic(
context.paused);
}
Row::Row(Key key, int pos) : _id(key), _pos(pos) {
Row::Row(Key key, int index, int top) : _id(key), _top(top), _index(index) {
if (const auto history = key.history()) {
updateCornerBadgeShown(history->peer);
_height = history->peer->isForum()
? st::forumDialogRow.height
: st::defaultDialogRow.height;
} else {
_height = st::forumTopicRow.height;
}
}
@ -173,10 +178,11 @@ void Row::validateListEntryCache() const {
void Row::setCornerBadgeShown(
bool shown,
Fn<void()> updateCallback) const {
if (_cornerBadgeShown == shown) {
const auto value = shown ? 1 : 0;
if (_cornerBadgeShown == value) {
return;
}
_cornerBadgeShown = shown;
_cornerBadgeShown = value;
if (_cornerBadgeUserpic && _cornerBadgeUserpic->animation.animating()) {
_cornerBadgeUserpic->animation.change(
_cornerBadgeShown ? 1. : 0.,

View File

@ -16,6 +16,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History;
class HistoryItem;
namespace style {
struct DialogRow;
} // namespace style
namespace Data {
class CloudImageView;
} // namespace Data
@ -57,7 +61,8 @@ public:
int outerWidth,
const QColor *colorOverride = nullptr) const;
std::shared_ptr<Data::CloudImageView> &userpicView() const {
[[nodiscard]] auto userpicView() const
-> std::shared_ptr<Data::CloudImageView> & {
return _userpic;
}
@ -68,11 +73,18 @@ private:
};
class List;
class Row : public BasicRow {
class Row final : public BasicRow {
public:
explicit Row(std::nullptr_t) {
}
Row(Key key, int pos);
Row(Key key, int index, int top);
[[nodiscard]] int top() const {
return _top;
}
[[nodiscard]] int height() const {
return _height;
}
void updateCornerBadgeShown(
not_null<PeerData*> peer,
@ -102,8 +114,8 @@ public:
[[nodiscard]] not_null<Entry*> entry() const {
return _id.entry();
}
[[nodiscard]] int pos() const {
return _pos;
[[nodiscard]] int index() const {
return _index;
}
[[nodiscard]] uint64 sortKey(FilterId filterId) const;
@ -139,11 +151,13 @@ private:
const Ui::PaintContext &context);
Key _id;
int _pos = 0;
mutable uint32 _listEntryCacheVersion = 0;
mutable Ui::Text::String _listEntryCache;
mutable std::unique_ptr<CornerBadgeUserpic> _cornerBadgeUserpic;
mutable bool _cornerBadgeShown = false;
int _top = 0;
int _height = 0;
int _index = 0;
mutable int _listEntryCacheVersion : 31 = 0;
mutable int _cornerBadgeShown : 1 = 0;
};

View File

@ -245,6 +245,7 @@ template <typename PaintItemCallback>
void PaintRow(
Painter &p,
not_null<const BasicRow*> row,
QRect geometry,
not_null<Entry*> entry,
VideoUserpic *videoUserpic,
PeerData *from,
@ -264,7 +265,6 @@ void PaintRow(
draft = nullptr;
}
auto fullRect = QRect(0, 0, context.width, context.st->height);
auto bg = context.active
? st::dialogsBgActive
: context.selected
@ -273,7 +273,7 @@ void PaintRow(
auto ripple = context.active
? st::dialogsRippleBgActive
: st::dialogsRippleBg;
p.fillRect(fullRect, bg);
p.fillRect(geometry, bg);
row->paintRipple(p, 0, 0, context.width, &ripple->c);
const auto history = entry->asHistory();
@ -932,6 +932,7 @@ void RowPainter::Paint(
PaintRow(
p,
row,
QRect(0, 0, context.width, row->height()),
entry,
videoUserpic,
from,
@ -1029,6 +1030,7 @@ void RowPainter::Paint(
PaintRow(
p,
row,
QRect(0, 0, context.width, context.st->height),
entry,
nullptr,
from,

View File

@ -205,7 +205,7 @@ base::options::toggle AutoScrollInactiveChat({
[[nodiscard]] rpl::producer<PeerData*> ActivePeerValue(
not_null<Window::SessionController*> controller) {
return controller->activeChatValue(
) | rpl::map([](const Dialogs::Key &key) {
) | rpl::map([](Dialogs::Key key) {
const auto history = key.history();
return history ? history->peer.get() : nullptr;
});
@ -2530,7 +2530,7 @@ void HistoryWidget::refreshSilentToggle() {
void HistoryWidget::setupScheduledToggle() {
controller()->activeChatValue(
) | rpl::map([=](const Dialogs::Key &key) -> rpl::producer<> {
) | rpl::map([=](Dialogs::Key key) -> rpl::producer<> {
if (const auto history = key.history()) {
return session().data().scheduledMessages().updates(history);
}

View File

@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/delete_messages_box.h"
#include "boxes/premium_preview_box.h"
#include "boxes/peers/edit_participant_box.h"
#include "core/crash_reports.h"
#include "data/data_session.h"
#include "data/data_sponsored_messages.h"
#include "data/data_changes.h"
@ -136,7 +137,10 @@ void ListWidget::enumerateItems(Method method) {
if (TopToBottom) {
Assert(itemTop(from->get()) + from->get()->height() > _visibleTop);
} else {
Assert(itemTop(from->get()) < _visibleBottom);
if (itemTop(from->get()) >= _visibleBottom) {
setGeometryCrashAnnotations(*from);
Unexpected("itemTop(from->get()) >= _visibleBottom");
}
}
while (true) {
@ -148,7 +152,10 @@ void ListWidget::enumerateItems(Method method) {
if (TopToBottom) {
Assert(itembottom > _visibleTop);
} else {
Assert(itemtop < _visibleBottom);
if (itemtop >= _visibleBottom) {
setGeometryCrashAnnotations(view);
Unexpected("itemtop >= _visibleBottom");
}
}
if (!method(view, itemtop, itembottom)) {
@ -441,6 +448,39 @@ void ListWidget::refreshViewer() {
}, _viewerLifetime);
}
void ListWidget::setGeometryCrashAnnotations(not_null<Element*> view) {
CrashReports::SetAnnotation(
"Geometry",
u"size: %1x%2, visibleTop: %3, visibleBottom: %4, top: %5"_q
.arg(width())
.arg(height())
.arg(_visibleTop)
.arg(_visibleBottom)
.arg(_itemsTop));
const auto logItems = [&] {
auto items = QStringList();
auto top = _itemsTop;
auto index = 0;
for (const auto &some : _items) {
items.push_back(u"(%1)%2=%3,%4,%5"_q
.arg(index++)
.arg(top)
.arg(itemTop(some))
.arg(some->y())
.arg(some->height()));
top += some->height();
}
return items.join(';');
};
CrashReports::SetAnnotation("Chosen", u"%1,%2,%3"_q
.arg(itemTop(view))
.arg(view->y())
.arg(view->height()));
CrashReports::SetAnnotation("Before", logItems());
updateSize();
CrashReports::SetAnnotation("After", logItems());
}
void ListWidget::refreshRows(const Data::MessagesSlice &old) {
saveScrollState();
@ -3167,6 +3207,12 @@ void ListWidget::mouseActionFinish(
auto activated = ClickHandler::unpressed();
if (_overElement) {
AssertIsDebug();
setGeometryCrashAnnotations(_overElement);
Unexpected("Test");
}
auto simpleSelectionChange = pressState.itemId
&& !_pressWasInactive
&& (button != Qt::RightButton)

View File

@ -608,6 +608,8 @@ private:
template <typename Method>
void enumerateDates(Method method);
void setGeometryCrashAnnotations(not_null<Element*> view);
static constexpr auto kMinimalIdsLimit = 24;
const not_null<ListDelegate*> _delegate;

View File

@ -401,7 +401,7 @@ void Session::addWindow(not_null<Window::SessionController*> controller) {
_windows.remove(controller);
});
updates().addActiveChat(controller->activeChatChanges(
) | rpl::map([=](const Dialogs::Key &chat) {
) | rpl::map([=](Dialogs::Key chat) {
return chat.peer();
}) | rpl::distinct_until_changed());
}

View File

@ -325,7 +325,7 @@ void SetupSendAsButton(
not_null<SendAsButton*> button,
not_null<Window::SessionController*> window) {
auto active = window->activeChatValue(
) | rpl::map([=](const Dialogs::Key &key) {
) | rpl::map([=](Dialogs::Key key) {
return key.history() ? key.history()->peer.get() : nullptr;
});
SetupSendAsButton(button, std::move(active), window);