mirror of https://github.com/procxx/kepka.git
Improve archive chat list entry layout.
This commit is contained in:
parent
2d1dcb36cb
commit
9ff02707bf
|
@ -304,7 +304,7 @@ historyPeer8NameFgSelected: historyPeer8NameFg; // orange group member name in a
|
||||||
historyPeer8UserpicBg: #faa774; // orange userpic background
|
historyPeer8UserpicBg: #faa774; // orange userpic background
|
||||||
historyPeerUserpicFg: windowFgActive; // default userpic initials
|
historyPeerUserpicFg: windowFgActive; // default userpic initials
|
||||||
historyPeerSavedMessagesBg: historyPeer4UserpicBg; // saved messages userpic background
|
historyPeerSavedMessagesBg: historyPeer4UserpicBg; // saved messages userpic background
|
||||||
historyPeerArchiveUserpicBg: historyPeer2UserpicBg; // archive folder userpic background
|
historyPeerArchiveUserpicBg: dialogsUnreadBgMuted; // archive folder userpic background
|
||||||
|
|
||||||
// Some values are marked as (adjusted), it means they're adjusted by
|
// Some values are marked as (adjusted), it means they're adjusted by
|
||||||
// hue and saturation of the average background color if user chooses
|
// hue and saturation of the average background color if user chooses
|
||||||
|
|
|
@ -1195,11 +1195,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_saved_short" = "Save";
|
"lng_saved_short" = "Save";
|
||||||
"lng_saved_forward_here" = "Forward messages here for quick access";
|
"lng_saved_forward_here" = "Forward messages here for quick access";
|
||||||
|
|
||||||
"lng_archived_chats" = "Archived chats";
|
"lng_archived_name" = "Archived chats";
|
||||||
"lng_archived_add" = "Archive";
|
"lng_archived_add" = "Archive";
|
||||||
"lng_archived_remove" = "Unarchive";
|
"lng_archived_remove" = "Unarchive";
|
||||||
"lng_chat_archived" = "Chat archived.\nMuted chats will stay archived after new messages arrive.";
|
"lng_archived_added" = "Chat archived.\nMuted chats will stay archived after new messages arrive.";
|
||||||
"lng_chat_unarchived" = "Chat restored from your archive.";
|
"lng_archived_removed" = "Chat restored from your archive.";
|
||||||
|
"lng_archived_chats#one" = "{count} chat";
|
||||||
|
"lng_archived_chats#other" = "{count} chats";
|
||||||
|
"lng_archived_unread_two" = "{chat}, {second_chat}";
|
||||||
|
"lng_archived_unread#one" = "{chat}, {second_chat} and {count} more unread chat";
|
||||||
|
"lng_archived_unread#other" = "{chat}, {second_chat} and {count} more unread chats";
|
||||||
|
|
||||||
"lng_dialogs_text_with_from" = "{from_part} {message}";
|
"lng_dialogs_text_with_from" = "{from_part} {message}";
|
||||||
"lng_dialogs_text_from_wrapped" = "{from}:";
|
"lng_dialogs_text_from_wrapped" = "{from}:";
|
||||||
|
|
|
@ -744,26 +744,33 @@ void ApiWrap::requestMoreDialogs(Data::Folder *folder) {
|
||||||
MTP_int(hash)
|
MTP_int(hash)
|
||||||
)).done([=](const MTPmessages_Dialogs &result) {
|
)).done([=](const MTPmessages_Dialogs &result) {
|
||||||
const auto state = dialogsLoadState(folder);
|
const auto state = dialogsLoadState(folder);
|
||||||
|
const auto count = result.match([](
|
||||||
|
const MTPDmessages_dialogsNotModified &) {
|
||||||
|
LOG(("API Error: not-modified received for requested dialogs."));
|
||||||
|
return 0;
|
||||||
|
}, [&](const MTPDmessages_dialogs &data) {
|
||||||
|
if (state) {
|
||||||
|
state->listReceived = true;
|
||||||
|
dialogsLoadFinish(folder); // may kill 'state'.
|
||||||
|
}
|
||||||
|
return int(data.vdialogs.v.size());
|
||||||
|
}, [&](const MTPDmessages_dialogsSlice &data) {
|
||||||
|
updateDialogsOffset(
|
||||||
|
folder,
|
||||||
|
data.vdialogs.v,
|
||||||
|
data.vmessages.v);
|
||||||
|
return data.vcount.v;
|
||||||
|
});
|
||||||
result.match([](const MTPDmessages_dialogsNotModified & data) {
|
result.match([](const MTPDmessages_dialogsNotModified & data) {
|
||||||
LOG(("API Error: not-modified received for requested dialogs."));
|
LOG(("API Error: not-modified received for requested dialogs."));
|
||||||
}, [&](const auto &data) {
|
}, [&](const auto &data) {
|
||||||
if constexpr (data.Is<MTPDmessages_dialogs>()) {
|
|
||||||
if (state) {
|
|
||||||
state->listReceived = true;
|
|
||||||
dialogsLoadFinish(folder); // may kill 'state'.
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
updateDialogsOffset(
|
|
||||||
folder,
|
|
||||||
data.vdialogs.v,
|
|
||||||
data.vmessages.v);
|
|
||||||
}
|
|
||||||
_session->data().processUsers(data.vusers);
|
_session->data().processUsers(data.vusers);
|
||||||
_session->data().processChats(data.vchats);
|
_session->data().processChats(data.vchats);
|
||||||
_session->data().applyDialogs(
|
_session->data().applyDialogs(
|
||||||
folder,
|
folder,
|
||||||
data.vmessages.v,
|
data.vmessages.v,
|
||||||
data.vdialogs.v);
|
data.vdialogs.v,
|
||||||
|
count);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace Data {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kLoadedChatsMinCount = 20;
|
constexpr auto kLoadedChatsMinCount = 20;
|
||||||
|
constexpr auto kShowChatNamesCount = 2;
|
||||||
|
|
||||||
rpl::producer<int> PinnedDialogsInFolderMaxValue() {
|
rpl::producer<int> PinnedDialogsInFolderMaxValue() {
|
||||||
return rpl::single(
|
return rpl::single(
|
||||||
|
@ -52,7 +53,7 @@ Folder::Folder(not_null<Data::Session*> owner, FolderId id)
|
||||||
: Entry(owner, this)
|
: Entry(owner, this)
|
||||||
, _id(id)
|
, _id(id)
|
||||||
, _chatsList(PinnedDialogsInFolderMaxValue())
|
, _chatsList(PinnedDialogsInFolderMaxValue())
|
||||||
, _name(lang(lng_archived_chats)) {
|
, _name(lang(lng_archived_name)) {
|
||||||
indexNameParts();
|
indexNameParts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +90,9 @@ void Folder::indexNameParts() {
|
||||||
void Folder::registerOne(not_null<History*> history) {
|
void Folder::registerOne(not_null<History*> history) {
|
||||||
if (_chatsList.indexed()->size() == 1) {
|
if (_chatsList.indexed()->size() == 1) {
|
||||||
updateChatListSortPosition();
|
updateChatListSortPosition();
|
||||||
|
} else {
|
||||||
|
++_chatListViewVersion;
|
||||||
|
updateChatListEntry();
|
||||||
}
|
}
|
||||||
applyChatListMessage(history->chatListMessage());
|
applyChatListMessage(history->chatListMessage());
|
||||||
}
|
}
|
||||||
|
@ -96,6 +100,9 @@ void Folder::registerOne(not_null<History*> history) {
|
||||||
void Folder::unregisterOne(not_null<History*> history) {
|
void Folder::unregisterOne(not_null<History*> history) {
|
||||||
if (_chatsList.empty()) {
|
if (_chatsList.empty()) {
|
||||||
updateChatListExistence();
|
updateChatListExistence();
|
||||||
|
} else {
|
||||||
|
++_chatListViewVersion;
|
||||||
|
updateChatListEntry();
|
||||||
}
|
}
|
||||||
if (_chatListMessage && _chatListMessage->history() == history) {
|
if (_chatListMessage && _chatListMessage->history() == history) {
|
||||||
computeChatListMessage();
|
computeChatListMessage();
|
||||||
|
@ -106,6 +113,12 @@ void Folder::oneListMessageChanged(HistoryItem *from, HistoryItem *to) {
|
||||||
if (!applyChatListMessage(to) && _chatListMessage == from) {
|
if (!applyChatListMessage(to) && _chatListMessage == from) {
|
||||||
computeChatListMessage();
|
computeChatListMessage();
|
||||||
}
|
}
|
||||||
|
if (from || to) {
|
||||||
|
const auto history = from ? from->history() : to->history();
|
||||||
|
if (!history->chatListUnreadState().empty()) {
|
||||||
|
reorderUnreadHistories();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Folder::applyChatListMessage(HistoryItem *item) {
|
bool Folder::applyChatListMessage(HistoryItem *item) {
|
||||||
|
@ -141,6 +154,55 @@ void Folder::computeChatListMessage() {
|
||||||
updateChatListEntry();
|
updateChatListEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Folder::addUnreadHistory(not_null<History*> history) {
|
||||||
|
const auto i = ranges::find(_unreadHistories, history);
|
||||||
|
if (i == end(_unreadHistories)) {
|
||||||
|
_unreadHistories.push_back(history);
|
||||||
|
reorderUnreadHistories();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::removeUnreadHistory(not_null<History*> history) {
|
||||||
|
const auto i = ranges::find(_unreadHistories, history);
|
||||||
|
if (i != end(_unreadHistories)) {
|
||||||
|
_unreadHistories.erase(i);
|
||||||
|
reorderUnreadHistories();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::reorderUnreadHistories() {
|
||||||
|
// We want first kShowChatNamesCount histories, by last message date.
|
||||||
|
const auto predicate = [](not_null<History*> a, not_null<History*> b) {
|
||||||
|
const auto aItem = a->chatListMessage();
|
||||||
|
const auto bItem = b->chatListMessage();
|
||||||
|
const auto aDate = aItem ? aItem->date() : TimeId(0);
|
||||||
|
const auto bDate = bItem ? bItem->date() : TimeId(0);
|
||||||
|
return aDate > bDate;
|
||||||
|
};
|
||||||
|
if (size(_unreadHistories) <= kShowChatNamesCount) {
|
||||||
|
ranges::sort(_unreadHistories, predicate);
|
||||||
|
if (!ranges::equal(_unreadHistories, _unreadHistoriesLast)) {
|
||||||
|
_unreadHistoriesLast = _unreadHistories;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const auto till = begin(_unreadHistories) + kShowChatNamesCount - 1;
|
||||||
|
ranges::nth_element(_unreadHistories, till, predicate);
|
||||||
|
if constexpr (kShowChatNamesCount > 2) {
|
||||||
|
ranges::sort(begin(_unreadHistories), till, predicate);
|
||||||
|
}
|
||||||
|
auto &&head = ranges::view::all(
|
||||||
|
_unreadHistories
|
||||||
|
) | ranges::view::take_exactly(
|
||||||
|
kShowChatNamesCount
|
||||||
|
);
|
||||||
|
if (!ranges::equal(head, _unreadHistoriesLast)) {
|
||||||
|
_unreadHistoriesLast = head | ranges::to_vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++_chatListViewVersion;
|
||||||
|
updateChatListEntry();
|
||||||
|
}
|
||||||
|
|
||||||
not_null<Dialogs::MainList*> Folder::chatsList() {
|
not_null<Dialogs::MainList*> Folder::chatsList() {
|
||||||
return &_chatsList;
|
return &_chatsList;
|
||||||
}
|
}
|
||||||
|
@ -194,6 +256,29 @@ void Folder::setChatsListLoaded(bool loaded) {
|
||||||
_chatsList.setLoaded(loaded);
|
_chatsList.setLoaded(loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Folder::setCloudChatsListSize(int size) {
|
||||||
|
_cloudChatsListSize = size;
|
||||||
|
updateChatListEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Folder::chatsListSize() const {
|
||||||
|
return std::max(
|
||||||
|
_chatsList.indexed()->size(),
|
||||||
|
_chatsList.loaded() ? 0 : _cloudChatsListSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Folder::unreadHistoriesCount() const {
|
||||||
|
return _unreadHistories.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<not_null<History*>> &Folder::lastUnreadHistories() const {
|
||||||
|
return _unreadHistoriesLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Folder::chatListViewVersion() const {
|
||||||
|
return _chatListViewVersion;
|
||||||
|
}
|
||||||
|
|
||||||
void Folder::requestChatListMessage() {
|
void Folder::requestChatListMessage() {
|
||||||
if (!chatListMessageKnown()) {
|
if (!chatListMessageKnown()) {
|
||||||
session().api().requestDialogEntry(this);
|
session().api().requestDialogEntry(this);
|
||||||
|
@ -252,8 +337,17 @@ void Folder::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::unreadStateChanged(
|
void Folder::unreadStateChanged(
|
||||||
|
const Dialogs::Key &key,
|
||||||
const Dialogs::UnreadState &wasState,
|
const Dialogs::UnreadState &wasState,
|
||||||
const Dialogs::UnreadState &nowState) {
|
const Dialogs::UnreadState &nowState) {
|
||||||
|
if (const auto history = key.history()) {
|
||||||
|
if (!wasState.empty() && nowState.empty()) {
|
||||||
|
removeUnreadHistory(history);
|
||||||
|
} else if (wasState.empty() && !nowState.empty()) {
|
||||||
|
addUnreadHistory(history);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const auto updateCloudUnread = _cloudUnread.messagesCount.has_value()
|
const auto updateCloudUnread = _cloudUnread.messagesCount.has_value()
|
||||||
&& wasState.messagesCount.has_value();
|
&& wasState.messagesCount.has_value();
|
||||||
const auto notify = _chatsList.loaded() || updateCloudUnread;
|
const auto notify = _chatsList.loaded() || updateCloudUnread;
|
||||||
|
@ -276,8 +370,19 @@ void Folder::unreadStateChanged(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::unreadEntryChanged(
|
void Folder::unreadEntryChanged(
|
||||||
|
const Dialogs::Key &key,
|
||||||
const Dialogs::UnreadState &state,
|
const Dialogs::UnreadState &state,
|
||||||
bool added) {
|
bool added) {
|
||||||
|
if (const auto history = key.history()) {
|
||||||
|
if (!state.empty()) {
|
||||||
|
if (added) {
|
||||||
|
addUnreadHistory(history);
|
||||||
|
} else {
|
||||||
|
removeUnreadHistory(history);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const auto updateCloudUnread = _cloudUnread.messagesCount.has_value()
|
const auto updateCloudUnread = _cloudUnread.messagesCount.has_value()
|
||||||
&& state.messagesCount.has_value();
|
&& state.messagesCount.has_value();
|
||||||
const auto notify = _chatsList.loaded() || updateCloudUnread;
|
const auto notify = _chatsList.loaded() || updateCloudUnread;
|
||||||
|
|
|
@ -44,9 +44,13 @@ public:
|
||||||
|
|
||||||
void updateCloudUnread(const MTPDdialogFolder &data);
|
void updateCloudUnread(const MTPDdialogFolder &data);
|
||||||
void unreadStateChanged(
|
void unreadStateChanged(
|
||||||
|
const Dialogs::Key &key,
|
||||||
const Dialogs::UnreadState &wasState,
|
const Dialogs::UnreadState &wasState,
|
||||||
const Dialogs::UnreadState &nowState);
|
const Dialogs::UnreadState &nowState);
|
||||||
void unreadEntryChanged(const Dialogs::UnreadState &state, bool added);
|
void unreadEntryChanged(
|
||||||
|
const Dialogs::Key &key,
|
||||||
|
const Dialogs::UnreadState &state,
|
||||||
|
bool added);
|
||||||
|
|
||||||
TimeId adjustedChatListTimeId() const override;
|
TimeId adjustedChatListTimeId() const override;
|
||||||
|
|
||||||
|
@ -73,12 +77,22 @@ public:
|
||||||
|
|
||||||
bool chatsListLoaded() const;
|
bool chatsListLoaded() const;
|
||||||
void setChatsListLoaded(bool loaded = true);
|
void setChatsListLoaded(bool loaded = true);
|
||||||
|
void setCloudChatsListSize(int size);
|
||||||
|
|
||||||
|
int chatsListSize() const;
|
||||||
|
int unreadHistoriesCount() const;
|
||||||
|
const std::vector<not_null<History*>> &lastUnreadHistories() const;
|
||||||
|
uint32 chatListViewVersion() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void indexNameParts();
|
void indexNameParts();
|
||||||
bool applyChatListMessage(HistoryItem *item);
|
bool applyChatListMessage(HistoryItem *item);
|
||||||
void computeChatListMessage();
|
void computeChatListMessage();
|
||||||
|
|
||||||
|
void addUnreadHistory(not_null<History*> history);
|
||||||
|
void removeUnreadHistory(not_null<History*> history);
|
||||||
|
void reorderUnreadHistories();
|
||||||
|
|
||||||
FolderId _id = 0;
|
FolderId _id = 0;
|
||||||
Dialogs::MainList _chatsList;
|
Dialogs::MainList _chatsList;
|
||||||
|
|
||||||
|
@ -87,7 +101,11 @@ private:
|
||||||
base::flat_set<QChar> _nameFirstLetters;
|
base::flat_set<QChar> _nameFirstLetters;
|
||||||
|
|
||||||
Dialogs::UnreadState _cloudUnread;
|
Dialogs::UnreadState _cloudUnread;
|
||||||
|
int _cloudChatsListSize = 0;
|
||||||
|
std::vector<not_null<History*>> _unreadHistories;
|
||||||
|
std::vector<not_null<History*>> _unreadHistoriesLast;
|
||||||
HistoryItem *_chatListMessage = nullptr;
|
HistoryItem *_chatListMessage = nullptr;
|
||||||
|
uint32 _chatListViewVersion = 0;
|
||||||
//rpl::variable<MessagePosition> _unreadPosition;
|
//rpl::variable<MessagePosition> _unreadPosition;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1375,13 +1375,17 @@ void Session::applyPinnedChats(
|
||||||
void Session::applyDialogs(
|
void Session::applyDialogs(
|
||||||
Data::Folder *requestFolder,
|
Data::Folder *requestFolder,
|
||||||
const QVector<MTPMessage> &messages,
|
const QVector<MTPMessage> &messages,
|
||||||
const QVector<MTPDialog> &dialogs) {
|
const QVector<MTPDialog> &dialogs,
|
||||||
|
std::optional<int> count) {
|
||||||
App::feedMsgs(messages, NewMessageLast);
|
App::feedMsgs(messages, NewMessageLast);
|
||||||
for (const auto &dialog : dialogs) {
|
for (const auto &dialog : dialogs) {
|
||||||
dialog.match([&](const auto &data) {
|
dialog.match([&](const auto &data) {
|
||||||
applyDialog(requestFolder, data);
|
applyDialog(requestFolder, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (requestFolder && count) {
|
||||||
|
requestFolder->setCloudChatsListSize(*count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::applyDialog(
|
void Session::applyDialog(
|
||||||
|
@ -1663,7 +1667,7 @@ void Session::unreadStateChanged(
|
||||||
|
|
||||||
const auto nowState = key.entry()->chatListUnreadState();
|
const auto nowState = key.entry()->chatListUnreadState();
|
||||||
if (const auto folder = key.entry()->folder()) {
|
if (const auto folder = key.entry()->folder()) {
|
||||||
folder->unreadStateChanged(wasState, nowState);
|
folder->unreadStateChanged(key, wasState, nowState);
|
||||||
} else {
|
} else {
|
||||||
_chatsList.unreadStateChanged(wasState, nowState);
|
_chatsList.unreadStateChanged(wasState, nowState);
|
||||||
}
|
}
|
||||||
|
@ -1674,10 +1678,12 @@ void Session::unreadEntryChanged(const Dialogs::Key &key, bool added) {
|
||||||
Expects(key.entry()->folderKnown());
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
const auto state = key.entry()->chatListUnreadState();
|
const auto state = key.entry()->chatListUnreadState();
|
||||||
if (const auto folder = key.entry()->folder()) {
|
if (!state.empty()) {
|
||||||
folder->unreadEntryChanged(state, added);
|
if (const auto folder = key.entry()->folder()) {
|
||||||
} else {
|
folder->unreadEntryChanged(key, state, added);
|
||||||
_chatsList.unreadEntryChanged(state, added);
|
} else {
|
||||||
|
_chatsList.unreadEntryChanged(state, added);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -296,7 +296,8 @@ public:
|
||||||
void applyDialogs(
|
void applyDialogs(
|
||||||
Data::Folder *requestFolder,
|
Data::Folder *requestFolder,
|
||||||
const QVector<MTPMessage> &messages,
|
const QVector<MTPMessage> &messages,
|
||||||
const QVector<MTPDialog> &dialogs);
|
const QVector<MTPDialog> &dialogs,
|
||||||
|
std::optional<int> count = std::nullopt);
|
||||||
void addSavedPeersAfter(const QDateTime &date);
|
void addSavedPeersAfter(const QDateTime &date);
|
||||||
void addAllSavedPeers();
|
void addAllSavedPeers();
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,10 @@ struct UnreadState {
|
||||||
int chatsCountMuted = 0;
|
int chatsCountMuted = 0;
|
||||||
bool mark = false;
|
bool mark = false;
|
||||||
bool markMuted = false;
|
bool markMuted = false;
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return !messagesCount.value_or(0) && !chatsCount && !mark;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Entry {
|
class Entry {
|
||||||
|
|
|
@ -34,7 +34,7 @@ bool ShowUserBotIcon(not_null<UserData*> user) {
|
||||||
return user->isBot() && !user->isSupport();
|
return user->isBot() && !user->isSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
void paintRowTopRight(Painter &p, const QString &text, QRect &rectForName, bool active, bool selected) {
|
void PaintRowTopRight(Painter &p, const QString &text, QRect &rectForName, bool active, bool selected) {
|
||||||
const auto width = st::dialogsDateFont->width(text);
|
const auto width = st::dialogsDateFont->width(text);
|
||||||
rectForName.setWidth(rectForName.width() - width - st::dialogsDateSkip);
|
rectForName.setWidth(rectForName.width() - width - st::dialogsDateSkip);
|
||||||
p.setFont(st::dialogsDateFont);
|
p.setFont(st::dialogsDateFont);
|
||||||
|
@ -42,7 +42,7 @@ void paintRowTopRight(Painter &p, const QString &text, QRect &rectForName, bool
|
||||||
p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, text);
|
p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void paintRowDate(Painter &p, QDateTime date, QRect &rectForName, bool active, bool selected) {
|
void PaintRowDate(Painter &p, QDateTime date, QRect &rectForName, bool active, bool selected) {
|
||||||
const auto now = QDateTime::currentDateTime();
|
const auto now = QDateTime::currentDateTime();
|
||||||
const auto &lastTime = date;
|
const auto &lastTime = date;
|
||||||
const auto nowDate = now.date();
|
const auto nowDate = now.date();
|
||||||
|
@ -60,7 +60,7 @@ void paintRowDate(Painter &p, QDateTime date, QRect &rectForName, bool active, b
|
||||||
return lastDate.toString(qsl("d.MM.yy"));
|
return lastDate.toString(qsl("d.MM.yy"));
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
paintRowTopRight(p, dt, rectForName, active, selected);
|
PaintRowTopRight(p, dt, rectForName, active, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintNarrowCounter(
|
void PaintNarrowCounter(
|
||||||
|
@ -159,6 +159,38 @@ int PaintWideCounter(
|
||||||
return availableWidth;
|
return availableWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PaintListEntryText(
|
||||||
|
Painter &p,
|
||||||
|
QRect rect,
|
||||||
|
bool active,
|
||||||
|
bool selected,
|
||||||
|
not_null<const Row*> row) {
|
||||||
|
if (rect.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row->validateListEntryCache();
|
||||||
|
const auto &palette = active
|
||||||
|
? st::dialogsTextPaletteActive
|
||||||
|
: selected
|
||||||
|
? st::dialogsTextPaletteOver
|
||||||
|
: st::dialogsTextPalette;
|
||||||
|
const auto &color = active
|
||||||
|
? st::dialogsTextFgActive
|
||||||
|
: selected
|
||||||
|
? st::dialogsTextFgOver
|
||||||
|
: st::dialogsTextFg;
|
||||||
|
p.setTextPalette(palette);
|
||||||
|
p.setFont(st::dialogsTextFont);
|
||||||
|
p.setPen(color);
|
||||||
|
row->listEntryCache().drawElided(
|
||||||
|
p,
|
||||||
|
rect.left(),
|
||||||
|
rect.top(),
|
||||||
|
rect.width(),
|
||||||
|
rect.height() / st::dialogsTextFont->height);
|
||||||
|
p.restoreTextPalette();
|
||||||
|
}
|
||||||
|
|
||||||
enum class Flag {
|
enum class Flag {
|
||||||
Active = 0x01,
|
Active = 0x01,
|
||||||
Selected = 0x02,
|
Selected = 0x02,
|
||||||
|
@ -255,7 +287,7 @@ void paintRow(
|
||||||
&& !(flags & (Flag::SearchResult/* | Flag::FeedSearchResult*/)); // #feed
|
&& !(flags & (Flag::SearchResult/* | Flag::FeedSearchResult*/)); // #feed
|
||||||
if (promoted) {
|
if (promoted) {
|
||||||
const auto text = lang(lng_proxy_sponsor);
|
const auto text = lang(lng_proxy_sponsor);
|
||||||
paintRowTopRight(p, text, rectForName, active, selected);
|
PaintRowTopRight(p, text, rectForName, active, selected);
|
||||||
} else if (from/* && !(flags & Flag::FeedSearchResult)*/) { // #feed
|
} else if (from/* && !(flags & Flag::FeedSearchResult)*/) { // #feed
|
||||||
if (const auto chatTypeIcon = ChatTypeIcon(from, active, selected)) {
|
if (const auto chatTypeIcon = ChatTypeIcon(from, active, selected)) {
|
||||||
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
|
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
|
||||||
|
@ -274,7 +306,7 @@ void paintRow(
|
||||||
|| (supportMode
|
|| (supportMode
|
||||||
&& Auth().supportHelper().isOccupiedBySomeone(history))) {
|
&& Auth().supportHelper().isOccupiedBySomeone(history))) {
|
||||||
if (!promoted) {
|
if (!promoted) {
|
||||||
paintRowDate(p, date, rectForName, active, selected);
|
PaintRowDate(p, date, rectForName, active, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto availableWidth = namewidth;
|
auto availableWidth = namewidth;
|
||||||
|
@ -318,7 +350,7 @@ void paintRow(
|
||||||
}
|
}
|
||||||
} else if (!item->isEmpty()) {
|
} else if (!item->isEmpty()) {
|
||||||
if (!promoted) {
|
if (!promoted) {
|
||||||
paintRowDate(p, date, rectForName, active, selected);
|
PaintRowDate(p, date, rectForName, active, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
paintItemCallback(nameleft, namewidth);
|
paintItemCallback(nameleft, namewidth);
|
||||||
|
@ -560,7 +592,7 @@ void RowPainter::paint(
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
const auto displayDate = [item, cloudDraft] {
|
const auto displayDate = [&] {
|
||||||
if (item) {
|
if (item) {
|
||||||
if (cloudDraft) {
|
if (cloudDraft) {
|
||||||
return (item->date() > cloudDraft->date)
|
return (item->date() > cloudDraft->date)
|
||||||
|
@ -623,20 +655,22 @@ void RowPainter::paint(
|
||||||
: (selected
|
: (selected
|
||||||
? st::dialogsTextFgServiceOver
|
? st::dialogsTextFgServiceOver
|
||||||
: st::dialogsTextFgService);
|
: st::dialogsTextFgService);
|
||||||
const auto actionWasPainted = history ? history->paintSendAction(
|
const auto itemRect = QRect(
|
||||||
p,
|
|
||||||
nameleft,
|
nameleft,
|
||||||
texttop,
|
texttop,
|
||||||
availableWidth,
|
availableWidth,
|
||||||
|
st::dialogsTextFont->height);
|
||||||
|
const auto actionWasPainted = history ? history->paintSendAction(
|
||||||
|
p,
|
||||||
|
itemRect.x(),
|
||||||
|
itemRect.y(),
|
||||||
|
itemRect.width(),
|
||||||
fullWidth,
|
fullWidth,
|
||||||
color,
|
color,
|
||||||
ms) : false;
|
ms) : false;
|
||||||
if (!actionWasPainted) {
|
if (const auto folder = row->folder()) {
|
||||||
const auto itemRect = QRect(
|
PaintListEntryText(p, itemRect, active, selected, row);
|
||||||
nameleft,
|
} else if (!actionWasPainted) {
|
||||||
texttop,
|
|
||||||
availableWidth,
|
|
||||||
st::dialogsTextFont->height);
|
|
||||||
item->drawInDialog(
|
item->drawInDialog(
|
||||||
p,
|
p,
|
||||||
itemRect,
|
itemRect,
|
||||||
|
|
|
@ -7,12 +7,49 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "dialogs/dialogs_row.h"
|
#include "dialogs/dialogs_row.h"
|
||||||
|
|
||||||
#include "styles/style_dialogs.h"
|
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
#include "ui/text_options.h"
|
||||||
#include "dialogs/dialogs_entry.h"
|
#include "dialogs/dialogs_entry.h"
|
||||||
|
#include "data/data_folder.h"
|
||||||
|
#include "history/history.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
QString ComposeFolderListEntryText(not_null<Data::Folder*> folder) {
|
||||||
|
const auto &list = folder->lastUnreadHistories();
|
||||||
|
if (list.empty()) {
|
||||||
|
const auto count = folder->chatsListSize();
|
||||||
|
if (!count) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return lng_archived_chats(lt_count, count);
|
||||||
|
}
|
||||||
|
const auto count = std::max(
|
||||||
|
int(list.size()),
|
||||||
|
folder->unreadHistoriesCount());
|
||||||
|
if (list.size() == 1) {
|
||||||
|
return App::peerName(list[0]->peer);
|
||||||
|
} else if (count == 2) {
|
||||||
|
return lng_archived_unread_two(
|
||||||
|
lt_chat,
|
||||||
|
App::peerName(list[0]->peer),
|
||||||
|
lt_second_chat,
|
||||||
|
App::peerName(list[1]->peer));
|
||||||
|
}
|
||||||
|
return lng_archived_unread(
|
||||||
|
lt_count,
|
||||||
|
count - 2,
|
||||||
|
lt_chat,
|
||||||
|
App::peerName(list[0]->peer),
|
||||||
|
lt_second_chat,
|
||||||
|
App::peerName(list[1]->peer));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
RippleRow::RippleRow() = default;
|
RippleRow::RippleRow() = default;
|
||||||
RippleRow::~RippleRow() = default;
|
RippleRow::~RippleRow() = default;
|
||||||
|
@ -44,6 +81,22 @@ uint64 Row::sortKey() const {
|
||||||
return _id.entry()->sortKeyInChatList();
|
return _id.entry()->sortKeyInChatList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Row::validateListEntryCache() const {
|
||||||
|
const auto folder = _id.folder();
|
||||||
|
if (!folder) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto version = folder->chatListViewVersion();
|
||||||
|
if (_listEntryCacheVersion == version) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_listEntryCacheVersion = version;
|
||||||
|
_listEntryCache.setText(
|
||||||
|
st::dialogsTextStyle,
|
||||||
|
ComposeFolderListEntryText(folder),
|
||||||
|
Ui::DialogTextOptions());
|
||||||
|
}
|
||||||
|
|
||||||
FakeRow::FakeRow(Key searchInChat, not_null<HistoryItem*> item)
|
FakeRow::FakeRow(Key searchInChat, not_null<HistoryItem*> item)
|
||||||
: _searchInChat(searchInChat)
|
: _searchInChat(searchInChat)
|
||||||
, _item(item)
|
, _item(item)
|
||||||
|
|
|
@ -62,6 +62,11 @@ public:
|
||||||
}
|
}
|
||||||
uint64 sortKey() const;
|
uint64 sortKey() const;
|
||||||
|
|
||||||
|
void validateListEntryCache() const;
|
||||||
|
const Text &listEntryCache() const {
|
||||||
|
return _listEntryCache;
|
||||||
|
}
|
||||||
|
|
||||||
// for any attached data, for example View in contacts list
|
// for any attached data, for example View in contacts list
|
||||||
void *attached = nullptr;
|
void *attached = nullptr;
|
||||||
|
|
||||||
|
@ -70,6 +75,8 @@ private:
|
||||||
|
|
||||||
Key _id;
|
Key _id;
|
||||||
int _pos = 0;
|
int _pos = 0;
|
||||||
|
mutable uint32 _listEntryCacheVersion = 0;
|
||||||
|
mutable Text _listEntryCache;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -742,17 +742,18 @@ void HistoryItem::drawInDialog(
|
||||||
DrawInDialog way,
|
DrawInDialog way,
|
||||||
const HistoryItem *&cacheFor,
|
const HistoryItem *&cacheFor,
|
||||||
Text &cache) const {
|
Text &cache) const {
|
||||||
|
if (r.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (cacheFor != this) {
|
if (cacheFor != this) {
|
||||||
cacheFor = this;
|
cacheFor = this;
|
||||||
cache.setText(st::dialogsTextStyle, inDialogsText(way), Ui::DialogTextOptions());
|
cache.setText(st::dialogsTextStyle, inDialogsText(way), Ui::DialogTextOptions());
|
||||||
}
|
}
|
||||||
if (r.width()) {
|
p.setTextPalette(active ? st::dialogsTextPaletteActive : (selected ? st::dialogsTextPaletteOver : st::dialogsTextPalette));
|
||||||
p.setTextPalette(active ? st::dialogsTextPaletteActive : (selected ? st::dialogsTextPaletteOver : st::dialogsTextPalette));
|
p.setFont(st::dialogsTextFont);
|
||||||
p.setFont(st::dialogsTextFont);
|
p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg));
|
||||||
p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg));
|
cache.drawElided(p, r.left(), r.top(), r.width(), r.height() / st::dialogsTextFont->height);
|
||||||
cache.drawElided(p, r.left(), r.top(), r.width(), r.height() / st::dialogsTextFont->height);
|
p.restoreTextPalette();
|
||||||
p.restoreTextPalette();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryItem::~HistoryItem() {
|
HistoryItem::~HistoryItem() {
|
||||||
|
|
|
@ -796,8 +796,8 @@ void PeerMenuAddMuteAction(
|
||||||
void ToggleHistoryArchived(not_null<History*> history, bool archived) {
|
void ToggleHistoryArchived(not_null<History*> history, bool archived) {
|
||||||
const auto callback = [=] {
|
const auto callback = [=] {
|
||||||
Ui::Toast::Show(lang(archived
|
Ui::Toast::Show(lang(archived
|
||||||
? lng_chat_archived
|
? lng_archived_added
|
||||||
: lng_chat_unarchived));
|
: lng_archived_removed));
|
||||||
};
|
};
|
||||||
history->session().api().toggleHistoryArchived(
|
history->session().api().toggleHistoryArchived(
|
||||||
history,
|
history,
|
||||||
|
|
Loading…
Reference in New Issue