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