mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Support dialog rows with variable height.
This commit is contained in:
parent
248337daf5
commit
37308cde21
@ -386,7 +386,7 @@ void ApiWrap::checkChatInvite(
|
|||||||
|
|
||||||
void ApiWrap::savePinnedOrder(Data::Folder *folder) {
|
void ApiWrap::savePinnedOrder(Data::Folder *folder) {
|
||||||
const auto &order = _session->data().pinnedChatsOrder(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()) {
|
if (const auto history = key.history()) {
|
||||||
return MTP_inputDialogPeer(history->peer->input);
|
return MTP_inputDialogPeer(history->peer->input);
|
||||||
} else if (const auto folder = key.folder()) {
|
} 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) {
|
void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
|
||||||
const auto &order = _session->data().pinnedChatsOrder(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()) {
|
if (const auto topic = key.topic()) {
|
||||||
return MTP_int(topic->rootId().bare);
|
return MTP_int(topic->rootId().bare);
|
||||||
}
|
}
|
||||||
|
@ -795,7 +795,9 @@ ShareBox::Inner::Chat *ShareBox::Inner::getChatAtIndex(int index) {
|
|||||||
}
|
}
|
||||||
const auto row = [=] {
|
const auto row = [=] {
|
||||||
if (_filter.isEmpty()) {
|
if (_filter.isEmpty()) {
|
||||||
return _chatsIndexed->rowAtY(index, 1);
|
return (index < _chatsIndexed->size())
|
||||||
|
? (_chatsIndexed->begin() + index)->get()
|
||||||
|
: nullptr;
|
||||||
}
|
}
|
||||||
return (index < _filtered.size())
|
return (index < _filtered.size())
|
||||||
? _filtered[index].get()
|
? _filtered[index].get()
|
||||||
@ -865,9 +867,11 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) {
|
|||||||
|
|
||||||
if (_filter.isEmpty()) {
|
if (_filter.isEmpty()) {
|
||||||
if (!_chatsIndexed->empty()) {
|
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) {
|
for (auto end = _chatsIndexed->cend(); i != end; ++i) {
|
||||||
if (((*i)->pos() * _rowHeight) >= yTo) {
|
if (((*i)->index() * _rowHeight) >= yTo) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
(*i)->entry()->loadUserpic();
|
(*i)->entry()->loadUserpic();
|
||||||
@ -973,7 +977,8 @@ void ShareBox::Inner::paintEvent(QPaintEvent *e) {
|
|||||||
auto indexTo = rowTo * _columnCount;
|
auto indexTo = rowTo * _columnCount;
|
||||||
if (_filter.isEmpty()) {
|
if (_filter.isEmpty()) {
|
||||||
if (!_chatsIndexed->empty()) {
|
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) {
|
for (auto end = _chatsIndexed->cend(); i != end; ++i) {
|
||||||
if (indexFrom >= indexTo) {
|
if (indexFrom >= indexTo) {
|
||||||
break;
|
break;
|
||||||
|
@ -1381,8 +1381,8 @@ void Session::setupUserIsContactViewer() {
|
|||||||
_contactsNoChatsList.addByName(history);
|
_contactsNoChatsList.addByName(history);
|
||||||
}
|
}
|
||||||
} else if (const auto history = historyLoaded(user)) {
|
} else if (const auto history = historyLoaded(user)) {
|
||||||
_contactsNoChatsList.del(history);
|
_contactsNoChatsList.remove(history);
|
||||||
_contactsList.del(history);
|
_contactsList.remove(history);
|
||||||
}
|
}
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
@ -1915,7 +1915,7 @@ MessageIdsList Session::itemOrItsGroup(not_null<HistoryItem*> item) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Session::setChatPinned(
|
void Session::setChatPinned(
|
||||||
const Dialogs::Key &key,
|
Dialogs::Key key,
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
bool pinned) {
|
bool pinned) {
|
||||||
Expects(key.entry()->folderKnown());
|
Expects(key.entry()->folderKnown());
|
||||||
@ -1927,7 +1927,7 @@ void Session::setChatPinned(
|
|||||||
notifyPinnedDialogsOrderUpdated();
|
notifyPinnedDialogsOrderUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::setPinnedFromEntryList(const Dialogs::Key &key, bool pinned) {
|
void Session::setPinnedFromEntryList(Dialogs::Key key, bool pinned) {
|
||||||
Expects(key.entry()->folderKnown());
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
const auto list = chatsListFor(key.entry())->pinned();
|
const auto list = chatsListFor(key.entry())->pinned();
|
||||||
@ -2109,8 +2109,8 @@ void Session::clearPinnedChats(Data::Folder *folder) {
|
|||||||
|
|
||||||
void Session::reorderTwoPinnedChats(
|
void Session::reorderTwoPinnedChats(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
const Dialogs::Key &key1,
|
Dialogs::Key key1,
|
||||||
const Dialogs::Key &key2) {
|
Dialogs::Key key2) {
|
||||||
Expects(key1.entry()->folderKnown() && key2.entry()->folderKnown());
|
Expects(key1.entry()->folderKnown() && key2.entry()->folderKnown());
|
||||||
Expects(filterId || (key1.entry()->folder() == key2.entry()->folder()));
|
Expects(filterId || (key1.entry()->folder() == key2.entry()->folder()));
|
||||||
|
|
||||||
@ -2510,14 +2510,14 @@ bool Session::unreadBadgeMuted() const {
|
|||||||
return computeUnreadBadgeMuted(_chatsList.unreadState());
|
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())
|
const auto remove = (key && key.entry()->inChatList())
|
||||||
? key.entry()->chatListUnreadState()
|
? key.entry()->chatListUnreadState()
|
||||||
: Dialogs::UnreadState();
|
: Dialogs::UnreadState();
|
||||||
return computeUnreadBadge(_chatsList.unreadState() - remove);
|
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()) {
|
if (!Core::App().settings().includeMutedCounter()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3997,7 +3997,7 @@ void Session::refreshChatListEntry(Dialogs::Key key) {
|
|||||||
return;
|
return;
|
||||||
} else if (event.existenceChanged) {
|
} else if (event.existenceChanged) {
|
||||||
const auto mainRow = entry->addToChatList(0, mainList);
|
const auto mainRow = entry->addToChatList(0, mainList);
|
||||||
_contactsNoChatsList.del(key, mainRow);
|
_contactsNoChatsList.remove(key, mainRow);
|
||||||
} else {
|
} else {
|
||||||
event.moved = entry->adjustByPosInChatList(0, mainList);
|
event.moved = entry->adjustByPosInChatList(0, mainList);
|
||||||
}
|
}
|
||||||
|
@ -363,11 +363,8 @@ public:
|
|||||||
not_null<Forum*> forum) const;
|
not_null<Forum*> forum) const;
|
||||||
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
[[nodiscard]] const std::vector<Dialogs::Key> &pinnedChatsOrder(
|
||||||
FilterId filterId) const;
|
FilterId filterId) const;
|
||||||
void setChatPinned(
|
void setChatPinned(Dialogs::Key key, FilterId filterId, bool pinned);
|
||||||
const Dialogs::Key &key,
|
void setPinnedFromEntryList(Dialogs::Key key, bool pinned);
|
||||||
FilterId filterId,
|
|
||||||
bool pinned);
|
|
||||||
void setPinnedFromEntryList(const Dialogs::Key &key, bool pinned);
|
|
||||||
void clearPinnedChats(Folder *folder);
|
void clearPinnedChats(Folder *folder);
|
||||||
void applyPinnedChats(
|
void applyPinnedChats(
|
||||||
Folder *folder,
|
Folder *folder,
|
||||||
@ -377,8 +374,8 @@ public:
|
|||||||
const QVector<MTPint> &list);
|
const QVector<MTPint> &list);
|
||||||
void reorderTwoPinnedChats(
|
void reorderTwoPinnedChats(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
const Dialogs::Key &key1,
|
Dialogs::Key key1,
|
||||||
const Dialogs::Key &key2);
|
Dialogs::Key key2);
|
||||||
|
|
||||||
void setSuggestToGigagroup(not_null<ChannelData*> group, bool suggest);
|
void setSuggestToGigagroup(not_null<ChannelData*> group, bool suggest);
|
||||||
[[nodiscard]] bool suggestToGigagroup(
|
[[nodiscard]] bool suggestToGigagroup(
|
||||||
@ -474,9 +471,8 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] int unreadBadge() const;
|
[[nodiscard]] int unreadBadge() const;
|
||||||
[[nodiscard]] bool unreadBadgeMuted() const;
|
[[nodiscard]] bool unreadBadgeMuted() const;
|
||||||
[[nodiscard]] int unreadBadgeIgnoreOne(const Dialogs::Key &key) const;
|
[[nodiscard]] int unreadBadgeIgnoreOne(Dialogs::Key key) const;
|
||||||
[[nodiscard]] bool unreadBadgeMutedIgnoreOne(
|
[[nodiscard]] bool unreadBadgeMutedIgnoreOne(Dialogs::Key key) const;
|
||||||
const Dialogs::Key &key) const;
|
|
||||||
[[nodiscard]] int unreadOnlyMutedBadge() const;
|
[[nodiscard]] int unreadOnlyMutedBadge() const;
|
||||||
[[nodiscard]] rpl::producer<> unreadBadgeChanges() const;
|
[[nodiscard]] rpl::producer<> unreadBadgeChanges() const;
|
||||||
void notifyUnreadBadgeChanged();
|
void notifyUnreadBadgeChanged();
|
||||||
|
@ -71,6 +71,9 @@ defaultDialogRow: DialogRow {
|
|||||||
textLeft: 68px;
|
textLeft: 68px;
|
||||||
textTop: 34px;
|
textTop: 34px;
|
||||||
}
|
}
|
||||||
|
forumDialogRow: DialogRow {
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
dialogsOnlineBadgeStroke: 2px;
|
dialogsOnlineBadgeStroke: 2px;
|
||||||
dialogsOnlineBadgeSize: 10px;
|
dialogsOnlineBadgeSize: 10px;
|
||||||
|
@ -300,10 +300,10 @@ PositionChange Entry::adjustByPosInChatList(
|
|||||||
not_null<MainList*> list) {
|
not_null<MainList*> list) {
|
||||||
const auto links = chatListLinks(filterId);
|
const auto links = chatListLinks(filterId);
|
||||||
Assert(links != nullptr);
|
Assert(links != nullptr);
|
||||||
const auto from = links->main->pos();
|
const auto from = links->main->top();
|
||||||
list->indexed()->adjustByDate(*links);
|
list->indexed()->adjustByDate(*links);
|
||||||
const auto to = links->main->pos();
|
const auto to = links->main->top();
|
||||||
return { from, to };
|
return { .from = from, .to = to, .height = links->main->height() };
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::setChatListTimeId(TimeId date) {
|
void Entry::setChatListTimeId(TimeId date) {
|
||||||
@ -315,7 +315,7 @@ void Entry::setChatListTimeId(TimeId date) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Entry::posInChatList(FilterId filterId) const {
|
int Entry::posInChatList(FilterId filterId) const {
|
||||||
return mainChatListLink(filterId)->pos();
|
return mainChatListLink(filterId)->index();
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Row*> Entry::addToChatList(
|
not_null<Row*> Entry::addToChatList(
|
||||||
|
@ -56,6 +56,7 @@ enum class SortMode {
|
|||||||
struct PositionChange {
|
struct PositionChange {
|
||||||
int from = -1;
|
int from = -1;
|
||||||
int to = -1;
|
int to = -1;
|
||||||
|
int height = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UnreadState {
|
struct UnreadState {
|
||||||
|
@ -134,7 +134,7 @@ void IndexedList::adjustByName(
|
|||||||
}
|
}
|
||||||
for (auto ch : toRemove) {
|
for (auto ch : toRemove) {
|
||||||
if (auto it = _index.find(ch); it != _index.cend()) {
|
if (auto it = _index.find(ch); it != _index.cend()) {
|
||||||
it->second.del(key, mainRow);
|
it->second.remove(key, mainRow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!toAdd.empty()) {
|
if (!toAdd.empty()) {
|
||||||
@ -171,7 +171,7 @@ void IndexedList::adjustNames(
|
|||||||
history->removeChatListEntryByLetter(filterId, ch);
|
history->removeChatListEntryByLetter(filterId, ch);
|
||||||
}
|
}
|
||||||
if (auto it = _index.find(ch); it != _index.cend()) {
|
if (auto it = _index.find(ch); it != _index.cend()) {
|
||||||
it->second.del(key, mainRow);
|
it->second.remove(key, mainRow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto ch : toAdd) {
|
for (auto ch : toAdd) {
|
||||||
@ -186,11 +186,11 @@ void IndexedList::adjustNames(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexedList::del(Key key, Row *replacedBy) {
|
void IndexedList::remove(Key key, Row *replacedBy) {
|
||||||
if (_list.del(key, replacedBy)) {
|
if (_list.remove(key, replacedBy)) {
|
||||||
for (const auto &ch : key.entry()->chatListFirstLetters()) {
|
for (const auto &ch : key.entry()->chatListFirstLetters()) {
|
||||||
if (auto it = _index.find(ch); it != _index.cend()) {
|
if (const auto it = _index.find(ch); it != _index.cend()) {
|
||||||
it->second.del(key, replacedBy);
|
it->second.remove(key, replacedBy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,39 +37,48 @@ public:
|
|||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const base::flat_set<QChar> &oldChars);
|
const base::flat_set<QChar> &oldChars);
|
||||||
|
|
||||||
void del(Key key, Row *replacedBy = nullptr);
|
void remove(Key key, Row *replacedBy = nullptr);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
const List &all() const {
|
[[nodiscard]] const List &all() const {
|
||||||
return _list;
|
return _list;
|
||||||
}
|
}
|
||||||
const List *filtered(QChar ch) const {
|
[[nodiscard]] const List *filtered(QChar ch) const {
|
||||||
const auto i = _index.find(ch);
|
const auto i = _index.find(ch);
|
||||||
return (i != _index.end()) ? &i->second : nullptr;
|
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.
|
// Part of List interface is duplicated here for all() list.
|
||||||
int size() const { return all().size(); }
|
[[nodiscard]] int size() const { return all().size(); }
|
||||||
bool empty() const { return all().empty(); }
|
[[nodiscard]] bool empty() const { return all().empty(); }
|
||||||
bool contains(Key key) const { return all().contains(key); }
|
[[nodiscard]] int height() const { return all().height(); }
|
||||||
Row *getRow(Key key) const { return all().getRow(key); }
|
[[nodiscard]] bool contains(Key key) const {
|
||||||
Row *rowAtY(int32 y, int32 h) const { return all().rowAtY(y, h); }
|
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 iterator = List::iterator;
|
||||||
using const_iterator = List::const_iterator;
|
using const_iterator = List::const_iterator;
|
||||||
const_iterator cbegin() const { return all().cbegin(); }
|
[[nodiscard]] const_iterator cbegin() const { return all().cbegin(); }
|
||||||
const_iterator cend() const { return all().cend(); }
|
[[nodiscard]] const_iterator cend() const { return all().cend(); }
|
||||||
const_iterator begin() const { return all().cbegin(); }
|
[[nodiscard]] const_iterator begin() const { return all().cbegin(); }
|
||||||
const_iterator end() const { return all().cend(); }
|
[[nodiscard]] const_iterator end() const { return all().cend(); }
|
||||||
iterator begin() { return all().begin(); }
|
[[nodiscard]] iterator begin() { return all().begin(); }
|
||||||
iterator end() { return all().end(); }
|
[[nodiscard]] iterator end() { return all().end(); }
|
||||||
const_iterator cfind(Row *value) const { return all().cfind(value); }
|
[[nodiscard]] const_iterator cfind(Row *value) const {
|
||||||
const_iterator find(Row *value) const { return all().cfind(value); }
|
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); }
|
[[nodiscard]] const_iterator find(Row *value) const {
|
||||||
const_iterator find(int y, int h) const { return all().cfind(y, h); }
|
return all().cfind(value);
|
||||||
iterator find(int y, int h) { return all().find(y, h); }
|
}
|
||||||
|
[[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:
|
private:
|
||||||
void adjustByName(
|
void adjustByName(
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -192,6 +192,19 @@ private:
|
|||||||
EmptyForum,
|
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;
|
Main::Session &session() const;
|
||||||
|
|
||||||
void dialogRowReplaced(Row *oldRow, Row *newRow);
|
void dialogRowReplaced(Row *oldRow, Row *newRow);
|
||||||
@ -220,6 +233,8 @@ private:
|
|||||||
void clearIrrelevantState();
|
void clearIrrelevantState();
|
||||||
void selectByMouse(QPoint globalPosition);
|
void selectByMouse(QPoint globalPosition);
|
||||||
void loadPeerPhotos();
|
void loadPeerPhotos();
|
||||||
|
void scrollToItem(int top, int height);
|
||||||
|
void scrollToDefaultSelected();
|
||||||
void setCollapsedPressed(int pressed);
|
void setCollapsedPressed(int pressed);
|
||||||
void setPressed(Row *pressed);
|
void setPressed(Row *pressed);
|
||||||
void setHashtagPressed(int pressed);
|
void setHashtagPressed(int pressed);
|
||||||
@ -283,13 +298,18 @@ private:
|
|||||||
void fillSupportSearchMenu(not_null<Ui::PopupMenu*> menu);
|
void fillSupportSearchMenu(not_null<Ui::PopupMenu*> menu);
|
||||||
void fillArchiveSearchMenu(not_null<Ui::PopupMenu*> menu);
|
void fillArchiveSearchMenu(not_null<Ui::PopupMenu*> menu);
|
||||||
|
|
||||||
int dialogsOffset() const;
|
void refreshShownList();
|
||||||
int fixedOnTopCount() const;
|
[[nodiscard]] int skipTopHeight() const;
|
||||||
int pinnedOffset() const;
|
[[nodiscard]] int dialogsOffset() const;
|
||||||
int filteredOffset() const;
|
[[nodiscard]] int shownHeight(int till = -1) const;
|
||||||
int peerSearchOffset() const;
|
[[nodiscard]] int fixedOnTopCount() const;
|
||||||
int searchedOffset() const;
|
[[nodiscard]] int pinnedOffset() const;
|
||||||
int searchInChatSkip() 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(
|
void paintCollapsedRows(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
@ -339,13 +359,12 @@ private:
|
|||||||
Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row);
|
Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row);
|
||||||
Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history);
|
Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history);
|
||||||
|
|
||||||
|
Row *shownRowByKey(Key key);
|
||||||
void clearSearchResults(bool clearPeerSearchResults = true);
|
void clearSearchResults(bool clearPeerSearchResults = true);
|
||||||
void updateSelectedRow(Key key = Key());
|
void updateSelectedRow(Key key = Key());
|
||||||
void trackSearchResultsHistory(not_null<History*> history);
|
void trackSearchResultsHistory(not_null<History*> history);
|
||||||
void trackSearchResultsForum(Data::Forum *forum);
|
void trackSearchResultsForum(Data::Forum *forum);
|
||||||
|
|
||||||
[[nodiscard]] not_null<IndexedList*> shownDialogs() const;
|
|
||||||
|
|
||||||
[[nodiscard]] const std::vector<Key> &pinnedChatsOrder() const;
|
[[nodiscard]] const std::vector<Key> &pinnedChatsOrder() const;
|
||||||
void checkReorderPinnedStart(QPoint localPosition);
|
void checkReorderPinnedStart(QPoint localPosition);
|
||||||
int updateReorderIndexGetCount();
|
int updateReorderIndexGetCount();
|
||||||
@ -363,6 +382,7 @@ private:
|
|||||||
|
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
|
|
||||||
|
not_null<IndexedList*> _shownList;
|
||||||
FilterId _filterId = 0;
|
FilterId _filterId = 0;
|
||||||
bool _mouseSelection = false;
|
bool _mouseSelection = false;
|
||||||
std::optional<QPoint> _lastMousePosition;
|
std::optional<QPoint> _lastMousePosition;
|
||||||
@ -376,7 +396,7 @@ private:
|
|||||||
not_null<const style::DialogRow*> _st;
|
not_null<const style::DialogRow*> _st;
|
||||||
int _collapsedSelected = -1;
|
int _collapsedSelected = -1;
|
||||||
int _collapsedPressed = -1;
|
int _collapsedPressed = -1;
|
||||||
int _skipTopDialogs = 0;
|
bool _skipTopDialog = false;
|
||||||
Row *_selected = nullptr;
|
Row *_selected = nullptr;
|
||||||
Row *_pressed = nullptr;
|
Row *_pressed = nullptr;
|
||||||
|
|
||||||
@ -384,10 +404,6 @@ private:
|
|||||||
int _draggingIndex = -1;
|
int _draggingIndex = -1;
|
||||||
int _aboveIndex = -1;
|
int _aboveIndex = -1;
|
||||||
QPoint _dragStart;
|
QPoint _dragStart;
|
||||||
struct PinnedRow {
|
|
||||||
anim::value yadd;
|
|
||||||
crl::time animStartTime = 0;
|
|
||||||
};
|
|
||||||
std::vector<PinnedRow> _pinnedRows;
|
std::vector<PinnedRow> _pinnedRows;
|
||||||
Ui::Animations::Basic _pinnedShiftAnimation;
|
Ui::Animations::Basic _pinnedShiftAnimation;
|
||||||
base::flat_set<Key> _pinnedOnDragStart;
|
base::flat_set<Key> _pinnedOnDragStart;
|
||||||
@ -405,7 +421,7 @@ private:
|
|||||||
bool _hashtagDeleteSelected = false;
|
bool _hashtagDeleteSelected = false;
|
||||||
bool _hashtagDeletePressed = false;
|
bool _hashtagDeletePressed = false;
|
||||||
|
|
||||||
std::vector<not_null<Row*>> _filterResults;
|
std::vector<FilterResult> _filterResults;
|
||||||
base::flat_map<Key, std::unique_ptr<Row>> _filterResultsGlobal;
|
base::flat_map<Key, std::unique_ptr<Row>> _filterResultsGlobal;
|
||||||
int _filteredSelected = -1;
|
int _filteredSelected = -1;
|
||||||
int _filteredPressed = -1;
|
int _filteredPressed = -1;
|
||||||
|
@ -39,13 +39,13 @@ public:
|
|||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return (_value != nullptr);
|
return (_value != nullptr);
|
||||||
}
|
}
|
||||||
not_null<Entry*> entry() const;
|
[[nodiscard]] not_null<Entry*> entry() const;
|
||||||
History *history() const;
|
[[nodiscard]] History *history() const;
|
||||||
Data::Folder *folder() const;
|
[[nodiscard]] Data::Folder *folder() const;
|
||||||
Data::ForumTopic *topic() const;
|
[[nodiscard]] Data::ForumTopic *topic() const;
|
||||||
Data::Thread *thread() const;
|
[[nodiscard]] Data::Thread *thread() const;
|
||||||
History *owningHistory() const;
|
[[nodiscard]] History *owningHistory() const;
|
||||||
PeerData *peer() const;
|
[[nodiscard]] PeerData *peer() const;
|
||||||
|
|
||||||
friend inline constexpr auto operator<=>(Key, Key) noexcept = default;
|
friend inline constexpr auto operator<=>(Key, Key) noexcept = default;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ List::List(SortMode sortMode, FilterId filterId)
|
|||||||
|
|
||||||
List::const_iterator List::cfind(Row *value) const {
|
List::const_iterator List::cfind(Row *value) const {
|
||||||
return value
|
return value
|
||||||
? (cbegin() + value->pos())
|
? (cbegin() + value->index())
|
||||||
: cend();
|
: cend();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ not_null<Row*> List::addToEnd(Key key) {
|
|||||||
}
|
}
|
||||||
const auto result = _rowByKey.emplace(
|
const auto result = _rowByKey.emplace(
|
||||||
key,
|
key,
|
||||||
std::make_unique<Row>(key, _rows.size())
|
std::make_unique<Row>(key, _rows.size(), height())
|
||||||
).first->second.get();
|
).first->second.get();
|
||||||
_rows.emplace_back(result);
|
_rows.emplace_back(result);
|
||||||
if (_sortMode == SortMode::Date) {
|
if (_sortMode == SortMode::Date) {
|
||||||
@ -60,10 +60,10 @@ not_null<Row*> List::addByName(Key key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void List::adjustByName(not_null<Row*> row) {
|
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 &key = row->entry()->chatListNameSortKey();
|
||||||
const auto index = row->pos();
|
const auto index = row->index();
|
||||||
const auto i = _rows.begin() + index;
|
const auto i = _rows.begin() + index;
|
||||||
const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
|
const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
|
||||||
return row->entry()->chatListNameSortKey().compare(key) >= 0;
|
return row->entry()->chatListNameSortKey().compare(key) >= 0;
|
||||||
@ -85,7 +85,7 @@ void List::adjustByDate(not_null<Row*> row) {
|
|||||||
Expects(_sortMode == SortMode::Date);
|
Expects(_sortMode == SortMode::Date);
|
||||||
|
|
||||||
const auto key = row->sortKey(_filterId);
|
const auto key = row->sortKey(_filterId);
|
||||||
const auto index = row->pos();
|
const auto index = row->index();
|
||||||
const auto i = _rows.begin() + index;
|
const auto i = _rows.begin() + index;
|
||||||
const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
|
const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
|
||||||
return (row->sortKey(_filterId) <= key);
|
return (row->sortKey(_filterId) <= key);
|
||||||
@ -108,7 +108,7 @@ bool List::moveToTop(Key key) {
|
|||||||
if (i == _rowByKey.cend()) {
|
if (i == _rowByKey.cend()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto index = i->second->pos();
|
const auto index = i->second->index();
|
||||||
const auto begin = _rows.begin();
|
const auto begin = _rows.begin();
|
||||||
rotate(begin, begin + index, begin + index + 1);
|
rotate(begin, begin + index, begin + index + 1);
|
||||||
return true;
|
return true;
|
||||||
@ -118,16 +118,20 @@ void List::rotate(
|
|||||||
std::vector<not_null<Row*>>::iterator first,
|
std::vector<not_null<Row*>>::iterator first,
|
||||||
std::vector<not_null<Row*>>::iterator middle,
|
std::vector<not_null<Row*>>::iterator middle,
|
||||||
std::vector<not_null<Row*>>::iterator last) {
|
std::vector<not_null<Row*>>::iterator last) {
|
||||||
|
auto top = (*first)->top();
|
||||||
std::rotate(first, middle, last);
|
std::rotate(first, middle, last);
|
||||||
|
|
||||||
auto count = (last - first);
|
auto count = (last - first);
|
||||||
auto index = (first - _rows.begin());
|
auto index = (first - _rows.begin());
|
||||||
while (count--) {
|
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);
|
auto i = _rowByKey.find(key);
|
||||||
if (i == _rowByKey.cend()) {
|
if (i == _rowByKey.cend()) {
|
||||||
return false;
|
return false;
|
||||||
@ -136,13 +140,34 @@ bool List::del(Key key, Row *replacedBy) {
|
|||||||
const auto row = i->second.get();
|
const auto row = i->second.get();
|
||||||
row->entry()->owner().dialogsRowReplaced({ row, replacedBy });
|
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);
|
_rows.erase(_rows.begin() + index);
|
||||||
for (auto i = index, count = int(_rows.size()); i != count; ++i) {
|
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);
|
_rowByKey.erase(i);
|
||||||
return true;
|
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
|
} // namespace Dialogs
|
||||||
|
@ -23,52 +23,49 @@ public:
|
|||||||
List &operator=(List &&other) = default;
|
List &operator=(List &&other) = default;
|
||||||
~List() = default;
|
~List() = default;
|
||||||
|
|
||||||
int size() const {
|
[[nodiscard]] int size() const {
|
||||||
return _rows.size();
|
return _rows.size();
|
||||||
}
|
}
|
||||||
bool empty() const {
|
[[nodiscard]] bool empty() const {
|
||||||
return _rows.empty();
|
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();
|
return _rowByKey.find(key) != _rowByKey.end();
|
||||||
}
|
}
|
||||||
Row *getRow(Key key) const {
|
[[nodiscard]] Row *getRow(Key key) const {
|
||||||
const auto i = _rowByKey.find(key);
|
const auto i = _rowByKey.find(key);
|
||||||
return (i != _rowByKey.end()) ? i->second.get() : nullptr;
|
return (i != _rowByKey.end()) ? i->second.get() : nullptr;
|
||||||
}
|
}
|
||||||
Row *rowAtY(int y, int h) const {
|
[[nodiscard]] Row *rowAtY(int y) const;
|
||||||
const auto i = cfind(y, h);
|
|
||||||
if (i == cend() || (*i)->pos() != ((y > 0) ? (y / h) : 0)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return *i;
|
|
||||||
}
|
|
||||||
|
|
||||||
not_null<Row*> addToEnd(Key key);
|
not_null<Row*> addToEnd(Key key);
|
||||||
Row *adjustByName(Key key);
|
Row *adjustByName(Key key);
|
||||||
not_null<Row*> addByName(Key key);
|
not_null<Row*> addByName(Key key);
|
||||||
bool moveToTop(Key key);
|
bool moveToTop(Key key);
|
||||||
void adjustByDate(not_null<Row*> row);
|
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 const_iterator = std::vector<not_null<Row*>>::const_iterator;
|
||||||
using iterator = const_iterator;
|
using iterator = const_iterator;
|
||||||
|
|
||||||
const_iterator cbegin() const { return _rows.cbegin(); }
|
[[nodiscard]] const_iterator cbegin() const { return _rows.cbegin(); }
|
||||||
const_iterator cend() const { return _rows.cend(); }
|
[[nodiscard]] const_iterator cend() const { return _rows.cend(); }
|
||||||
const_iterator begin() const { return cbegin(); }
|
[[nodiscard]] const_iterator begin() const { return cbegin(); }
|
||||||
const_iterator end() const { return cend(); }
|
[[nodiscard]] const_iterator end() const { return cend(); }
|
||||||
iterator begin() { return cbegin(); }
|
[[nodiscard]] iterator begin() { return cbegin(); }
|
||||||
iterator end() { return cend(); }
|
[[nodiscard]] iterator end() { return cend(); }
|
||||||
const_iterator cfind(Row *value) const;
|
[[nodiscard]] const_iterator cfind(Row *value) const;
|
||||||
const_iterator find(Row *value) const { return cfind(value); }
|
[[nodiscard]] const_iterator find(Row *value) const {
|
||||||
iterator find(Row *value) { return cfind(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());
|
|
||||||
}
|
}
|
||||||
const_iterator find(int y, int h) const { return cfind(y, h); }
|
[[nodiscard]] iterator find(Row *value) { return cfind(value); }
|
||||||
iterator find(int y, int h) { return cfind(y, h); }
|
[[nodiscard]] const_iterator findByY(int y) const;
|
||||||
|
[[nodiscard]] iterator findByY(int y) { return findByY(y); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void adjustByName(not_null<Row*> row);
|
void adjustByName(not_null<Row*> row);
|
||||||
|
@ -89,7 +89,7 @@ void MainList::clear() {
|
|||||||
_cloudListSize = 0;
|
_cloudListSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RowsByLetter MainList::addEntry(const Key &key) {
|
RowsByLetter MainList::addEntry(Key key) {
|
||||||
const auto result = _all.addToEnd(key);
|
const auto result = _all.addToEnd(key);
|
||||||
|
|
||||||
const auto unread = key.entry()->chatListUnreadState();
|
const auto unread = key.entry()->chatListUnreadState();
|
||||||
@ -99,8 +99,8 @@ RowsByLetter MainList::addEntry(const Key &key) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainList::removeEntry(const Key &key) {
|
void MainList::removeEntry(Key key) {
|
||||||
_all.del(key);
|
_all.remove(key);
|
||||||
|
|
||||||
const auto unread = key.entry()->chatListUnreadState();
|
const auto unread = key.entry()->chatListUnreadState();
|
||||||
unreadEntryChanged(unread, false);
|
unreadEntryChanged(unread, false);
|
||||||
|
@ -33,8 +33,8 @@ public:
|
|||||||
void setAllAreMuted(bool allAreMuted = true);
|
void setAllAreMuted(bool allAreMuted = true);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
RowsByLetter addEntry(const Key &key);
|
RowsByLetter addEntry(Key key);
|
||||||
void removeEntry(const Key &key);
|
void removeEntry(Key key);
|
||||||
|
|
||||||
void unreadStateChanged(
|
void unreadStateChanged(
|
||||||
const UnreadState &wasState,
|
const UnreadState &wasState,
|
||||||
|
@ -31,13 +31,13 @@ void PinnedList::setLimit(int limit) {
|
|||||||
applyLimit(_limit);
|
applyLimit(_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PinnedList::addPinned(const Key &key) {
|
void PinnedList::addPinned(Key key) {
|
||||||
Expects(key.entry()->folderKnown());
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
addPinnedGetPosition(key);
|
addPinnedGetPosition(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PinnedList::addPinnedGetPosition(const Key &key) {
|
int PinnedList::addPinnedGetPosition(Key key) {
|
||||||
const auto already = ranges::find(_data, key);
|
const auto already = ranges::find(_data, key);
|
||||||
if (already != end(_data)) {
|
if (already != end(_data)) {
|
||||||
return already - begin(_data);
|
return already - begin(_data);
|
||||||
@ -49,7 +49,7 @@ int PinnedList::addPinnedGetPosition(const Key &key) {
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PinnedList::setPinned(const Key &key, bool pinned) {
|
void PinnedList::setPinned(Key key, bool pinned) {
|
||||||
Expects(key.entry()->folderKnown() || _filterId != 0);
|
Expects(key.entry()->folderKnown() || _filterId != 0);
|
||||||
|
|
||||||
if (pinned) {
|
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 index1 = ranges::find(_data, key1) - begin(_data);
|
||||||
const auto index2 = ranges::find(_data, key2) - begin(_data);
|
const auto index2 = ranges::find(_data, key2) - begin(_data);
|
||||||
Assert(index1 >= 0 && index1 < _data.size());
|
Assert(index1 >= 0 && index1 < _data.size());
|
||||||
|
@ -26,10 +26,10 @@ public:
|
|||||||
|
|
||||||
// Places on the last place in the list otherwise.
|
// Places on the last place in the list otherwise.
|
||||||
// Does nothing if already pinned.
|
// Does nothing if already pinned.
|
||||||
void addPinned(const Key &key);
|
void addPinned(Key key);
|
||||||
|
|
||||||
// if (pinned) places on the first place in the list.
|
// 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();
|
void clear();
|
||||||
|
|
||||||
@ -40,14 +40,14 @@ public:
|
|||||||
not_null<Data::Forum*> forum,
|
not_null<Data::Forum*> forum,
|
||||||
const QVector<MTPint> &list);
|
const QVector<MTPint> &list);
|
||||||
void applyList(const std::vector<not_null<History*>> &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 {
|
const std::vector<Key> &order() const {
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int addPinnedGetPosition(const Key &key);
|
int addPinnedGetPosition(Key key);
|
||||||
void applyLimit(int limit);
|
void applyLimit(int limit);
|
||||||
|
|
||||||
FilterId _filterId = 0;
|
FilterId _filterId = 0;
|
||||||
|
@ -143,9 +143,14 @@ void BasicRow::paintUserpic(
|
|||||||
context.paused);
|
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()) {
|
if (const auto history = key.history()) {
|
||||||
updateCornerBadgeShown(history->peer);
|
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(
|
void Row::setCornerBadgeShown(
|
||||||
bool shown,
|
bool shown,
|
||||||
Fn<void()> updateCallback) const {
|
Fn<void()> updateCallback) const {
|
||||||
if (_cornerBadgeShown == shown) {
|
const auto value = shown ? 1 : 0;
|
||||||
|
if (_cornerBadgeShown == value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_cornerBadgeShown = shown;
|
_cornerBadgeShown = value;
|
||||||
if (_cornerBadgeUserpic && _cornerBadgeUserpic->animation.animating()) {
|
if (_cornerBadgeUserpic && _cornerBadgeUserpic->animation.animating()) {
|
||||||
_cornerBadgeUserpic->animation.change(
|
_cornerBadgeUserpic->animation.change(
|
||||||
_cornerBadgeShown ? 1. : 0.,
|
_cornerBadgeShown ? 1. : 0.,
|
||||||
|
@ -16,6 +16,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
class History;
|
class History;
|
||||||
class HistoryItem;
|
class HistoryItem;
|
||||||
|
|
||||||
|
namespace style {
|
||||||
|
struct DialogRow;
|
||||||
|
} // namespace style
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class CloudImageView;
|
class CloudImageView;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
@ -57,7 +61,8 @@ public:
|
|||||||
int outerWidth,
|
int outerWidth,
|
||||||
const QColor *colorOverride = nullptr) const;
|
const QColor *colorOverride = nullptr) const;
|
||||||
|
|
||||||
std::shared_ptr<Data::CloudImageView> &userpicView() const {
|
[[nodiscard]] auto userpicView() const
|
||||||
|
-> std::shared_ptr<Data::CloudImageView> & {
|
||||||
return _userpic;
|
return _userpic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,11 +73,18 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class List;
|
class List;
|
||||||
class Row : public BasicRow {
|
class Row final : public BasicRow {
|
||||||
public:
|
public:
|
||||||
explicit Row(std::nullptr_t) {
|
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(
|
void updateCornerBadgeShown(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
@ -102,8 +114,8 @@ public:
|
|||||||
[[nodiscard]] not_null<Entry*> entry() const {
|
[[nodiscard]] not_null<Entry*> entry() const {
|
||||||
return _id.entry();
|
return _id.entry();
|
||||||
}
|
}
|
||||||
[[nodiscard]] int pos() const {
|
[[nodiscard]] int index() const {
|
||||||
return _pos;
|
return _index;
|
||||||
}
|
}
|
||||||
[[nodiscard]] uint64 sortKey(FilterId filterId) const;
|
[[nodiscard]] uint64 sortKey(FilterId filterId) const;
|
||||||
|
|
||||||
@ -139,11 +151,13 @@ private:
|
|||||||
const Ui::PaintContext &context);
|
const Ui::PaintContext &context);
|
||||||
|
|
||||||
Key _id;
|
Key _id;
|
||||||
int _pos = 0;
|
|
||||||
mutable uint32 _listEntryCacheVersion = 0;
|
|
||||||
mutable Ui::Text::String _listEntryCache;
|
mutable Ui::Text::String _listEntryCache;
|
||||||
mutable std::unique_ptr<CornerBadgeUserpic> _cornerBadgeUserpic;
|
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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -245,6 +245,7 @@ template <typename PaintItemCallback>
|
|||||||
void PaintRow(
|
void PaintRow(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<const BasicRow*> row,
|
not_null<const BasicRow*> row,
|
||||||
|
QRect geometry,
|
||||||
not_null<Entry*> entry,
|
not_null<Entry*> entry,
|
||||||
VideoUserpic *videoUserpic,
|
VideoUserpic *videoUserpic,
|
||||||
PeerData *from,
|
PeerData *from,
|
||||||
@ -264,7 +265,6 @@ void PaintRow(
|
|||||||
draft = nullptr;
|
draft = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fullRect = QRect(0, 0, context.width, context.st->height);
|
|
||||||
auto bg = context.active
|
auto bg = context.active
|
||||||
? st::dialogsBgActive
|
? st::dialogsBgActive
|
||||||
: context.selected
|
: context.selected
|
||||||
@ -273,7 +273,7 @@ void PaintRow(
|
|||||||
auto ripple = context.active
|
auto ripple = context.active
|
||||||
? st::dialogsRippleBgActive
|
? st::dialogsRippleBgActive
|
||||||
: st::dialogsRippleBg;
|
: st::dialogsRippleBg;
|
||||||
p.fillRect(fullRect, bg);
|
p.fillRect(geometry, bg);
|
||||||
row->paintRipple(p, 0, 0, context.width, &ripple->c);
|
row->paintRipple(p, 0, 0, context.width, &ripple->c);
|
||||||
|
|
||||||
const auto history = entry->asHistory();
|
const auto history = entry->asHistory();
|
||||||
@ -932,6 +932,7 @@ void RowPainter::Paint(
|
|||||||
PaintRow(
|
PaintRow(
|
||||||
p,
|
p,
|
||||||
row,
|
row,
|
||||||
|
QRect(0, 0, context.width, row->height()),
|
||||||
entry,
|
entry,
|
||||||
videoUserpic,
|
videoUserpic,
|
||||||
from,
|
from,
|
||||||
@ -1029,6 +1030,7 @@ void RowPainter::Paint(
|
|||||||
PaintRow(
|
PaintRow(
|
||||||
p,
|
p,
|
||||||
row,
|
row,
|
||||||
|
QRect(0, 0, context.width, context.st->height),
|
||||||
entry,
|
entry,
|
||||||
nullptr,
|
nullptr,
|
||||||
from,
|
from,
|
||||||
|
@ -205,7 +205,7 @@ base::options::toggle AutoScrollInactiveChat({
|
|||||||
[[nodiscard]] rpl::producer<PeerData*> ActivePeerValue(
|
[[nodiscard]] rpl::producer<PeerData*> ActivePeerValue(
|
||||||
not_null<Window::SessionController*> controller) {
|
not_null<Window::SessionController*> controller) {
|
||||||
return controller->activeChatValue(
|
return controller->activeChatValue(
|
||||||
) | rpl::map([](const Dialogs::Key &key) {
|
) | rpl::map([](Dialogs::Key key) {
|
||||||
const auto history = key.history();
|
const auto history = key.history();
|
||||||
return history ? history->peer.get() : nullptr;
|
return history ? history->peer.get() : nullptr;
|
||||||
});
|
});
|
||||||
@ -2530,7 +2530,7 @@ void HistoryWidget::refreshSilentToggle() {
|
|||||||
|
|
||||||
void HistoryWidget::setupScheduledToggle() {
|
void HistoryWidget::setupScheduledToggle() {
|
||||||
controller()->activeChatValue(
|
controller()->activeChatValue(
|
||||||
) | rpl::map([=](const Dialogs::Key &key) -> rpl::producer<> {
|
) | rpl::map([=](Dialogs::Key key) -> rpl::producer<> {
|
||||||
if (const auto history = key.history()) {
|
if (const auto history = key.history()) {
|
||||||
return session().data().scheduledMessages().updates(history);
|
return session().data().scheduledMessages().updates(history);
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "boxes/delete_messages_box.h"
|
#include "boxes/delete_messages_box.h"
|
||||||
#include "boxes/premium_preview_box.h"
|
#include "boxes/premium_preview_box.h"
|
||||||
#include "boxes/peers/edit_participant_box.h"
|
#include "boxes/peers/edit_participant_box.h"
|
||||||
|
#include "core/crash_reports.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_sponsored_messages.h"
|
#include "data/data_sponsored_messages.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
@ -136,7 +137,10 @@ void ListWidget::enumerateItems(Method method) {
|
|||||||
if (TopToBottom) {
|
if (TopToBottom) {
|
||||||
Assert(itemTop(from->get()) + from->get()->height() > _visibleTop);
|
Assert(itemTop(from->get()) + from->get()->height() > _visibleTop);
|
||||||
} else {
|
} else {
|
||||||
Assert(itemTop(from->get()) < _visibleBottom);
|
if (itemTop(from->get()) >= _visibleBottom) {
|
||||||
|
setGeometryCrashAnnotations(*from);
|
||||||
|
Unexpected("itemTop(from->get()) >= _visibleBottom");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -148,7 +152,10 @@ void ListWidget::enumerateItems(Method method) {
|
|||||||
if (TopToBottom) {
|
if (TopToBottom) {
|
||||||
Assert(itembottom > _visibleTop);
|
Assert(itembottom > _visibleTop);
|
||||||
} else {
|
} else {
|
||||||
Assert(itemtop < _visibleBottom);
|
if (itemtop >= _visibleBottom) {
|
||||||
|
setGeometryCrashAnnotations(view);
|
||||||
|
Unexpected("itemtop >= _visibleBottom");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!method(view, itemtop, itembottom)) {
|
if (!method(view, itemtop, itembottom)) {
|
||||||
@ -441,6 +448,39 @@ void ListWidget::refreshViewer() {
|
|||||||
}, _viewerLifetime);
|
}, _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) {
|
void ListWidget::refreshRows(const Data::MessagesSlice &old) {
|
||||||
saveScrollState();
|
saveScrollState();
|
||||||
|
|
||||||
@ -3167,6 +3207,12 @@ void ListWidget::mouseActionFinish(
|
|||||||
|
|
||||||
auto activated = ClickHandler::unpressed();
|
auto activated = ClickHandler::unpressed();
|
||||||
|
|
||||||
|
if (_overElement) {
|
||||||
|
AssertIsDebug();
|
||||||
|
setGeometryCrashAnnotations(_overElement);
|
||||||
|
Unexpected("Test");
|
||||||
|
}
|
||||||
|
|
||||||
auto simpleSelectionChange = pressState.itemId
|
auto simpleSelectionChange = pressState.itemId
|
||||||
&& !_pressWasInactive
|
&& !_pressWasInactive
|
||||||
&& (button != Qt::RightButton)
|
&& (button != Qt::RightButton)
|
||||||
|
@ -608,6 +608,8 @@ private:
|
|||||||
template <typename Method>
|
template <typename Method>
|
||||||
void enumerateDates(Method method);
|
void enumerateDates(Method method);
|
||||||
|
|
||||||
|
void setGeometryCrashAnnotations(not_null<Element*> view);
|
||||||
|
|
||||||
static constexpr auto kMinimalIdsLimit = 24;
|
static constexpr auto kMinimalIdsLimit = 24;
|
||||||
|
|
||||||
const not_null<ListDelegate*> _delegate;
|
const not_null<ListDelegate*> _delegate;
|
||||||
|
@ -401,7 +401,7 @@ void Session::addWindow(not_null<Window::SessionController*> controller) {
|
|||||||
_windows.remove(controller);
|
_windows.remove(controller);
|
||||||
});
|
});
|
||||||
updates().addActiveChat(controller->activeChatChanges(
|
updates().addActiveChat(controller->activeChatChanges(
|
||||||
) | rpl::map([=](const Dialogs::Key &chat) {
|
) | rpl::map([=](Dialogs::Key chat) {
|
||||||
return chat.peer();
|
return chat.peer();
|
||||||
}) | rpl::distinct_until_changed());
|
}) | rpl::distinct_until_changed());
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ void SetupSendAsButton(
|
|||||||
not_null<SendAsButton*> button,
|
not_null<SendAsButton*> button,
|
||||||
not_null<Window::SessionController*> window) {
|
not_null<Window::SessionController*> window) {
|
||||||
auto active = window->activeChatValue(
|
auto active = window->activeChatValue(
|
||||||
) | rpl::map([=](const Dialogs::Key &key) {
|
) | rpl::map([=](Dialogs::Key key) {
|
||||||
return key.history() ? key.history()->peer.get() : nullptr;
|
return key.history() ? key.history()->peer.get() : nullptr;
|
||||||
});
|
});
|
||||||
SetupSendAsButton(button, std::move(active), window);
|
SetupSendAsButton(button, std::move(active), window);
|
||||||
|
Loading…
Reference in New Issue
Block a user