mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Track mentions / reactions together with unread.
This commit is contained in:
parent
5356f6cd2c
commit
4910a60499
22 changed files with 407 additions and 478 deletions
|
@ -1711,11 +1711,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
if (const auto history = session().data().historyLoaded(id)) {
|
if (const auto history = session().data().historyLoaded(id)) {
|
||||||
history->setUnreadMark(data.is_unread());
|
history->setUnreadMark(data.is_unread());
|
||||||
}
|
}
|
||||||
}, [&](const MTPDdialogPeerFolder &dialog) {
|
}, [](const MTPDdialogPeerFolder &dialog) {
|
||||||
//const auto id = dialog.vfolder_id().v; // #TODO archive
|
|
||||||
//if (const auto folder = session().data().folderLoaded(id)) {
|
|
||||||
// folder->setUnreadMark(data.is_unread());
|
|
||||||
//}
|
|
||||||
});
|
});
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -204,17 +204,19 @@ bool ChatFilter::contains(not_null<History*> history) const {
|
||||||
if (_never.contains(history)) {
|
if (_never.contains(history)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const auto state = (_flags & (Flag::NoMuted | Flag::NoRead))
|
||||||
|
? history->chatListBadgesState()
|
||||||
|
: Dialogs::BadgesState();
|
||||||
return false
|
return false
|
||||||
|| ((_flags & flag)
|
|| ((_flags & flag)
|
||||||
&& (!(_flags & Flag::NoMuted)
|
&& (!(_flags & Flag::NoMuted)
|
||||||
|| !history->muted()
|
|| !history->muted()
|
||||||
|| (history->unreadMentions().has()
|
|| (state.mention
|
||||||
&& history->folderKnown()
|
&& history->folderKnown()
|
||||||
&& !history->folder()))
|
&& !history->folder()))
|
||||||
&& (!(_flags & Flag::NoRead)
|
&& (!(_flags & Flag::NoRead)
|
||||||
|| history->chatListUnreadCount()
|
|| state.unread
|
||||||
|| history->unreadMark()
|
|| state.mention
|
||||||
|| history->unreadMentions().has()
|
|
||||||
|| history->fakeUnreadWhileOpened())
|
|| history->fakeUnreadWhileOpened())
|
||||||
&& (!(_flags & Flag::NoArchived)
|
&& (!(_flags & Flag::NoArchived)
|
||||||
|| (history->folderKnown() && !history->folder())))
|
|| (history->folderKnown() && !history->folder())))
|
||||||
|
|
|
@ -62,7 +62,6 @@ Folder::Folder(not_null<Data::Session*> owner, FolderId id)
|
||||||
}) | rpl::start_with_next([=](const Dialogs::UnreadState &old) {
|
}) | rpl::start_with_next([=](const Dialogs::UnreadState &old) {
|
||||||
++_chatListViewVersion;
|
++_chatListViewVersion;
|
||||||
notifyUnreadStateChange(old);
|
notifyUnreadStateChange(old);
|
||||||
updateChatListEntryPostponed();
|
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
_chatsList.fullSize().changes(
|
_chatsList.fullSize().changes(
|
||||||
|
@ -328,24 +327,20 @@ bool Folder::shouldBeInChatList() const {
|
||||||
return !_chatsList.empty();
|
return !_chatsList.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Folder::chatListUnreadCount() const {
|
|
||||||
const auto state = chatListUnreadState();
|
|
||||||
return state.marks
|
|
||||||
+ (Core::App().settings().countUnreadMessages()
|
|
||||||
? state.messages
|
|
||||||
: state.chats);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dialogs::UnreadState Folder::chatListUnreadState() const {
|
Dialogs::UnreadState Folder::chatListUnreadState() const {
|
||||||
return _chatsList.unreadState();
|
return _chatsList.unreadState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Folder::chatListUnreadMark() const {
|
Dialogs::BadgesState Folder::chatListBadgesState() const {
|
||||||
return false;
|
auto result = Dialogs::BadgesForUnread(
|
||||||
}
|
chatListUnreadState(),
|
||||||
|
Dialogs::CountInBadge::Chats,
|
||||||
bool Folder::chatListMutedBadge() const {
|
Dialogs::IncludeInBadge::All);
|
||||||
return true;
|
result.unreadMuted = result.mentionMuted = result.reactionMuted = true;
|
||||||
|
if (result.unread && !result.unreadCounter) {
|
||||||
|
result.unreadCounter = 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryItem *Folder::chatListMessage() const {
|
HistoryItem *Folder::chatListMessage() const {
|
||||||
|
|
|
@ -44,10 +44,8 @@ public:
|
||||||
|
|
||||||
int fixedOnTopIndex() const override;
|
int fixedOnTopIndex() const override;
|
||||||
bool shouldBeInChatList() const override;
|
bool shouldBeInChatList() const override;
|
||||||
int chatListUnreadCount() const override;
|
|
||||||
bool chatListUnreadMark() const override;
|
|
||||||
bool chatListMutedBadge() const override;
|
|
||||||
Dialogs::UnreadState chatListUnreadState() const override;
|
Dialogs::UnreadState chatListUnreadState() const override;
|
||||||
|
Dialogs::BadgesState chatListBadgesState() const override;
|
||||||
HistoryItem *chatListMessage() const override;
|
HistoryItem *chatListMessage() const override;
|
||||||
bool chatListMessageKnown() const override;
|
bool chatListMessageKnown() const override;
|
||||||
void requestChatListMessage() override;
|
void requestChatListMessage() override;
|
||||||
|
|
|
@ -155,7 +155,6 @@ ForumTopic::ForumTopic(not_null<Forum*> forum, MsgId rootId)
|
||||||
_replies->unreadCountValue(
|
_replies->unreadCountValue(
|
||||||
) | rpl::combine_previous(
|
) | rpl::combine_previous(
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
session().changes().topicUpdated(this, UpdateFlag::UnreadView);
|
|
||||||
return inChatList();
|
return inChatList();
|
||||||
}) | rpl::start_with_next([=](
|
}) | rpl::start_with_next([=](
|
||||||
std::optional<int> previous,
|
std::optional<int> previous,
|
||||||
|
@ -602,87 +601,52 @@ bool ForumTopic::isServerSideUnread(
|
||||||
return _replies->isServerSideUnread(item);
|
return _replies->isServerSideUnread(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ForumTopic::unreadCount() const {
|
|
||||||
return _replies->unreadCountCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ForumTopic::unreadCountForBadge() const {
|
|
||||||
const auto result = unreadCount();
|
|
||||||
return (!result && unreadMark()) ? 1 : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForumTopic::setMuted(bool muted) {
|
void ForumTopic::setMuted(bool muted) {
|
||||||
if (this->muted() == muted) {
|
if (this->muted() == muted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto refresher = gsl::finally([&] {
|
const auto state = chatListBadgesState();
|
||||||
if (inChatList()) {
|
const auto notify = state.unread || state.reaction;
|
||||||
updateChatListEntry();
|
|
||||||
}
|
|
||||||
session().changes().topicUpdated(
|
|
||||||
this,
|
|
||||||
Data::TopicUpdate::Flag::Notifications);
|
|
||||||
});
|
|
||||||
const auto notify = (unreadCountForBadge() > 0);
|
|
||||||
const auto notifier = unreadStateChangeNotifier(notify);
|
const auto notifier = unreadStateChangeNotifier(notify);
|
||||||
Thread::setMuted(muted);
|
Thread::setMuted(muted);
|
||||||
}
|
session().changes().topicUpdated(
|
||||||
|
this,
|
||||||
bool ForumTopic::unreadCountKnown() const {
|
Data::TopicUpdate::Flag::Notifications);
|
||||||
return _replies->unreadCountKnown();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForumTopic::setUnreadMark(bool unread) {
|
|
||||||
if (unreadMark() == unread) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto noUnreadMessages = !unreadCount();
|
|
||||||
const auto refresher = gsl::finally([&] {
|
|
||||||
if (inChatList() && noUnreadMessages) {
|
|
||||||
updateChatListEntry();
|
|
||||||
}
|
|
||||||
session().changes().topicUpdated(this, UpdateFlag::UnreadView);
|
|
||||||
});
|
|
||||||
const auto notifier = unreadStateChangeNotifier(noUnreadMessages);
|
|
||||||
Thread::setUnreadMark(unread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<HistoryView::SendActionPainter*> ForumTopic::sendActionPainter() {
|
not_null<HistoryView::SendActionPainter*> ForumTopic::sendActionPainter() {
|
||||||
return _sendActionPainter.get();
|
return _sendActionPainter.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ForumTopic::chatListUnreadCount() const {
|
Dialogs::UnreadState ForumTopic::chatListUnreadState() const {
|
||||||
return unreadCount();
|
return unreadStateFor(
|
||||||
|
_replies->unreadCountCurrent(),
|
||||||
|
_replies->unreadCountKnown());
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialogs::UnreadState ForumTopic::chatListUnreadState() const {
|
Dialogs::BadgesState ForumTopic::chatListBadgesState() const {
|
||||||
return unreadStateFor(unreadCount(), unreadCountKnown());
|
return Dialogs::BadgesForUnread(
|
||||||
|
chatListUnreadState(),
|
||||||
|
Dialogs::CountInBadge::Messages,
|
||||||
|
Dialogs::IncludeInBadge::All);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialogs::UnreadState ForumTopic::unreadStateFor(
|
Dialogs::UnreadState ForumTopic::unreadStateFor(
|
||||||
int count,
|
int count,
|
||||||
bool known) const {
|
bool known) const {
|
||||||
auto result = Dialogs::UnreadState();
|
auto result = Dialogs::UnreadState();
|
||||||
const auto mark = !count && unreadMark();
|
|
||||||
const auto muted = this->muted();
|
const auto muted = this->muted();
|
||||||
result.messages = count;
|
result.messages = count;
|
||||||
result.messagesMuted = muted ? count : 0;
|
|
||||||
result.chats = count ? 1 : 0;
|
result.chats = count ? 1 : 0;
|
||||||
result.chatsMuted = (count && muted) ? 1 : 0;
|
result.mentions = unreadMentions().has() ? 1 : 0;
|
||||||
result.marks = mark ? 1 : 0;
|
result.reactions = unreadReactions().has() ? 1 : 0;
|
||||||
result.marksMuted = (mark && muted) ? 1 : 0;
|
result.messagesMuted = muted ? result.messages : 0;
|
||||||
|
result.chatsMuted = muted ? result.chats : 0;
|
||||||
|
result.reactionsMuted = muted ? result.reactions : 0;
|
||||||
result.known = known;
|
result.known = known;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ForumTopic::chatListUnreadMark() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForumTopic::chatListMutedBadge() const {
|
|
||||||
return muted();
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryItem *ForumTopic::chatListMessage() const {
|
HistoryItem *ForumTopic::chatListMessage() const {
|
||||||
return _lastMessage.value_or(nullptr);
|
return _lastMessage.value_or(nullptr);
|
||||||
}
|
}
|
||||||
|
@ -703,6 +667,27 @@ const base::flat_set<QChar> &ForumTopic::chatListFirstLetters() const {
|
||||||
return _titleFirstLetters;
|
return _titleFirstLetters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ForumTopic::hasUnreadMentionChanged(bool has) {
|
||||||
|
auto was = chatListUnreadState();
|
||||||
|
if (has) {
|
||||||
|
was.mentions = 0;
|
||||||
|
} else {
|
||||||
|
was.mentions = 1;
|
||||||
|
}
|
||||||
|
notifyUnreadStateChange(was);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForumTopic::hasUnreadReactionChanged(bool has) {
|
||||||
|
auto was = chatListUnreadState();
|
||||||
|
if (has) {
|
||||||
|
was.reactions = was.reactionsMuted = 0;
|
||||||
|
} else {
|
||||||
|
was.reactions = 1;
|
||||||
|
was.reactionsMuted = muted() ? was.reactions : 0;
|
||||||
|
}
|
||||||
|
notifyUnreadStateChange(was);
|
||||||
|
}
|
||||||
|
|
||||||
const QString &ForumTopic::chatListNameSortKey() const {
|
const QString &ForumTopic::chatListNameSortKey() const {
|
||||||
static const auto empty = QString();
|
static const auto empty = QString();
|
||||||
return empty;
|
return empty;
|
||||||
|
|
|
@ -81,10 +81,8 @@ public:
|
||||||
|
|
||||||
int fixedOnTopIndex() const override;
|
int fixedOnTopIndex() const override;
|
||||||
bool shouldBeInChatList() const override;
|
bool shouldBeInChatList() const override;
|
||||||
int chatListUnreadCount() const override;
|
|
||||||
bool chatListUnreadMark() const override;
|
|
||||||
bool chatListMutedBadge() const override;
|
|
||||||
Dialogs::UnreadState chatListUnreadState() const override;
|
Dialogs::UnreadState chatListUnreadState() const override;
|
||||||
|
Dialogs::BadgesState chatListBadgesState() const override;
|
||||||
HistoryItem *chatListMessage() const override;
|
HistoryItem *chatListMessage() const override;
|
||||||
bool chatListMessageKnown() const override;
|
bool chatListMessageKnown() const override;
|
||||||
void requestChatListMessage() override;
|
void requestChatListMessage() override;
|
||||||
|
@ -93,6 +91,9 @@ public:
|
||||||
const base::flat_set<QString> &chatListNameWords() const override;
|
const base::flat_set<QString> &chatListNameWords() const override;
|
||||||
const base::flat_set<QChar> &chatListFirstLetters() const override;
|
const base::flat_set<QChar> &chatListFirstLetters() const override;
|
||||||
|
|
||||||
|
void hasUnreadMentionChanged(bool has) override;
|
||||||
|
void hasUnreadReactionChanged(bool has) override;
|
||||||
|
|
||||||
[[nodiscard]] HistoryItem *lastMessage() const;
|
[[nodiscard]] HistoryItem *lastMessage() const;
|
||||||
[[nodiscard]] HistoryItem *lastServerMessage() const;
|
[[nodiscard]] HistoryItem *lastServerMessage() const;
|
||||||
[[nodiscard]] bool lastMessageKnown() const;
|
[[nodiscard]] bool lastMessageKnown() const;
|
||||||
|
@ -125,13 +126,7 @@ public:
|
||||||
[[nodiscard]] bool isServerSideUnread(
|
[[nodiscard]] bool isServerSideUnread(
|
||||||
not_null<const HistoryItem*> item) const override;
|
not_null<const HistoryItem*> item) const override;
|
||||||
|
|
||||||
[[nodiscard]] int unreadCount() const;
|
|
||||||
[[nodiscard]] bool unreadCountKnown() const;
|
|
||||||
|
|
||||||
[[nodiscard]] int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0.
|
|
||||||
|
|
||||||
void setMuted(bool muted) override;
|
void setMuted(bool muted) override;
|
||||||
void setUnreadMark(bool unread) override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto sendActionPainter()
|
[[nodiscard]] auto sendActionPainter()
|
||||||
->not_null<HistoryView::SendActionPainter*> override;
|
->not_null<HistoryView::SendActionPainter*> override;
|
||||||
|
|
|
@ -144,7 +144,7 @@ void Thread::setMuted(bool muted) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::setUnreadMark(bool unread) {
|
void Thread::setUnreadMarkFlag(bool unread) {
|
||||||
if (unread) {
|
if (unread) {
|
||||||
_flags |= Flag::UnreadMark;
|
_flags |= Flag::UnreadMark;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -71,6 +71,8 @@ public:
|
||||||
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadMentions() const;
|
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadMentions() const;
|
||||||
[[nodiscard]] HistoryUnreadThings::Proxy unreadReactions();
|
[[nodiscard]] HistoryUnreadThings::Proxy unreadReactions();
|
||||||
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadReactions() const;
|
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadReactions() const;
|
||||||
|
virtual void hasUnreadMentionChanged(bool has) = 0;
|
||||||
|
virtual void hasUnreadReactionChanged(bool has) = 0;
|
||||||
|
|
||||||
void removeNotification(not_null<HistoryItem*> item);
|
void removeNotification(not_null<HistoryItem*> item);
|
||||||
void clearNotifications();
|
void clearNotifications();
|
||||||
|
@ -90,7 +92,6 @@ public:
|
||||||
[[nodiscard]] bool unreadMark() const {
|
[[nodiscard]] bool unreadMark() const {
|
||||||
return (_flags & Flag::UnreadMark);
|
return (_flags & Flag::UnreadMark);
|
||||||
}
|
}
|
||||||
virtual void setUnreadMark(bool unread);
|
|
||||||
|
|
||||||
[[nodiscard]] virtual bool isServerSideUnread(
|
[[nodiscard]] virtual bool isServerSideUnread(
|
||||||
not_null<const HistoryItem*> item) const = 0;
|
not_null<const HistoryItem*> item) const = 0;
|
||||||
|
@ -108,6 +109,9 @@ public:
|
||||||
[[nodiscard]] virtual auto sendActionPainter()
|
[[nodiscard]] virtual auto sendActionPainter()
|
||||||
-> not_null<HistoryView::SendActionPainter*> = 0;
|
-> not_null<HistoryView::SendActionPainter*> = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setUnreadMarkFlag(bool unread);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Flag : uchar {
|
enum class Flag : uchar {
|
||||||
UnreadMark = (1 << 0),
|
UnreadMark = (1 << 0),
|
||||||
|
|
|
@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_forum_topic.h"
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_chat_filters.h"
|
#include "data/data_chat_filters.h"
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "core/core_settings.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_session_settings.h"
|
#include "main/main_session_settings.h"
|
||||||
|
@ -44,6 +46,37 @@ uint64 PinnedDialogPos(int pinnedIndex) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
BadgesState BadgesForUnread(
|
||||||
|
const UnreadState &state,
|
||||||
|
CountInBadge count,
|
||||||
|
IncludeInBadge include) {
|
||||||
|
const auto countMessages = (count == CountInBadge::Messages)
|
||||||
|
|| ((count == CountInBadge::Default)
|
||||||
|
&& Core::App().settings().countUnreadMessages());
|
||||||
|
const auto counterFull = state.marks
|
||||||
|
+ (countMessages ? state.messages : state.chats);
|
||||||
|
const auto counterMuted = state.marksMuted
|
||||||
|
+ (countMessages ? state.messagesMuted : state.chatsMuted);
|
||||||
|
const auto unreadMuted = (counterFull <= counterMuted);
|
||||||
|
|
||||||
|
const auto includeMuted = (include == IncludeInBadge::All)
|
||||||
|
|| (include == IncludeInBadge::UnmutedOrAll && unreadMuted)
|
||||||
|
|| ((include == IncludeInBadge::Default)
|
||||||
|
&& Core::App().settings().includeMutedCounter());
|
||||||
|
|
||||||
|
const auto marks = state.marks - (includeMuted ? 0 : state.marksMuted);
|
||||||
|
const auto counter = counterFull - (includeMuted ? 0 : counterMuted);
|
||||||
|
const auto mark = (counter == 1) && (marks == 1);
|
||||||
|
return {
|
||||||
|
.unreadCounter = mark ? 0 : counter,
|
||||||
|
.unread = (counter > 0),
|
||||||
|
.unreadMuted = includeMuted && (counter <= counterMuted),
|
||||||
|
.mention = (state.mentions > 0),
|
||||||
|
.reaction = (state.reactions > 0),
|
||||||
|
.reactionMuted = (state.reactions <= state.reactionsMuted),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Entry::Entry(not_null<Data::Session*> owner, Type type)
|
Entry::Entry(not_null<Data::Session*> owner, Type type)
|
||||||
: _owner(owner)
|
: _owner(owner)
|
||||||
, _flags((type == Type::History)
|
, _flags((type == Type::History)
|
||||||
|
@ -181,8 +214,24 @@ void Entry::notifyUnreadStateChange(const UnreadState &wasState) {
|
||||||
owner().chatsListFor(this)->unreadStateChanged(wasState, nowState);
|
owner().chatsListFor(this)->unreadStateChanged(wasState, nowState);
|
||||||
auto &filters = owner().chatsFilters();
|
auto &filters = owner().chatsFilters();
|
||||||
for (const auto &[filterId, links] : _chatListLinks) {
|
for (const auto &[filterId, links] : _chatListLinks) {
|
||||||
filters.chatsList(filterId)->unreadStateChanged(wasState, nowState);
|
if (filterId) {
|
||||||
|
filters.chatsList(filterId)->unreadStateChanged(
|
||||||
|
wasState,
|
||||||
|
nowState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (const auto history = asHistory()) {
|
||||||
|
session().changes().historyUpdated(
|
||||||
|
history,
|
||||||
|
Data::HistoryUpdate::Flag::UnreadView);
|
||||||
|
const auto isForFilters = [](UnreadState state) {
|
||||||
|
return state.messages || state.marks || state.mentions;
|
||||||
|
};
|
||||||
|
if (isForFilters(wasState) != isForFilters(nowState)) {
|
||||||
|
owner().chatsFilters().refreshHistory(history);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateChatListEntryPostponed();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Ui::Text::String &Entry::chatListNameText() const {
|
const Ui::Text::String &Entry::chatListNameText() const {
|
||||||
|
|
|
@ -64,6 +64,9 @@ struct UnreadState {
|
||||||
int chatsMuted = 0;
|
int chatsMuted = 0;
|
||||||
int marks = 0;
|
int marks = 0;
|
||||||
int marksMuted = 0;
|
int marksMuted = 0;
|
||||||
|
int reactions = 0;
|
||||||
|
int reactionsMuted = 0;
|
||||||
|
int mentions = 0;
|
||||||
bool known = false;
|
bool known = false;
|
||||||
|
|
||||||
UnreadState &operator+=(const UnreadState &other) {
|
UnreadState &operator+=(const UnreadState &other) {
|
||||||
|
@ -73,6 +76,9 @@ struct UnreadState {
|
||||||
chatsMuted += other.chatsMuted;
|
chatsMuted += other.chatsMuted;
|
||||||
marks += other.marks;
|
marks += other.marks;
|
||||||
marksMuted += other.marksMuted;
|
marksMuted += other.marksMuted;
|
||||||
|
reactions += other.reactions;
|
||||||
|
reactionsMuted += other.reactionsMuted;
|
||||||
|
mentions += other.mentions;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
UnreadState &operator-=(const UnreadState &other) {
|
UnreadState &operator-=(const UnreadState &other) {
|
||||||
|
@ -82,12 +88,11 @@ struct UnreadState {
|
||||||
chatsMuted -= other.chatsMuted;
|
chatsMuted -= other.chatsMuted;
|
||||||
marks -= other.marks;
|
marks -= other.marks;
|
||||||
marksMuted -= other.marksMuted;
|
marksMuted -= other.marksMuted;
|
||||||
|
reactions -= other.reactions;
|
||||||
|
reactionsMuted -= other.reactionsMuted;
|
||||||
|
mentions -= other.mentions;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
|
||||||
return !messages && !chats && !marks;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline UnreadState operator+(const UnreadState &a, const UnreadState &b) {
|
inline UnreadState operator+(const UnreadState &a, const UnreadState &b) {
|
||||||
|
@ -102,6 +107,42 @@ inline UnreadState operator-(const UnreadState &a, const UnreadState &b) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BadgesState {
|
||||||
|
int unreadCounter = 0;
|
||||||
|
bool unread : 1 = false;
|
||||||
|
bool unreadMuted : 1 = false;
|
||||||
|
bool mention : 1 = false;
|
||||||
|
bool mentionMuted : 1 = false;
|
||||||
|
bool reaction : 1 = false;
|
||||||
|
bool reactionMuted : 1 = false;
|
||||||
|
|
||||||
|
friend inline constexpr auto operator<=>(
|
||||||
|
BadgesState,
|
||||||
|
BadgesState) = default;
|
||||||
|
|
||||||
|
[[nodiscard]] bool empty() const {
|
||||||
|
return !unread && !mention && !reaction;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CountInBadge : uchar {
|
||||||
|
Default,
|
||||||
|
Chats,
|
||||||
|
Messages,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class IncludeInBadge : uchar {
|
||||||
|
Default,
|
||||||
|
Unmuted,
|
||||||
|
All,
|
||||||
|
UnmutedOrAll,
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] BadgesState BadgesForUnread(
|
||||||
|
const UnreadState &state,
|
||||||
|
CountInBadge count = CountInBadge::Default,
|
||||||
|
IncludeInBadge include = IncludeInBadge::Default);
|
||||||
|
|
||||||
class Entry : public base::has_weak_ptr {
|
class Entry : public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
enum class Type : uchar {
|
enum class Type : uchar {
|
||||||
|
@ -167,10 +208,8 @@ public:
|
||||||
static constexpr auto kTopPromotionFixOnTopIndex = 2;
|
static constexpr auto kTopPromotionFixOnTopIndex = 2;
|
||||||
|
|
||||||
virtual bool shouldBeInChatList() const = 0;
|
virtual bool shouldBeInChatList() const = 0;
|
||||||
virtual int chatListUnreadCount() const = 0;
|
|
||||||
virtual bool chatListUnreadMark() const = 0;
|
|
||||||
virtual bool chatListMutedBadge() const = 0;
|
|
||||||
virtual UnreadState chatListUnreadState() const = 0;
|
virtual UnreadState chatListUnreadState() const = 0;
|
||||||
|
virtual BadgesState chatListBadgesState() const = 0;
|
||||||
virtual HistoryItem *chatListMessage() const = 0;
|
virtual HistoryItem *chatListMessage() const = 0;
|
||||||
virtual bool chatListMessageKnown() const = 0;
|
virtual bool chatListMessageKnown() const = 0;
|
||||||
virtual void requestChatListMessage() = 0;
|
virtual void requestChatListMessage() = 0;
|
||||||
|
@ -197,21 +236,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const Ui::Text::String &chatListNameText() const;
|
[[nodiscard]] const Ui::Text::String &chatListNameText() const;
|
||||||
[[nodiscard]] Ui::PeerBadge &chatListBadge() const {
|
[[nodiscard]] Ui::PeerBadge &chatListPeerBadge() const {
|
||||||
return _chatListBadge;
|
return _chatListPeerBadge;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void notifyUnreadStateChange(const UnreadState &wasState);
|
void notifyUnreadStateChange(const UnreadState &wasState);
|
||||||
auto unreadStateChangeNotifier(bool required) {
|
auto unreadStateChangeNotifier(bool required);
|
||||||
const auto notify = required && inChatList();
|
|
||||||
const auto wasState = notify ? chatListUnreadState() : UnreadState();
|
|
||||||
return gsl::finally([=] {
|
|
||||||
if (notify) {
|
|
||||||
notifyUnreadStateChange(wasState);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] int lookupPinnedIndex(FilterId filterId) const;
|
[[nodiscard]] int lookupPinnedIndex(FilterId filterId) const;
|
||||||
|
|
||||||
|
@ -220,6 +251,7 @@ private:
|
||||||
IsThread = (1 << 0),
|
IsThread = (1 << 0),
|
||||||
IsHistory = (1 << 1),
|
IsHistory = (1 << 1),
|
||||||
UpdatePostponed = (1 << 2),
|
UpdatePostponed = (1 << 2),
|
||||||
|
InUnreadChangeBlock = (1 << 3),
|
||||||
};
|
};
|
||||||
friend inline constexpr bool is_flag_type(Flag) { return true; }
|
friend inline constexpr bool is_flag_type(Flag) { return true; }
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
|
@ -239,7 +271,7 @@ private:
|
||||||
uint64 _sortKeyInChatList = 0;
|
uint64 _sortKeyInChatList = 0;
|
||||||
uint64 _sortKeyByDate = 0;
|
uint64 _sortKeyByDate = 0;
|
||||||
base::flat_map<FilterId, int> _pinnedIndex;
|
base::flat_map<FilterId, int> _pinnedIndex;
|
||||||
mutable Ui::PeerBadge _chatListBadge;
|
mutable Ui::PeerBadge _chatListPeerBadge;
|
||||||
mutable Ui::Text::String _chatListNameText;
|
mutable Ui::Text::String _chatListNameText;
|
||||||
mutable int _chatListNameVersion = 0;
|
mutable int _chatListNameVersion = 0;
|
||||||
TimeId _timeId = 0;
|
TimeId _timeId = 0;
|
||||||
|
@ -247,4 +279,19 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto Entry::unreadStateChangeNotifier(bool required) {
|
||||||
|
Expects(!(_flags & Flag::InUnreadChangeBlock));
|
||||||
|
|
||||||
|
_flags |= Flag::InUnreadChangeBlock;
|
||||||
|
const auto notify = required && inChatList();
|
||||||
|
const auto wasState = notify ? chatListUnreadState() : UnreadState();
|
||||||
|
return gsl::finally([=] {
|
||||||
|
_flags &= ~Flag::InUnreadChangeBlock;
|
||||||
|
if (notify) {
|
||||||
|
Assert(inChatList());
|
||||||
|
notifyUnreadStateChange(wasState);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Dialogs
|
} // namespace Dialogs
|
||||||
|
|
|
@ -799,7 +799,7 @@ void InnerWidget::paintCollapsedRow(
|
||||||
Expects(row->folder != nullptr);
|
Expects(row->folder != nullptr);
|
||||||
|
|
||||||
const auto text = row->folder->chatListName();
|
const auto text = row->folder->chatListName();
|
||||||
const auto unread = row->folder->chatListUnreadCount();
|
const auto unread = row->folder->chatListBadgesState().unreadCounter;
|
||||||
Ui::PaintCollapsedRow(p, row->row, row->folder, text, unread, {
|
Ui::PaintCollapsedRow(p, row->row, row->folder, text, unread, {
|
||||||
.st = _st,
|
.st = _st,
|
||||||
.width = width(),
|
.width = width(),
|
||||||
|
@ -3435,8 +3435,7 @@ void InnerWidget::setupShortcuts() {
|
||||||
request->check(Command::ReadChat) && request->handle([=] {
|
request->check(Command::ReadChat) && request->handle([=] {
|
||||||
const auto history = _selected ? _selected->history() : nullptr;
|
const auto history = _selected ? _selected->history() : nullptr;
|
||||||
if (history) {
|
if (history) {
|
||||||
if ((history->chatListUnreadCount() > 0)
|
if (history->chatListBadgesState().unread) {
|
||||||
|| history->chatListUnreadMark()) {
|
|
||||||
session().data().histories().readInbox(history);
|
session().data().histories().readInbox(history);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -3470,8 +3469,7 @@ RowDescriptor InnerWidget::computeJump(
|
||||||
const auto needSkip = [&] {
|
const auto needSkip = [&] {
|
||||||
return (result.key.folder() != nullptr)
|
return (result.key.folder() != nullptr)
|
||||||
|| (session().supportMode()
|
|| (session().supportMode()
|
||||||
&& !result.key.entry()->chatListUnreadCount()
|
&& !result.key.entry()->chatListBadgesState().unread);
|
||||||
&& !result.key.entry()->chatListUnreadMark());
|
|
||||||
};
|
};
|
||||||
while (needSkip()) {
|
while (needSkip()) {
|
||||||
const auto next = down
|
const auto next = down
|
||||||
|
|
|
@ -8,7 +8,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "dialogs/dialogs_main_list.h"
|
#include "dialogs/dialogs_main_list.h"
|
||||||
|
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_chat_filters.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "history/history_unread_things.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
@ -126,7 +129,11 @@ void MainList::unreadStateChanged(
|
||||||
void MainList::unreadEntryChanged(
|
void MainList::unreadEntryChanged(
|
||||||
const Dialogs::UnreadState &state,
|
const Dialogs::UnreadState &state,
|
||||||
bool added) {
|
bool added) {
|
||||||
if (state.empty()) {
|
if (!state.messages
|
||||||
|
&& !state.chats
|
||||||
|
&& !state.marks
|
||||||
|
&& !state.mentions
|
||||||
|
&& !state.reactions) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto updateCloudUnread = _cloudUnreadState.known && state.known;
|
const auto updateCloudUnread = _cloudUnreadState.known && state.known;
|
||||||
|
|
|
@ -14,6 +14,10 @@ namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class Thread;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
|
||||||
class MainList final {
|
class MainList final {
|
||||||
|
@ -35,9 +39,7 @@ public:
|
||||||
void unreadStateChanged(
|
void unreadStateChanged(
|
||||||
const UnreadState &wasState,
|
const UnreadState &wasState,
|
||||||
const UnreadState &nowState);
|
const UnreadState &nowState);
|
||||||
void unreadEntryChanged(
|
void unreadEntryChanged(const UnreadState &state, bool added);
|
||||||
const Dialogs::UnreadState &state,
|
|
||||||
bool added);
|
|
||||||
void updateCloudUnread(const MTPDdialogFolder &data);
|
void updateCloudUnread(const MTPDdialogFolder &data);
|
||||||
[[nodiscard]] bool cloudUnreadKnown() const;
|
[[nodiscard]] bool cloudUnreadKnown() const;
|
||||||
[[nodiscard]] UnreadState unreadState() const;
|
[[nodiscard]] UnreadState unreadState() const;
|
||||||
|
|
|
@ -47,12 +47,12 @@ namespace {
|
||||||
const auto name = history->peer->name();
|
const auto name = history->peer->name();
|
||||||
return TextWithEntities{
|
return TextWithEntities{
|
||||||
.text = name,
|
.text = name,
|
||||||
.entities = (history->chatListUnreadCount() > 0)
|
.entities = (history->chatListBadgesState().unread
|
||||||
? EntitiesInText{
|
? EntitiesInText{
|
||||||
{ EntityType::Semibold, 0, int(name.size()), QString() },
|
{ EntityType::Semibold, 0, int(name.size()), QString() },
|
||||||
{ EntityType::PlainLink, 0, int(name.size()), QString() },
|
{ EntityType::PlainLink, 0, int(name.size()), QString() },
|
||||||
}
|
}
|
||||||
: EntitiesInText{}
|
: EntitiesInText{}),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const auto shown = int(peers.size());
|
const auto shown = int(peers.size());
|
||||||
|
|
|
@ -99,156 +99,49 @@ void PaintRowDate(
|
||||||
PaintRowTopRight(p, dt, rectForName, context);
|
PaintRowTopRight(p, dt, rectForName, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintNarrowCounter(
|
int PaintBadges(
|
||||||
QPainter &p,
|
QPainter &p,
|
||||||
const PaintContext &context,
|
const PaintContext &context,
|
||||||
bool displayUnreadCounter,
|
BadgesState badgesState,
|
||||||
bool displayUnreadMark,
|
int right,
|
||||||
bool displayMentionBadge,
|
int top,
|
||||||
bool displayReactionBadge,
|
bool displayPinnedIcon = false,
|
||||||
int unreadCount,
|
int pinnedIconTop = 0) {
|
||||||
bool unreadMuted,
|
auto initial = right;
|
||||||
bool mentionOrReactionMuted) {
|
if (badgesState.unread) {
|
||||||
auto skipBeforeMention = 0;
|
UnreadBadgeStyle st;
|
||||||
if (displayUnreadCounter || displayUnreadMark) {
|
st.active = context.active;
|
||||||
const auto counter = (unreadCount > 0)
|
st.selected = context.selected;
|
||||||
? QString::number(unreadCount)
|
st.muted = badgesState.unreadMuted;
|
||||||
|
const auto counter = (badgesState.unreadCounter > 0)
|
||||||
|
? QString::number(badgesState.unreadCounter)
|
||||||
: QString();
|
: QString();
|
||||||
const auto allowDigits = (displayMentionBadge
|
const auto badge = PaintUnreadBadge(p, counter, right, top, st);
|
||||||
|| displayReactionBadge)
|
right -= badge.width() + st.padding;
|
||||||
? 1
|
|
||||||
: 3;
|
|
||||||
const auto unreadRight = context.st->padding.left()
|
|
||||||
+ context.st->photoSize;
|
|
||||||
const auto unreadTop = context.st->padding.top()
|
|
||||||
+ context.st->photoSize
|
|
||||||
- st::dialogsUnreadHeight;
|
|
||||||
|
|
||||||
UnreadBadgeStyle st;
|
|
||||||
st.active = context.active;
|
|
||||||
st.selected = context.selected;
|
|
||||||
st.muted = unreadMuted;
|
|
||||||
const auto badge = PaintUnreadBadge(
|
|
||||||
p,
|
|
||||||
counter,
|
|
||||||
unreadRight,
|
|
||||||
unreadTop,
|
|
||||||
st,
|
|
||||||
allowDigits);
|
|
||||||
skipBeforeMention += badge.width() + st.padding;
|
|
||||||
}
|
|
||||||
if (displayMentionBadge || displayReactionBadge) {
|
|
||||||
const auto counter = QString();
|
|
||||||
const auto unreadRight = context.st->padding.left()
|
|
||||||
+ context.st->photoSize
|
|
||||||
- skipBeforeMention;
|
|
||||||
const auto unreadTop = context.st->padding.top()
|
|
||||||
+ context.st->photoSize
|
|
||||||
- st::dialogsUnreadHeight;
|
|
||||||
|
|
||||||
UnreadBadgeStyle st;
|
|
||||||
st.sizeId = displayMentionBadge
|
|
||||||
? UnreadBadgeSize::Dialogs
|
|
||||||
: UnreadBadgeSize::ReactionInDialogs;
|
|
||||||
st.active = context.active;
|
|
||||||
st.selected = context.selected;
|
|
||||||
st.muted = mentionOrReactionMuted;
|
|
||||||
st.padding = 0;
|
|
||||||
st.textTop = 0;
|
|
||||||
const auto badge = PaintUnreadBadge(
|
|
||||||
p,
|
|
||||||
counter,
|
|
||||||
unreadRight,
|
|
||||||
unreadTop,
|
|
||||||
st);
|
|
||||||
(displayMentionBadge
|
|
||||||
? (st.active
|
|
||||||
? st::dialogsUnreadMentionActive
|
|
||||||
: st.selected
|
|
||||||
? st::dialogsUnreadMentionOver
|
|
||||||
: st::dialogsUnreadMention)
|
|
||||||
: (st.active
|
|
||||||
? st::dialogsUnreadReactionActive
|
|
||||||
: st.selected
|
|
||||||
? st::dialogsUnreadReactionOver
|
|
||||||
: st::dialogsUnreadReaction)).paintInCenter(p, badge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int PaintWideCounter(
|
|
||||||
QPainter &p,
|
|
||||||
const PaintContext &context,
|
|
||||||
int texttop,
|
|
||||||
int availableWidth,
|
|
||||||
bool displayUnreadCounter,
|
|
||||||
bool displayUnreadMark,
|
|
||||||
bool displayMentionBadge,
|
|
||||||
bool displayReactionBadge,
|
|
||||||
bool displayPinnedIcon,
|
|
||||||
int unreadCount,
|
|
||||||
bool unreadMuted,
|
|
||||||
bool mentionOrReactionMuted) {
|
|
||||||
const auto initial = availableWidth;
|
|
||||||
if (displayUnreadCounter || displayUnreadMark) {
|
|
||||||
const auto counter = (unreadCount > 0)
|
|
||||||
? QString::number(unreadCount)
|
|
||||||
: QString();
|
|
||||||
const auto unreadRight = context.width - context.st->padding.right();
|
|
||||||
const auto unreadTop = texttop
|
|
||||||
+ st::dialogsTextFont->ascent
|
|
||||||
- st::dialogsUnreadFont->ascent
|
|
||||||
- (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
|
|
||||||
|
|
||||||
UnreadBadgeStyle st;
|
|
||||||
st.active = context.active;
|
|
||||||
st.selected = context.selected;
|
|
||||||
st.muted = unreadMuted;
|
|
||||||
const auto badge = PaintUnreadBadge(
|
|
||||||
p,
|
|
||||||
counter,
|
|
||||||
unreadRight,
|
|
||||||
unreadTop,
|
|
||||||
st);
|
|
||||||
availableWidth -= badge.width() + st.padding;
|
|
||||||
} else if (displayPinnedIcon) {
|
} else if (displayPinnedIcon) {
|
||||||
const auto &icon = context.active
|
const auto &icon = context.active
|
||||||
? st::dialogsPinnedIconActive
|
? st::dialogsPinnedIconActive
|
||||||
: context.selected
|
: context.selected
|
||||||
? st::dialogsPinnedIconOver
|
? st::dialogsPinnedIconOver
|
||||||
: st::dialogsPinnedIcon;
|
: st::dialogsPinnedIcon;
|
||||||
icon.paint(
|
icon.paint(p, right - icon.width(), pinnedIconTop, context.width);
|
||||||
p,
|
right -= icon.width() + st::dialogsUnreadPadding;
|
||||||
context.width - context.st->padding.right() - icon.width(),
|
|
||||||
texttop,
|
|
||||||
context.width);
|
|
||||||
availableWidth -= icon.width() + st::dialogsUnreadPadding;
|
|
||||||
}
|
}
|
||||||
if (displayMentionBadge || displayReactionBadge) {
|
if (badgesState.mention || badgesState.reaction) {
|
||||||
const auto counter = QString();
|
|
||||||
const auto unreadRight = context.width
|
|
||||||
- context.st->padding.right()
|
|
||||||
- (initial - availableWidth);
|
|
||||||
const auto unreadTop = texttop
|
|
||||||
+ st::dialogsTextFont->ascent
|
|
||||||
- st::dialogsUnreadFont->ascent
|
|
||||||
- (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
|
|
||||||
|
|
||||||
UnreadBadgeStyle st;
|
UnreadBadgeStyle st;
|
||||||
st.sizeId = displayMentionBadge
|
st.sizeId = badgesState.mention
|
||||||
? UnreadBadgeSize::Dialogs
|
? UnreadBadgeSize::Dialogs
|
||||||
: UnreadBadgeSize::ReactionInDialogs;
|
: UnreadBadgeSize::ReactionInDialogs;
|
||||||
st.active = context.active;
|
st.active = context.active;
|
||||||
st.selected = context.selected;
|
st.selected = context.selected;
|
||||||
st.muted = mentionOrReactionMuted;
|
st.muted = badgesState.mention
|
||||||
|
? badgesState.mentionMuted
|
||||||
|
: badgesState.reactionMuted;
|
||||||
st.padding = 0;
|
st.padding = 0;
|
||||||
st.textTop = 0;
|
st.textTop = 0;
|
||||||
const auto badge = PaintUnreadBadge(
|
const auto counter = QString();
|
||||||
p,
|
const auto badge = PaintUnreadBadge(p, counter, right, top, st);
|
||||||
counter,
|
(badgesState.mention
|
||||||
unreadRight,
|
|
||||||
unreadTop,
|
|
||||||
st);
|
|
||||||
(displayMentionBadge
|
|
||||||
? (st.active
|
? (st.active
|
||||||
? st::dialogsUnreadMentionActive
|
? st::dialogsUnreadMentionActive
|
||||||
: st.selected
|
: st.selected
|
||||||
|
@ -259,11 +152,46 @@ int PaintWideCounter(
|
||||||
: st.selected
|
: st.selected
|
||||||
? st::dialogsUnreadReactionOver
|
? st::dialogsUnreadReactionOver
|
||||||
: st::dialogsUnreadReaction)).paintInCenter(p, badge);
|
: st::dialogsUnreadReaction)).paintInCenter(p, badge);
|
||||||
availableWidth -= badge.width()
|
right -= badge.width() + st.padding + st::dialogsUnreadPadding;
|
||||||
+ st.padding
|
|
||||||
+ st::dialogsUnreadPadding;
|
|
||||||
}
|
}
|
||||||
return availableWidth;
|
return (initial - right);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaintNarrowCounter(
|
||||||
|
QPainter &p,
|
||||||
|
const PaintContext &context,
|
||||||
|
BadgesState badgesState) {
|
||||||
|
const auto top = context.st->padding.top()
|
||||||
|
+ context.st->photoSize
|
||||||
|
- st::dialogsUnreadHeight;
|
||||||
|
PaintBadges(
|
||||||
|
p,
|
||||||
|
context,
|
||||||
|
badgesState,
|
||||||
|
context.st->padding.left() + context.st->photoSize,
|
||||||
|
top);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PaintWideCounter(
|
||||||
|
QPainter &p,
|
||||||
|
const PaintContext &context,
|
||||||
|
BadgesState badgesState,
|
||||||
|
int texttop,
|
||||||
|
int availableWidth,
|
||||||
|
bool displayPinnedIcon) {
|
||||||
|
const auto top = texttop
|
||||||
|
+ st::dialogsTextFont->ascent
|
||||||
|
- st::dialogsUnreadFont->ascent
|
||||||
|
- (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
|
||||||
|
const auto used = PaintBadges(
|
||||||
|
p,
|
||||||
|
context,
|
||||||
|
badgesState,
|
||||||
|
context.width - context.st->padding.right(),
|
||||||
|
top,
|
||||||
|
displayPinnedIcon,
|
||||||
|
texttop);
|
||||||
|
return availableWidth - used;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintListEntryText(
|
void PaintListEntryText(
|
||||||
|
@ -309,7 +237,7 @@ enum class Flag {
|
||||||
};
|
};
|
||||||
inline constexpr bool is_flag_type(Flag) { return true; }
|
inline constexpr bool is_flag_type(Flag) { return true; }
|
||||||
|
|
||||||
template <typename PaintItemCallback, typename PaintCounterCallback>
|
template <typename PaintItemCallback>
|
||||||
void PaintRow(
|
void PaintRow(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<const BasicRow*> row,
|
not_null<const BasicRow*> row,
|
||||||
|
@ -325,9 +253,9 @@ void PaintRow(
|
||||||
const Data::Draft *draft,
|
const Data::Draft *draft,
|
||||||
QDateTime date,
|
QDateTime date,
|
||||||
const PaintContext &context,
|
const PaintContext &context,
|
||||||
|
BadgesState badgesState,
|
||||||
base::flags<Flag> flags,
|
base::flags<Flag> flags,
|
||||||
PaintItemCallback &&paintItemCallback,
|
PaintItemCallback &&paintItemCallback) {
|
||||||
PaintCounterCallback &&paintCounterCallback) {
|
|
||||||
const auto supportMode = entry->session().supportMode();
|
const auto supportMode = entry->session().supportMode();
|
||||||
if (supportMode) {
|
if (supportMode) {
|
||||||
draft = nullptr;
|
draft = nullptr;
|
||||||
|
@ -383,7 +311,7 @@ void PaintRow(
|
||||||
auto nameleft = context.st->nameLeft;
|
auto nameleft = context.st->nameLeft;
|
||||||
if (context.width <= nameleft) {
|
if (context.width <= nameleft) {
|
||||||
if (!draft && item && !item->isEmpty()) {
|
if (!draft && item && !item->isEmpty()) {
|
||||||
paintCounterCallback();
|
PaintNarrowCounter(p, context, badgesState);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -891,12 +819,10 @@ void RowPainter::Paint(
|
||||||
const auto history = row->history();
|
const auto history = row->history();
|
||||||
const auto thread = row->thread();
|
const auto thread = row->thread();
|
||||||
const auto peer = history ? history->peer.get() : nullptr;
|
const auto peer = history ? history->peer.get() : nullptr;
|
||||||
const auto unreadCount = entry->chatListUnreadCount();
|
const auto badgesState = entry->chatListBadgesState();
|
||||||
const auto unreadMark = entry->chatListUnreadMark();
|
|
||||||
const auto unreadMuted = entry->chatListMutedBadge();
|
|
||||||
const auto item = entry->chatListMessage();
|
const auto item = entry->chatListMessage();
|
||||||
const auto cloudDraft = [&]() -> const Data::Draft*{
|
const auto cloudDraft = [&]() -> const Data::Draft*{
|
||||||
if (thread && (!item || (!unreadCount && !unreadMark))) {
|
if (thread && (!item || !badgesState.unread)) {
|
||||||
// Draw item, if there are unread messages.
|
// Draw item, if there are unread messages.
|
||||||
const auto draft = thread->owningHistory()->cloudDraft(
|
const auto draft = thread->owningHistory()->cloudDraft(
|
||||||
thread->topicRootId());
|
thread->topicRootId());
|
||||||
|
@ -919,30 +845,7 @@ void RowPainter::Paint(
|
||||||
? base::unixtime::parse(cloudDraft->date)
|
? base::unixtime::parse(cloudDraft->date)
|
||||||
: QDateTime();
|
: QDateTime();
|
||||||
}();
|
}();
|
||||||
const auto displayMentionBadge = thread
|
const auto displayPinnedIcon = badgesState.empty()
|
||||||
&& thread->unreadMentions().has();
|
|
||||||
const auto displayReactionBadge = !displayMentionBadge
|
|
||||||
&& thread
|
|
||||||
&& thread->unreadReactions().has();
|
|
||||||
const auto mentionOrReactionMuted = (entry->folder() != nullptr)
|
|
||||||
|| (!displayMentionBadge && unreadMuted);
|
|
||||||
const auto displayUnreadCounter = [&] {
|
|
||||||
if (displayMentionBadge
|
|
||||||
&& unreadCount == 1
|
|
||||||
&& item
|
|
||||||
&& item->isUnreadMention()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (unreadCount > 0);
|
|
||||||
}();
|
|
||||||
const auto displayUnreadMark = !displayUnreadCounter
|
|
||||||
&& !displayMentionBadge
|
|
||||||
&& history
|
|
||||||
&& unreadMark;
|
|
||||||
const auto displayPinnedIcon = !displayUnreadCounter
|
|
||||||
&& !displayMentionBadge
|
|
||||||
&& !displayReactionBadge
|
|
||||||
&& !displayUnreadMark
|
|
||||||
&& entry->isPinnedDialog(context.filter)
|
&& entry->isPinnedDialog(context.filter)
|
||||||
&& (context.filter || !entry->fixedOnTopIndex());
|
&& (context.filter || !entry->fixedOnTopIndex());
|
||||||
|
|
||||||
|
@ -951,8 +854,7 @@ void RowPainter::Paint(
|
||||||
? history->peer->migrateTo()
|
? history->peer->migrateTo()
|
||||||
: history->peer.get())
|
: history->peer.get())
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto allowUserOnline = !context.narrow
|
const auto allowUserOnline = !context.narrow || badgesState.empty();
|
||||||
|| (!displayUnreadCounter && !displayUnreadMark);
|
|
||||||
const auto flags = (allowUserOnline ? Flag::AllowUserOnline : Flag(0))
|
const auto flags = (allowUserOnline ? Flag::AllowUserOnline : Flag(0))
|
||||||
| (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0))
|
| (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0))
|
||||||
| (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0));
|
| (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0));
|
||||||
|
@ -961,16 +863,10 @@ void RowPainter::Paint(
|
||||||
const auto availableWidth = PaintWideCounter(
|
const auto availableWidth = PaintWideCounter(
|
||||||
p,
|
p,
|
||||||
context,
|
context,
|
||||||
|
badgesState,
|
||||||
texttop,
|
texttop,
|
||||||
namewidth,
|
namewidth,
|
||||||
displayUnreadCounter,
|
displayPinnedIcon);
|
||||||
displayUnreadMark,
|
|
||||||
displayMentionBadge,
|
|
||||||
displayReactionBadge,
|
|
||||||
displayPinnedIcon,
|
|
||||||
unreadCount,
|
|
||||||
unreadMuted,
|
|
||||||
mentionOrReactionMuted);
|
|
||||||
const auto &color = context.active
|
const auto &color = context.active
|
||||||
? st::dialogsTextFgServiceActive
|
? st::dialogsTextFgServiceActive
|
||||||
: context.selected
|
: context.selected
|
||||||
|
@ -1008,18 +904,6 @@ void RowPainter::Paint(
|
||||||
view->paint(p, rect, context);
|
view->paint(p, rect, context);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto paintCounterCallback = [&] {
|
|
||||||
PaintNarrowCounter(
|
|
||||||
p,
|
|
||||||
context,
|
|
||||||
displayUnreadCounter,
|
|
||||||
displayUnreadMark,
|
|
||||||
displayMentionBadge,
|
|
||||||
displayReactionBadge,
|
|
||||||
unreadCount,
|
|
||||||
unreadMuted,
|
|
||||||
mentionOrReactionMuted);
|
|
||||||
};
|
|
||||||
PaintRow(
|
PaintRow(
|
||||||
p,
|
p,
|
||||||
row,
|
row,
|
||||||
|
@ -1027,7 +911,7 @@ void RowPainter::Paint(
|
||||||
row->key(),
|
row->key(),
|
||||||
videoUserpic,
|
videoUserpic,
|
||||||
from,
|
from,
|
||||||
entry->chatListBadge(),
|
entry->chatListPeerBadge(),
|
||||||
[=] { history->updateChatListEntry(); },
|
[=] { history->updateChatListEntry(); },
|
||||||
entry->chatListNameText(),
|
entry->chatListNameText(),
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -1035,9 +919,9 @@ void RowPainter::Paint(
|
||||||
cloudDraft,
|
cloudDraft,
|
||||||
displayDate,
|
displayDate,
|
||||||
context,
|
context,
|
||||||
|
badgesState,
|
||||||
flags,
|
flags,
|
||||||
paintItemCallback,
|
paintItemCallback);
|
||||||
paintCounterCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RowPainter::Paint(
|
void RowPainter::Paint(
|
||||||
|
@ -1078,22 +962,9 @@ void RowPainter::Paint(
|
||||||
return {};
|
return {};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
const auto unreadCount = context.displayUnreadInfo
|
const auto badgesState = context.displayUnreadInfo
|
||||||
? history->chatListUnreadCount()
|
? history->chatListBadgesState()
|
||||||
: 0;
|
: BadgesState();
|
||||||
const auto unreadMark = context.displayUnreadInfo
|
|
||||||
&& history->chatListUnreadMark();
|
|
||||||
const auto unreadMuted = history->chatListMutedBadge();
|
|
||||||
const auto mentionOrReactionMuted = (history->folder() != nullptr);
|
|
||||||
const auto displayMentionBadge = context.displayUnreadInfo
|
|
||||||
&& history->unreadMentions().has();
|
|
||||||
const auto displayReactionBadge = context.displayUnreadInfo
|
|
||||||
&& !displayMentionBadge
|
|
||||||
&& history->unreadReactions().has();
|
|
||||||
const auto displayUnreadCounter = (unreadCount > 0);
|
|
||||||
const auto displayUnreadMark = !displayUnreadCounter
|
|
||||||
&& !displayMentionBadge
|
|
||||||
&& unreadMark;
|
|
||||||
const auto displayPinnedIcon = false;
|
const auto displayPinnedIcon = false;
|
||||||
|
|
||||||
const auto paintItemCallback = [&](int nameleft, int namewidth) {
|
const auto paintItemCallback = [&](int nameleft, int namewidth) {
|
||||||
|
@ -1101,16 +972,10 @@ void RowPainter::Paint(
|
||||||
const auto availableWidth = PaintWideCounter(
|
const auto availableWidth = PaintWideCounter(
|
||||||
p,
|
p,
|
||||||
context,
|
context,
|
||||||
|
badgesState,
|
||||||
texttop,
|
texttop,
|
||||||
namewidth,
|
namewidth,
|
||||||
displayUnreadCounter,
|
displayPinnedIcon);
|
||||||
displayUnreadMark,
|
|
||||||
displayMentionBadge,
|
|
||||||
displayReactionBadge,
|
|
||||||
displayPinnedIcon,
|
|
||||||
unreadCount,
|
|
||||||
unreadMuted,
|
|
||||||
mentionOrReactionMuted);
|
|
||||||
|
|
||||||
const auto itemRect = QRect(
|
const auto itemRect = QRect(
|
||||||
nameleft,
|
nameleft,
|
||||||
|
@ -1123,18 +988,6 @@ void RowPainter::Paint(
|
||||||
}
|
}
|
||||||
row->itemView().paint(p, itemRect, context);
|
row->itemView().paint(p, itemRect, context);
|
||||||
};
|
};
|
||||||
const auto paintCounterCallback = [&] {
|
|
||||||
PaintNarrowCounter(
|
|
||||||
p,
|
|
||||||
context,
|
|
||||||
displayUnreadCounter,
|
|
||||||
displayUnreadMark,
|
|
||||||
displayMentionBadge,
|
|
||||||
displayReactionBadge,
|
|
||||||
unreadCount,
|
|
||||||
unreadMuted,
|
|
||||||
mentionOrReactionMuted);
|
|
||||||
};
|
|
||||||
const auto showSavedMessages = history->peer->isSelf()
|
const auto showSavedMessages = history->peer->isSelf()
|
||||||
&& !row->searchInChat();
|
&& !row->searchInChat();
|
||||||
const auto showRepliesMessages = history->peer->isRepliesChat()
|
const auto showRepliesMessages = history->peer->isRepliesChat()
|
||||||
|
@ -1156,9 +1009,9 @@ void RowPainter::Paint(
|
||||||
cloudDraft,
|
cloudDraft,
|
||||||
ItemDateTime(item),
|
ItemDateTime(item),
|
||||||
context,
|
context,
|
||||||
|
badgesState,
|
||||||
flags,
|
flags,
|
||||||
paintItemCallback,
|
paintItemCallback);
|
||||||
paintCounterCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect RowPainter::SendActionAnimationRect(
|
QRect RowPainter::SendActionAnimationRect(
|
||||||
|
|
|
@ -1693,11 +1693,6 @@ int History::unreadCount() const {
|
||||||
return _unreadCount ? *_unreadCount : 0;
|
return _unreadCount ? *_unreadCount : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int History::unreadCountForBadge() const {
|
|
||||||
const auto result = unreadCount();
|
|
||||||
return (!result && unreadMark()) ? 1 : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool History::unreadCountKnown() const {
|
bool History::unreadCountKnown() const {
|
||||||
return _unreadCount.has_value();
|
return _unreadCount.has_value();
|
||||||
}
|
}
|
||||||
|
@ -1708,14 +1703,7 @@ void History::setUnreadCount(int newUnreadCount) {
|
||||||
if (_unreadCount == newUnreadCount) {
|
if (_unreadCount == newUnreadCount) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto wasForBadge = (unreadCountForBadge() > 0);
|
const auto notifier = unreadStateChangeNotifier(!peer->isForum());
|
||||||
const auto refresher = gsl::finally([&] {
|
|
||||||
if (wasForBadge != (unreadCountForBadge() > 0)) {
|
|
||||||
owner().chatsFilters().refreshHistory(this);
|
|
||||||
}
|
|
||||||
session().changes().historyUpdated(this, UpdateFlag::UnreadView);
|
|
||||||
});
|
|
||||||
const auto notifier = unreadStateChangeNotifier(true);
|
|
||||||
_unreadCount = newUnreadCount;
|
_unreadCount = newUnreadCount;
|
||||||
|
|
||||||
const auto lastOutgoing = [&] {
|
const auto lastOutgoing = [&] {
|
||||||
|
@ -1753,26 +1741,22 @@ void History::setUnreadMark(bool unread) {
|
||||||
if (unreadMark() == unread) {
|
if (unreadMark() == unread) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto noUnreadMessages = !unreadCount();
|
const auto notifier = unreadStateChangeNotifier(
|
||||||
const auto refresher = gsl::finally([&] {
|
!unreadCount() && !peer->isForum());
|
||||||
if (inChatList() && noUnreadMessages) {
|
Thread::setUnreadMarkFlag(unread);
|
||||||
owner().chatsFilters().refreshHistory(this);
|
|
||||||
updateChatListEntry();
|
|
||||||
}
|
|
||||||
session().changes().historyUpdated(this, UpdateFlag::UnreadView);
|
|
||||||
});
|
|
||||||
const auto notifier = unreadStateChangeNotifier(noUnreadMessages);
|
|
||||||
Thread::setUnreadMark(unread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::setFakeUnreadWhileOpened(bool enabled) {
|
void History::setFakeUnreadWhileOpened(bool enabled) {
|
||||||
if (_fakeUnreadWhileOpened == enabled
|
if (_fakeUnreadWhileOpened == enabled) {
|
||||||
|| (enabled
|
|
||||||
&& (!inChatList()
|
|
||||||
|| (!unreadCount()
|
|
||||||
&& !unreadMark()
|
|
||||||
&& !unreadMentions().has())))) {
|
|
||||||
return;
|
return;
|
||||||
|
} else if (enabled) {
|
||||||
|
if (!inChatList()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto state = chatListBadgesState();
|
||||||
|
if (!state.unread && !state.mention) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_fakeUnreadWhileOpened = enabled;
|
_fakeUnreadWhileOpened = enabled;
|
||||||
owner().chatsFilters().refreshHistory(this);
|
owner().chatsFilters().refreshHistory(this);
|
||||||
|
@ -1785,19 +1769,18 @@ void History::setFakeUnreadWhileOpened(bool enabled) {
|
||||||
void History::setMuted(bool muted) {
|
void History::setMuted(bool muted) {
|
||||||
if (this->muted() == muted) {
|
if (this->muted() == muted) {
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
const auto state = peer->isForum()
|
||||||
|
? Dialogs::BadgesState()
|
||||||
|
: computeBadgesState();
|
||||||
|
const auto notify = (state.unread || state.reaction);
|
||||||
|
const auto notifier = unreadStateChangeNotifier(notify);
|
||||||
|
Thread::setMuted(muted);
|
||||||
}
|
}
|
||||||
const auto refresher = gsl::finally([&] {
|
session().changes().peerUpdated(
|
||||||
if (inChatList()) {
|
peer,
|
||||||
owner().chatsFilters().refreshHistory(this);
|
Data::PeerUpdate::Flag::Notifications);
|
||||||
updateChatListEntry();
|
owner().chatsFilters().refreshHistory(this);
|
||||||
}
|
|
||||||
session().changes().peerUpdated(
|
|
||||||
peer,
|
|
||||||
Data::PeerUpdate::Flag::Notifications);
|
|
||||||
});
|
|
||||||
const auto notify = (unreadCountForBadge() > 0);
|
|
||||||
const auto notifier = unreadStateChangeNotifier(notify);
|
|
||||||
Thread::setMuted(muted);
|
|
||||||
if (const auto forum = peer->forum()) {
|
if (const auto forum = peer->forum()) {
|
||||||
owner().notifySettings().forumParentMuteUpdated(forum);
|
owner().notifySettings().forumParentMuteUpdated(forum);
|
||||||
}
|
}
|
||||||
|
@ -1899,6 +1882,33 @@ int History::chatListNameVersion() const {
|
||||||
return peer->nameVersion();
|
return peer->nameVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void History::hasUnreadMentionChanged(bool has) {
|
||||||
|
if (peer->isForum()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto was = chatListUnreadState();
|
||||||
|
if (has) {
|
||||||
|
was.mentions = 0;
|
||||||
|
} else {
|
||||||
|
was.mentions = 1;
|
||||||
|
}
|
||||||
|
notifyUnreadStateChange(was);
|
||||||
|
}
|
||||||
|
|
||||||
|
void History::hasUnreadReactionChanged(bool has) {
|
||||||
|
if (peer->isForum()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto was = chatListUnreadState();
|
||||||
|
if (has) {
|
||||||
|
was.reactions = was.reactionsMuted = 0;
|
||||||
|
} else {
|
||||||
|
was.reactions = 1;
|
||||||
|
was.reactionsMuted = muted() ? was.reactions : 0;
|
||||||
|
}
|
||||||
|
notifyUnreadStateChange(was);
|
||||||
|
}
|
||||||
|
|
||||||
void History::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
void History::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
||||||
const auto folderId = data.vfolder_id().value_or_empty();
|
const auto folderId = data.vfolder_id().value_or_empty();
|
||||||
if (!folderKnown()) {
|
if (!folderKnown()) {
|
||||||
|
@ -1998,10 +2008,7 @@ void History::getNextScrollTopItem(HistoryBlock *block, int32 i) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::addUnreadBar() {
|
void History::addUnreadBar() {
|
||||||
if (_unreadBarView || !_firstUnreadView || !unreadCount()) {
|
if (!_unreadBarView && _firstUnreadView && unreadCount()) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (const auto count = chatListUnreadCount()) {
|
|
||||||
_unreadBarView = _firstUnreadView;
|
_unreadBarView = _firstUnreadView;
|
||||||
_unreadBarView->createUnreadBar(tr::lng_unread_bar_some());
|
_unreadBarView->createUnreadBar(tr::lng_unread_bar_some());
|
||||||
}
|
}
|
||||||
|
@ -2066,41 +2073,6 @@ History *History::migrateSibling() const {
|
||||||
return owner().historyLoaded(addFromId);
|
return owner().historyLoaded(addFromId);
|
||||||
}
|
}
|
||||||
|
|
||||||
int History::chatListUnreadCount() const {
|
|
||||||
if (peer->isForum()) {
|
|
||||||
const auto state = chatListUnreadState();
|
|
||||||
return state.marks
|
|
||||||
+ (Core::App().settings().countUnreadMessages()
|
|
||||||
? state.messages
|
|
||||||
: state.chats);
|
|
||||||
}
|
|
||||||
const auto result = unreadCount();
|
|
||||||
if (const auto migrated = migrateSibling()) {
|
|
||||||
return result + migrated->unreadCount();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool History::chatListUnreadMark() const {
|
|
||||||
if (unreadMark()) {
|
|
||||||
return true;
|
|
||||||
} else if (const auto migrated = migrateSibling()) {
|
|
||||||
return migrated->unreadMark();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool History::chatListMutedBadge() const {
|
|
||||||
if (const auto forum = peer->forum()) {
|
|
||||||
const auto state = forum->topicsList()->unreadState();
|
|
||||||
return (state.marksMuted >= state.marks)
|
|
||||||
&& (Core::App().settings().countUnreadMessages()
|
|
||||||
? (state.messagesMuted >= state.messages)
|
|
||||||
: (state.chatsMuted >= state.chats));
|
|
||||||
}
|
|
||||||
return muted();
|
|
||||||
}
|
|
||||||
|
|
||||||
Dialogs::UnreadState History::chatListUnreadState() const {
|
Dialogs::UnreadState History::chatListUnreadState() const {
|
||||||
if (const auto forum = peer->forum()) {
|
if (const auto forum = peer->forum()) {
|
||||||
return forum->topicsList()->unreadState();
|
return forum->topicsList()->unreadState();
|
||||||
|
@ -2108,17 +2080,47 @@ Dialogs::UnreadState History::chatListUnreadState() const {
|
||||||
return computeUnreadState();
|
return computeUnreadState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dialogs::BadgesState History::chatListBadgesState() const {
|
||||||
|
if (const auto forum = peer->forum()) {
|
||||||
|
return adjustBadgesStateByFolder(
|
||||||
|
Dialogs::BadgesForUnread(
|
||||||
|
forum->topicsList()->unreadState(),
|
||||||
|
Dialogs::CountInBadge::Chats,
|
||||||
|
Dialogs::IncludeInBadge::UnmutedOrAll));
|
||||||
|
}
|
||||||
|
return computeBadgesState();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialogs::BadgesState History::computeBadgesState() const {
|
||||||
|
return adjustBadgesStateByFolder(
|
||||||
|
Dialogs::BadgesForUnread(
|
||||||
|
computeUnreadState(),
|
||||||
|
Dialogs::CountInBadge::Messages,
|
||||||
|
Dialogs::IncludeInBadge::All));
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialogs::BadgesState History::adjustBadgesStateByFolder(
|
||||||
|
Dialogs::BadgesState state) const {
|
||||||
|
if (folder()) {
|
||||||
|
state.mentionMuted = state.reactionMuted = state.unreadMuted = true;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
Dialogs::UnreadState History::computeUnreadState() const {
|
Dialogs::UnreadState History::computeUnreadState() const {
|
||||||
auto result = Dialogs::UnreadState();
|
auto result = Dialogs::UnreadState();
|
||||||
const auto count = _unreadCount.value_or(0);
|
const auto count = _unreadCount.value_or(0);
|
||||||
const auto mark = !count && unreadMark();
|
const auto mark = !count && unreadMark();
|
||||||
const auto muted = this->muted();
|
const auto muted = this->muted();
|
||||||
result.messages = count;
|
result.messages = count;
|
||||||
result.messagesMuted = muted ? count : 0;
|
|
||||||
result.chats = count ? 1 : 0;
|
result.chats = count ? 1 : 0;
|
||||||
result.chatsMuted = (count && muted) ? 1 : 0;
|
|
||||||
result.marks = mark ? 1 : 0;
|
result.marks = mark ? 1 : 0;
|
||||||
result.marksMuted = (mark && muted) ? 1 : 0;
|
result.mentions = unreadMentions().has() ? 1 : 0;
|
||||||
|
result.reactions = unreadReactions().has() ? 1 : 0;
|
||||||
|
result.messagesMuted = muted ? result.messages : 0;
|
||||||
|
result.chatsMuted = muted ? result.chats : 0;
|
||||||
|
result.marksMuted = muted ? result.marks : 0;
|
||||||
|
result.reactionsMuted = muted ? result.reactions : 0;
|
||||||
result.known = _unreadCount.has_value();
|
result.known = _unreadCount.has_value();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2908,7 +2910,6 @@ void History::forumChanged(Data::Forum *old) {
|
||||||
return (_flags & Flag::IsForum) && inChatList();
|
return (_flags & Flag::IsForum) && inChatList();
|
||||||
}) | rpl::start_with_next([=](const Dialogs::UnreadState &old) {
|
}) | rpl::start_with_next([=](const Dialogs::UnreadState &old) {
|
||||||
notifyUnreadStateChange(old);
|
notifyUnreadStateChange(old);
|
||||||
updateChatListEntryPostponed();
|
|
||||||
}, forum->lifetime());
|
}, forum->lifetime());
|
||||||
} else {
|
} else {
|
||||||
_flags &= ~Flag::IsForum;
|
_flags &= ~Flag::IsForum;
|
||||||
|
|
|
@ -248,10 +248,9 @@ public:
|
||||||
[[nodiscard]] bool unreadCountRefreshNeeded(MsgId readTillId) const;
|
[[nodiscard]] bool unreadCountRefreshNeeded(MsgId readTillId) const;
|
||||||
|
|
||||||
void setUnreadCount(int newUnreadCount);
|
void setUnreadCount(int newUnreadCount);
|
||||||
void setUnreadMark(bool unread) override;
|
void setUnreadMark(bool unread);
|
||||||
void setFakeUnreadWhileOpened(bool enabled);
|
void setFakeUnreadWhileOpened(bool enabled);
|
||||||
[[nodiscard]] bool fakeUnreadWhileOpened() const;
|
[[nodiscard]] bool fakeUnreadWhileOpened() const;
|
||||||
[[nodiscard]] int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0.
|
|
||||||
void setMuted(bool muted) override;
|
void setMuted(bool muted) override;
|
||||||
void addUnreadBar();
|
void addUnreadBar();
|
||||||
void destroyUnreadBar();
|
void destroyUnreadBar();
|
||||||
|
@ -380,10 +379,8 @@ public:
|
||||||
int fixedOnTopIndex() const override;
|
int fixedOnTopIndex() const override;
|
||||||
void updateChatListExistence() override;
|
void updateChatListExistence() override;
|
||||||
bool shouldBeInChatList() const override;
|
bool shouldBeInChatList() const override;
|
||||||
int chatListUnreadCount() const override;
|
|
||||||
bool chatListUnreadMark() const override;
|
|
||||||
bool chatListMutedBadge() const override;
|
|
||||||
Dialogs::UnreadState chatListUnreadState() const override;
|
Dialogs::UnreadState chatListUnreadState() const override;
|
||||||
|
Dialogs::BadgesState chatListBadgesState() const override;
|
||||||
HistoryItem *chatListMessage() const override;
|
HistoryItem *chatListMessage() const override;
|
||||||
bool chatListMessageKnown() const override;
|
bool chatListMessageKnown() const override;
|
||||||
void requestChatListMessage() override;
|
void requestChatListMessage() override;
|
||||||
|
@ -574,11 +571,17 @@ private:
|
||||||
HistoryService *insertJoinedMessage();
|
HistoryService *insertJoinedMessage();
|
||||||
void insertMessageToBlocks(not_null<HistoryItem*> item);
|
void insertMessageToBlocks(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
|
[[nodiscard]] Dialogs::BadgesState computeBadgesState() const;
|
||||||
|
[[nodiscard]] Dialogs::BadgesState adjustBadgesStateByFolder(
|
||||||
|
Dialogs::BadgesState state) const;
|
||||||
[[nodiscard]] Dialogs::UnreadState computeUnreadState() const;
|
[[nodiscard]] Dialogs::UnreadState computeUnreadState() const;
|
||||||
void setFolderPointer(Data::Folder *folder);
|
void setFolderPointer(Data::Folder *folder);
|
||||||
|
|
||||||
int chatListNameVersion() const override;
|
int chatListNameVersion() const override;
|
||||||
|
|
||||||
|
void hasUnreadMentionChanged(bool has) override;
|
||||||
|
void hasUnreadReactionChanged(bool has) override;
|
||||||
|
|
||||||
const std::unique_ptr<HistoryMainElementDelegateMixin> _delegateMixin;
|
const std::unique_ptr<HistoryMainElementDelegateMixin> _delegateMixin;
|
||||||
|
|
||||||
Flags _flags = 0;
|
Flags _flags = 0;
|
||||||
|
|
|
@ -67,13 +67,12 @@ void Proxy::setCount(int count) {
|
||||||
list.setCount(count);
|
list.setCount(count);
|
||||||
}
|
}
|
||||||
const auto has = (count > 0);
|
const auto has = (count > 0);
|
||||||
if (has != had) {
|
if (has != had && _thread->inChatList()) {
|
||||||
if (_type == Type::Mentions) {
|
if (_type == Type::Mentions) {
|
||||||
if (const auto history = _thread->asHistory()) {
|
_thread->hasUnreadMentionChanged(has);
|
||||||
_thread->owner().chatsFilters().refreshHistory(history);
|
} else if (_type == Type::Reactions) {
|
||||||
}
|
_thread->hasUnreadReactionChanged(has);
|
||||||
}
|
}
|
||||||
_thread->updateChatListEntry();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2257,21 +2257,17 @@ void HistoryWidget::showHistory(
|
||||||
if (!_history->folderKnown()) {
|
if (!_history->folderKnown()) {
|
||||||
session().data().histories().requestDialogEntry(_history);
|
session().data().histories().requestDialogEntry(_history);
|
||||||
}
|
}
|
||||||
if (_history->chatListUnreadMark()) {
|
|
||||||
_history->owner().histories().changeDialogUnreadMark(
|
// Must be done before unreadCountUpdated(), or we auto-close.
|
||||||
|
if (_history->unreadMark()) {
|
||||||
|
session().data().histories().changeDialogUnreadMark(
|
||||||
_history,
|
_history,
|
||||||
false);
|
false);
|
||||||
if (_migrated) {
|
}
|
||||||
_migrated->owner().histories().changeDialogUnreadMark(
|
if (_migrated && _migrated->unreadMark()) {
|
||||||
_migrated,
|
session().data().histories().changeDialogUnreadMark(
|
||||||
false);
|
_migrated,
|
||||||
}
|
false);
|
||||||
|
|
||||||
// Must be done before unreadCountUpdated(), or we auto-close.
|
|
||||||
_history->setUnreadMark(false);
|
|
||||||
if (_migrated) {
|
|
||||||
_migrated->setUnreadMark(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
unreadCountUpdated(); // set _historyDown badge.
|
unreadCountUpdated(); // set _historyDown badge.
|
||||||
showAboutTopPromotion();
|
showAboutTopPromotion();
|
||||||
|
@ -2913,7 +2909,7 @@ void HistoryWidget::maybeMarkReactionsRead(not_null<HistoryItem*> item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::unreadCountUpdated() {
|
void HistoryWidget::unreadCountUpdated() {
|
||||||
if (_history->chatListUnreadMark()) {
|
if (_history->unreadMark() || (_migrated && _migrated->unreadMark())) {
|
||||||
crl::on_main(this, [=, history = _history] {
|
crl::on_main(this, [=, history = _history] {
|
||||||
if (history == _history) {
|
if (history == _history) {
|
||||||
closeCurrent();
|
closeCurrent();
|
||||||
|
@ -2922,7 +2918,7 @@ void HistoryWidget::unreadCountUpdated() {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_cornerButtons.updateJumpDownVisibility(
|
_cornerButtons.updateJumpDownVisibility(
|
||||||
_history->chatListUnreadCount());
|
_history->chatListBadgesState().unreadCounter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,16 +91,16 @@ QImage ArchiveUserpic(not_null<Data::Folder*> folder) {
|
||||||
|
|
||||||
QImage UnreadBadge(not_null<PeerData*> peer) {
|
QImage UnreadBadge(not_null<PeerData*> peer) {
|
||||||
const auto history = peer->owner().history(peer->id);
|
const auto history = peer->owner().history(peer->id);
|
||||||
const auto count = history->unreadCountForBadge();
|
const auto state = history->chatListBadgesState();
|
||||||
if (!count) {
|
if (!state.unread) {
|
||||||
return QImage();
|
return QImage();
|
||||||
}
|
}
|
||||||
const auto unread = history->unreadMark()
|
const auto counter = (state.unreadCounter > 0)
|
||||||
? QString()
|
? QString::number(state.unreadCounter)
|
||||||
: QString::number(count);
|
: QString();
|
||||||
Dialogs::Ui::UnreadBadgeStyle unreadSt;
|
Dialogs::Ui::UnreadBadgeStyle unreadSt;
|
||||||
unreadSt.sizeId = Dialogs::Ui::UnreadBadgeSize::TouchBar;
|
unreadSt.sizeId = Dialogs::Ui::UnreadBadgeSize::TouchBar;
|
||||||
unreadSt.muted = history->muted();
|
unreadSt.muted = state.unreadMuted;
|
||||||
// Use constant values to draw badge regardless of cConfigScale().
|
// Use constant values to draw badge regardless of cConfigScale().
|
||||||
unreadSt.size = kUnreadBadgeSize * cRetinaFactor();
|
unreadSt.size = kUnreadBadgeSize * cRetinaFactor();
|
||||||
unreadSt.padding = 4 * cRetinaFactor();
|
unreadSt.padding = 4 * cRetinaFactor();
|
||||||
|
|
|
@ -579,10 +579,10 @@ void MainMenu::setupArchive() {
|
||||||
return folder->owner().chatsList(folder)->unreadStateChanges();
|
return folder->owner().chatsList(folder)->unreadStateChanges();
|
||||||
}) | rpl::flatten_latest() | rpl::to_empty) | rpl::map([=] {
|
}) | rpl::flatten_latest() | rpl::to_empty) | rpl::map([=] {
|
||||||
const auto loaded = folder();
|
const auto loaded = folder();
|
||||||
return Badge::UnreadBadge{
|
const auto state = loaded
|
||||||
loaded ? loaded->chatListUnreadCount() : 0,
|
? loaded->chatListBadgesState()
|
||||||
true,
|
: Dialogs::BadgesState();
|
||||||
};
|
return Badge::UnreadBadge{ state.unreadCounter, true };
|
||||||
}));
|
}));
|
||||||
|
|
||||||
controller->session().data().chatsListChanges(
|
controller->session().data().chatsListChanges(
|
||||||
|
|
|
@ -112,8 +112,7 @@ void SetActionText(not_null<QAction*> action, rpl::producer<QString> &&text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool IsUnreadThread(not_null<Data::Thread*> thread) {
|
[[nodiscard]] bool IsUnreadThread(not_null<Data::Thread*> thread) {
|
||||||
return (thread->chatListUnreadCount() > 0)
|
return thread->chatListBadgesState().unread;
|
||||||
|| (thread->chatListUnreadMark());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkAsReadThread(not_null<Data::Thread*> thread) {
|
void MarkAsReadThread(not_null<Data::Thread*> thread) {
|
||||||
|
@ -1739,7 +1738,7 @@ void MenuAddMarkAsReadChatListAction(
|
||||||
const PeerMenuCallback &addAction) {
|
const PeerMenuCallback &addAction) {
|
||||||
// There is no async to make weak from controller.
|
// There is no async to make weak from controller.
|
||||||
const auto unreadState = list()->unreadState();
|
const auto unreadState = list()->unreadState();
|
||||||
if (unreadState.empty()) {
|
if (!unreadState.messages && !unreadState.marks && !unreadState.chats) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue