From b01e0b77fe31bb71f22c262fe70a390b4f34e276 Mon Sep 17 00:00:00 2001
From: 23rd <23rd@vivaldi.net>
Date: Tue, 24 Mar 2026 12:37:53 +0300
Subject: [PATCH] Added support of unread poll votes to corner button from
history widget.
---
.../icons/history_unread_poll_vote.svg | 9 ++
Telegram/Resources/langs/lang.strings | 1 +
.../SourceFiles/api/api_unread_things.cpp | 56 +++++++++++++
Telegram/SourceFiles/api/api_unread_things.h | 4 +
Telegram/SourceFiles/api/api_updates.cpp | 24 +++++-
.../chat_helpers/chat_helpers.style | 4 +
Telegram/SourceFiles/data/data_changes.h | 9 +-
Telegram/SourceFiles/data/data_folder.cpp | 6 +-
Telegram/SourceFiles/data/data_forum.cpp | 6 ++
Telegram/SourceFiles/data/data_forum.h | 1 +
.../SourceFiles/data/data_forum_topic.cpp | 3 +
Telegram/SourceFiles/data/data_forum_topic.h | 1 +
.../SourceFiles/data/data_saved_sublist.cpp | 4 +
.../SourceFiles/data/data_saved_sublist.h | 1 +
Telegram/SourceFiles/data/data_session.cpp | 18 ++++
Telegram/SourceFiles/data/data_thread.cpp | 24 ++++++
Telegram/SourceFiles/data/data_thread.h | 4 +
Telegram/SourceFiles/data/data_types.h | 1 +
Telegram/SourceFiles/history/history.cpp | 82 ++++++++++++++++++-
Telegram/SourceFiles/history/history.h | 8 ++
Telegram/SourceFiles/history/history_item.cpp | 44 +++++++++-
Telegram/SourceFiles/history/history_item.h | 3 +
.../history/history_unread_things.cpp | 52 ++++++++++--
.../history/history_unread_things.h | 6 +-
.../SourceFiles/history/history_widget.cpp | 4 +-
.../view/history_view_chat_section.cpp | 14 +++-
.../view/history_view_corner_buttons.cpp | 62 +++++++++++++-
.../view/history_view_corner_buttons.h | 3 +
.../view/history_view_pinned_section.cpp | 3 +-
.../info/polls/info_polls_list_widget.cpp | 3 +-
Telegram/SourceFiles/menu/menu_send.cpp | 42 ++++++++++
Telegram/SourceFiles/menu/menu_send.h | 4 +
32 files changed, 481 insertions(+), 25 deletions(-)
create mode 100644 Telegram/Resources/icons/history_unread_poll_vote.svg
diff --git a/Telegram/Resources/icons/history_unread_poll_vote.svg b/Telegram/Resources/icons/history_unread_poll_vote.svg
new file mode 100644
index 0000000000..ccc1f67190
--- /dev/null
+++ b/Telegram/Resources/icons/history_unread_poll_vote.svg
@@ -0,0 +1,9 @@
+
+
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 40f02919c4..533fa110e0 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -4920,6 +4920,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_mark_read_all_sure_2" = "**This action cannot be undone.**";
"lng_context_mark_read_mentions_all" = "Mark all mentions as read";
"lng_context_mark_read_reactions_all" = "Read all reactions";
+"lng_context_mark_read_poll_votes_all" = "Read all poll votes";
"lng_context_archive_expand" = "Expand";
"lng_context_archive_collapse" = "Collapse";
"lng_context_archive_to_menu" = "Move to main menu";
diff --git a/Telegram/SourceFiles/api/api_unread_things.cpp b/Telegram/SourceFiles/api/api_unread_things.cpp
index f7a43d6414..e871b71faa 100644
--- a/Telegram/SourceFiles/api/api_unread_things.cpp
+++ b/Telegram/SourceFiles/api/api_unread_things.cpp
@@ -42,6 +42,13 @@ bool UnreadThings::trackReactions(Data::Thread *thread) const {
return peer && (peer->isUser() || peer->isChat() || peer->isMegagroup());
}
+bool UnreadThings::trackPollVotes(Data::Thread *thread) const {
+ const auto peer = thread ? thread->peer().get() : nullptr;
+ return peer
+ && (peer->isChat() || peer->isMegagroup())
+ && !peer->isMonoforum();
+}
+
void UnreadThings::preloadEnough(Data::Thread *thread) {
if (trackMentions(thread)) {
preloadEnoughMentions(thread);
@@ -49,6 +56,9 @@ void UnreadThings::preloadEnough(Data::Thread *thread) {
if (trackReactions(thread)) {
preloadEnoughReactions(thread);
}
+ if (trackPollVotes(thread)) {
+ preloadEnoughPollVotes(thread);
+ }
}
void UnreadThings::mediaAndMentionsRead(
@@ -84,6 +94,15 @@ void UnreadThings::preloadEnoughReactions(not_null thread) {
}
}
+void UnreadThings::preloadEnoughPollVotes(not_null thread) {
+ const auto fullCount = thread->unreadPollVotes().count();
+ const auto loadedCount = thread->unreadPollVotes().loadedCount();
+ const auto allLoaded = (fullCount >= 0) && (loadedCount >= fullCount);
+ if (fullCount >= 0 && loadedCount < kPreloadIfLess && !allLoaded) {
+ requestPollVotes(thread, loadedCount);
+ }
+}
+
void UnreadThings::cancelRequests(not_null thread) {
if (const auto requestId = _mentionsRequests.take(thread)) {
_api->request(*requestId).cancel();
@@ -91,6 +110,9 @@ void UnreadThings::cancelRequests(not_null thread) {
if (const auto requestId = _reactionsRequests.take(thread)) {
_api->request(*requestId).cancel();
}
+ if (const auto requestId = _pollVotesRequests.take(thread)) {
+ _api->request(*requestId).cancel();
+ }
}
void UnreadThings::requestMentions(
@@ -164,4 +186,38 @@ void UnreadThings::requestReactions(
_reactionsRequests.emplace(thread, requestId);
}
+void UnreadThings::requestPollVotes(
+ not_null thread,
+ int loaded) {
+ if (_pollVotesRequests.contains(thread) || thread->asSublist()) {
+ return;
+ }
+ const auto offsetId = loaded
+ ? std::max(thread->unreadPollVotes().maxLoaded(), MsgId(1))
+ : MsgId(1);
+ const auto limit = loaded ? kNextRequestLimit : kFirstRequestLimit;
+ const auto addOffset = loaded ? -(limit + 1) : -limit;
+ const auto maxId = 0;
+ const auto minId = 0;
+ const auto history = thread->owningHistory();
+ const auto topic = thread->asTopic();
+ using Flag = MTPmessages_GetUnreadPollVotes::Flag;
+ const auto requestId = _api->request(MTPmessages_GetUnreadPollVotes(
+ MTP_flags(topic ? Flag::f_top_msg_id : Flag()),
+ history->peer->input(),
+ MTP_int(topic ? topic->rootId() : 0),
+ MTP_int(offsetId),
+ MTP_int(addOffset),
+ MTP_int(limit),
+ MTP_int(maxId),
+ MTP_int(minId)
+ )).done([=](const MTPmessages_Messages &result) {
+ _pollVotesRequests.remove(thread);
+ thread->unreadPollVotes().addSlice(result, loaded);
+ }).fail([=] {
+ _pollVotesRequests.remove(thread);
+ }).send();
+ _pollVotesRequests.emplace(thread, requestId);
+}
+
} // namespace UnreadThings
diff --git a/Telegram/SourceFiles/api/api_unread_things.h b/Telegram/SourceFiles/api/api_unread_things.h
index f3c7e1711e..dfc07459a5 100644
--- a/Telegram/SourceFiles/api/api_unread_things.h
+++ b/Telegram/SourceFiles/api/api_unread_things.h
@@ -23,6 +23,7 @@ public:
[[nodiscard]] bool trackMentions(Data::Thread *thread) const;
[[nodiscard]] bool trackReactions(Data::Thread *thread) const;
+ [[nodiscard]] bool trackPollVotes(Data::Thread *thread) const;
void preloadEnough(Data::Thread *thread);
@@ -35,14 +36,17 @@ public:
private:
void preloadEnoughMentions(not_null thread);
void preloadEnoughReactions(not_null thread);
+ void preloadEnoughPollVotes(not_null thread);
void requestMentions(not_null thread, int loaded);
void requestReactions(not_null thread, int loaded);
+ void requestPollVotes(not_null thread, int loaded);
const not_null _api;
base::flat_map, mtpRequestId> _mentionsRequests;
base::flat_map, mtpRequestId> _reactionsRequests;
+ base::flat_map, mtpRequestId> _pollVotesRequests;
};
diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp
index bbb0ab721a..860940f3bd 100644
--- a/Telegram/SourceFiles/api/api_updates.cpp
+++ b/Telegram/SourceFiles/api/api_updates.cpp
@@ -1848,7 +1848,29 @@ void Updates::feedUpdate(const MTPUpdate &update) {
} break;
case mtpc_updateMessagePoll: {
- session().data().applyUpdate(update.c_updateMessagePoll());
+ const auto &d = update.c_updateMessagePoll();
+ session().data().applyUpdate(d);
+ if (const auto tlPeer = d.vpeer()) {
+ const auto peer = peerFromMTP(*tlPeer);
+ const auto msgId = d.vmsg_id()->v;
+ if (const auto history = session().data().historyLoaded(peer)) {
+ if (const auto item = session().data().message(
+ peer,
+ msgId)) {
+ if (!item->hasUnreadPollVote()) {
+ item->setHasUnreadPollVote();
+ item->addToUnreadThings(
+ HistoryUnreadThings::AddType::New);
+ }
+ } else {
+ if (history->unreadPollVotes().has()) {
+ history->unreadPollVotes().checkAdd(msgId);
+ }
+ history->owner().histories().requestDialogEntry(
+ history);
+ }
+ }
+ }
} break;
case mtpc_updateUserTyping: {
diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
index 7dc2408297..64f6597098 100644
--- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style
+++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
@@ -1088,6 +1088,10 @@ historyUnreadReactions: TwoIconButton(historyToDown) {
iconAbove: icon {{ "history_unread_reaction", historyToDownFg }};
iconAboveOver: icon {{ "history_unread_reaction", historyToDownFgOver }};
}
+historyUnreadPollVotes: TwoIconButton(historyToDown) {
+ iconAbove: icon {{ "history_unread_poll_vote-40x40", historyToDownFg, point(6px, 6px) }};
+ iconAboveOver: icon {{ "history_unread_poll_vote-40x40", historyToDownFgOver, point(6px, 6px) }};
+}
historyUnreadThingsSkip: 4px;
historyQuoteStyle: QuoteStyle(defaultQuoteStyle) {
diff --git a/Telegram/SourceFiles/data/data_changes.h b/Telegram/SourceFiles/data/data_changes.h
index f5c66416af..84faa0757e 100644
--- a/Telegram/SourceFiles/data/data_changes.h
+++ b/Telegram/SourceFiles/data/data_changes.h
@@ -152,8 +152,9 @@ struct HistoryUpdate {
CloudDraft = (1U << 12),
TranslateFrom = (1U << 13),
TranslatedTo = (1U << 14),
+ UnreadPollVotes = (1U << 15),
- LastUsedBit = (1U << 14),
+ LastUsedBit = (1U << 15),
};
using Flags = base::flags;
friend inline constexpr auto is_flag_type(Flag) { return true; }
@@ -178,8 +179,9 @@ struct TopicUpdate {
Closed = (1U << 9),
Creator = (1U << 10),
Destroyed = (1U << 11),
+ UnreadPollVotes = (1U << 12),
- LastUsedBit = (1U << 11),
+ LastUsedBit = (1U << 12),
};
using Flags = base::flags;
friend inline constexpr auto is_flag_type(Flag) { return true; }
@@ -197,8 +199,9 @@ struct SublistUpdate {
UnreadReactions = (1U << 2),
CloudDraft = (1U << 3),
Destroyed = (1U << 4),
+ UnreadPollVotes = (1U << 5),
- LastUsedBit = (1U << 4),
+ LastUsedBit = (1U << 5),
};
using Flags = base::flags;
friend inline constexpr auto is_flag_type(Flag) { return true; }
diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp
index f032785f3f..46897b6908 100644
--- a/Telegram/SourceFiles/data/data_folder.cpp
+++ b/Telegram/SourceFiles/data/data_folder.cpp
@@ -387,7 +387,11 @@ Dialogs::BadgesState Folder::chatListBadgesState() const {
chatListUnreadState(),
Dialogs::CountInBadge::Chats,
Dialogs::IncludeInBadge::All);
- result.unreadMuted = result.mentionMuted = result.reactionMuted = true;
+ result.unreadMuted
+ = result.mentionMuted
+ = result.reactionMuted
+ = result.pollMuted
+ = true;
if (result.unread && !result.unreadCounter) {
result.unreadCounter = 1;
}
diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp
index 0c059f9490..ec8bfb59a3 100644
--- a/Telegram/SourceFiles/data/data_forum.cpp
+++ b/Telegram/SourceFiles/data/data_forum.cpp
@@ -584,6 +584,12 @@ void Forum::clearAllUnreadReactions() {
}
}
+void Forum::clearAllUnreadPollVotes() {
+ for (const auto &[rootId, topic] : _topics) {
+ topic->unreadPollVotes().clear();
+ }
+}
+
void Forum::enumerateTopics(Fn)> action) const {
for (const auto &[rootId, topic] : _topics) {
action(topic.get());
diff --git a/Telegram/SourceFiles/data/data_forum.h b/Telegram/SourceFiles/data/data_forum.h
index 96f4fcb49f..8a5fb37cf2 100644
--- a/Telegram/SourceFiles/data/data_forum.h
+++ b/Telegram/SourceFiles/data/data_forum.h
@@ -91,6 +91,7 @@ public:
void clearAllUnreadMentions();
void clearAllUnreadReactions();
+ void clearAllUnreadPollVotes();
void enumerateTopics(Fn)> action) const;
void listMessageChanged(HistoryItem *from, HistoryItem *to);
diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp
index 4f096f8be3..a712c83ff3 100644
--- a/Telegram/SourceFiles/data/data_forum_topic.cpp
+++ b/Telegram/SourceFiles/data/data_forum_topic.cpp
@@ -989,6 +989,9 @@ void ForumTopic::hasUnreadReactionChanged(bool has) {
notifyUnreadStateChange(was);
}
+void ForumTopic::hasUnreadPollVoteChanged(bool has) {
+}
+
const QString &ForumTopic::chatListNameSortKey() const {
static const auto empty = QString();
return empty;
diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h
index 068fb343ab..383fa26754 100644
--- a/Telegram/SourceFiles/data/data_forum_topic.h
+++ b/Telegram/SourceFiles/data/data_forum_topic.h
@@ -141,6 +141,7 @@ public:
void hasUnreadMentionChanged(bool has) override;
void hasUnreadReactionChanged(bool has) override;
+ void hasUnreadPollVoteChanged(bool has) override;
[[nodiscard]] HistoryItem *lastMessage() const;
[[nodiscard]] HistoryItem *lastServerMessage() const;
diff --git a/Telegram/SourceFiles/data/data_saved_sublist.cpp b/Telegram/SourceFiles/data/data_saved_sublist.cpp
index 21209db5f1..1542c484a0 100644
--- a/Telegram/SourceFiles/data/data_saved_sublist.cpp
+++ b/Telegram/SourceFiles/data/data_saved_sublist.cpp
@@ -963,6 +963,7 @@ Dialogs::BadgesState SavedSublist::chatListBadgesState() const {
result.unreadMuted
= result.mentionMuted
= result.reactionMuted
+ = result.pollMuted
= true;
}
return result;
@@ -1028,6 +1029,9 @@ void SavedSublist::hasUnreadReactionChanged(bool has) {
notifyUnreadStateChange(was);
}
+void SavedSublist::hasUnreadPollVoteChanged(bool has) {
+}
+
void SavedSublist::allowChatListMessageResolve() {
if (_flags & Flag::ResolveChatListMessage) {
return;
diff --git a/Telegram/SourceFiles/data/data_saved_sublist.h b/Telegram/SourceFiles/data/data_saved_sublist.h
index 38a06f83e3..b1d2422587 100644
--- a/Telegram/SourceFiles/data/data_saved_sublist.h
+++ b/Telegram/SourceFiles/data/data_saved_sublist.h
@@ -90,6 +90,7 @@ public:
void hasUnreadMentionChanged(bool has) override;
void hasUnreadReactionChanged(bool has) override;
+ void hasUnreadPollVoteChanged(bool has) override;
[[nodiscard]] HistoryItem *lastMessage() const;
[[nodiscard]] HistoryItem *lastServerMessage() const;
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index ac2d58ce66..b459dedfe9 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtproto_config.h"
#include "window/notifications_manager.h"
#include "history/history.h"
+#include "history/history_item.h"
#include "history/history_item_components.h"
#include "history/view/media/history_view_media.h"
#include "history/view/history_view_element.h"
@@ -4464,6 +4465,23 @@ void Session::applyUpdate(const MTPDupdateMessagePoll &update) {
if (updated && updated->applyResults(update.vresults())) {
notifyPollUpdateDelayed(updated);
}
+ if (const auto tlPeer = update.vpeer()) {
+ const auto peer = peerFromMTP(*tlPeer);
+ if (const auto history = historyLoaded(peer)) {
+ histories().requestDialogEntry(history);
+ }
+ } else if (updated) {
+ if (const auto i = _pollViews.find(updated)
+ ; i != _pollViews.end()) {
+ for (const auto &view : i->second) {
+ if (view->data()->hasUnreadPollVote()) {
+ histories().requestDialogEntry(
+ view->data()->history());
+ break;
+ }
+ }
+ }
+ }
}
void Session::applyUpdate(const MTPDupdateChatParticipants &update) {
diff --git a/Telegram/SourceFiles/data/data_thread.cpp b/Telegram/SourceFiles/data/data_thread.cpp
index cf35b979e4..5fd76d0162 100644
--- a/Telegram/SourceFiles/data/data_thread.cpp
+++ b/Telegram/SourceFiles/data/data_thread.cpp
@@ -98,6 +98,22 @@ HistoryUnreadThings::ConstProxy Thread::unreadReactions() const {
};
}
+HistoryUnreadThings::Proxy Thread::unreadPollVotes() {
+ return {
+ this,
+ _unreadThings,
+ HistoryUnreadThings::Type::PollVotes,
+ !!(_flags & Flag::UnreadThingsKnown),
+ };
+}
+
+HistoryUnreadThings::ConstProxy Thread::unreadPollVotes() const {
+ return {
+ _unreadThings ? &_unreadThings->pollVotes : nullptr,
+ !!(_flags & Flag::UnreadThingsKnown),
+ };
+}
+
bool Thread::canToggleUnread(bool nowUnread) const {
if ((asTopic() || asForum()) && !nowUnread) {
return false;
@@ -125,6 +141,14 @@ const base::flat_set &Thread::unreadReactionsIds() const {
return _unreadThings->reactions.ids();
}
+const base::flat_set &Thread::unreadPollVotesIds() const {
+ if (!_unreadThings) {
+ static const auto Result = base::flat_set();
+ return Result;
+ }
+ return _unreadThings->pollVotes.ids();
+}
+
void Thread::clearNotifications() {
_notifications.clear();
}
diff --git a/Telegram/SourceFiles/data/data_thread.h b/Telegram/SourceFiles/data/data_thread.h
index 42fd2dca06..c57943baa2 100644
--- a/Telegram/SourceFiles/data/data_thread.h
+++ b/Telegram/SourceFiles/data/data_thread.h
@@ -78,8 +78,11 @@ public:
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadMentions() const;
[[nodiscard]] HistoryUnreadThings::Proxy unreadReactions();
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadReactions() const;
+ [[nodiscard]] HistoryUnreadThings::Proxy unreadPollVotes();
+ [[nodiscard]] HistoryUnreadThings::ConstProxy unreadPollVotes() const;
virtual void hasUnreadMentionChanged(bool has) = 0;
virtual void hasUnreadReactionChanged(bool has) = 0;
+ virtual void hasUnreadPollVoteChanged(bool has) = 0;
bool canToggleUnread(bool nowUnread) const;
void removeNotification(not_null item);
@@ -106,6 +109,7 @@ public:
[[nodiscard]] const base::flat_set &unreadMentionsIds() const;
[[nodiscard]] const base::flat_set &unreadReactionsIds() const;
+ [[nodiscard]] const base::flat_set &unreadPollVotesIds() const;
[[nodiscard]] Ui::Text::String &cloudDraftTextCache() {
return _cloudDraftTextCache;
diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h
index 92c7958f4d..7017b37cd6 100644
--- a/Telegram/SourceFiles/data/data_types.h
+++ b/Telegram/SourceFiles/data/data_types.h
@@ -363,6 +363,7 @@ enum class MessageFlag : uint64 {
HasHiddenLinks = (1ULL << 56),
HasSummaryEntry = (1ULL << 57),
CanBeSummarized = (1ULL << 58),
+ HasUnreadPollVote = (1ULL << 59),
};
inline constexpr bool is_flag_type(MessageFlag) { return true; }
using MessageFlags = base::flags;
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index b7dc560cbe..9cd279ee15 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -918,6 +918,57 @@ void History::clearUnreadReactionsFor(
}
}
+int History::unreadPollVotesCount() const {
+ return _unreadPollVotesCount;
+}
+
+void History::setUnreadPollVotesCount(int count) {
+ if (_unreadPollVotesCount == count) {
+ return;
+ }
+ const auto notifier = unreadStateChangeNotifier(
+ useMyUnreadInParent());
+ _unreadPollVotesCount = count;
+ _unreadPollVotesCountChanges.fire_copy(count);
+}
+
+rpl::producer History::unreadPollVotesCountChanges() const {
+ return _unreadPollVotesCountChanges.events();
+}
+
+void History::clearUnreadPollVotesFor(MsgId topicRootId) {
+ const auto forum = peer->forum();
+ if (!topicRootId) {
+ if (forum) {
+ forum->clearAllUnreadPollVotes();
+ }
+ unreadPollVotes().clear();
+ return;
+ } else if (forum) {
+ if (const auto topic = forum->topicFor(topicRootId)) {
+ topic->unreadPollVotes().clear();
+ }
+ }
+ const auto &ids = unreadPollVotesIds();
+ if (ids.empty()) {
+ return;
+ }
+ const auto owner = &this->owner();
+ const auto peerId = peer->id;
+ auto items = base::flat_set();
+ items.reserve(ids.size());
+ for (const auto &id : ids) {
+ if (const auto item = owner->message(peerId, id)) {
+ if (item->topicRootId() == topicRootId) {
+ items.emplace(id);
+ }
+ }
+ }
+ for (const auto &id : items) {
+ unreadPollVotes().erase(id);
+ }
+}
+
not_null History::addNewToBack(
not_null item,
bool unread) {
@@ -2111,7 +2162,7 @@ void History::setMuted(bool muted) {
const auto state = useMyUnreadInParent()
? computeBadgesState()
: Dialogs::BadgesState();
- const auto notify = (state.unread || state.reaction);
+ const auto notify = (state.unread || state.reaction || state.poll);
const auto notifier = unreadStateChangeNotifier(notify);
Thread::setMuted(muted);
}
@@ -2247,6 +2298,20 @@ void History::hasUnreadReactionChanged(bool has) {
notifyUnreadStateChange(was);
}
+void History::hasUnreadPollVoteChanged(bool has) {
+ if (isForum()) {
+ return;
+ }
+ auto was = chatListUnreadState();
+ if (has) {
+ was.polls = was.pollsMuted = 0;
+ } else {
+ was.polls = 1;
+ was.pollsMuted = muted() ? was.polls : 0;
+ }
+ notifyUnreadStateChange(was);
+}
+
void History::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
const auto folderId = data.vfolder_id().value_or_empty();
if (!folderKnown()) {
@@ -2451,7 +2516,11 @@ Dialogs::BadgesState History::computeBadgesState() const {
Dialogs::BadgesState History::adjustBadgesStateByFolder(
Dialogs::BadgesState state) const {
if (folder()) {
- state.mentionMuted = state.reactionMuted = state.unreadMuted = true;
+ state.mentionMuted
+ = state.reactionMuted
+ = state.pollMuted
+ = state.unreadMuted
+ = true;
}
return state;
}
@@ -2466,10 +2535,12 @@ Dialogs::UnreadState History::computeUnreadState() const {
result.marks = mark ? 1 : 0;
result.mentions = unreadMentions().has() ? 1 : 0;
result.reactions = unreadReactions().has() ? 1 : 0;
+ result.polls = (_unreadPollVotesCount > 0) ? 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.pollsMuted = muted ? result.polls : 0;
result.known = _unreadCount.has_value();
return result;
}
@@ -2480,6 +2551,7 @@ Dialogs::UnreadState History::withMyMuted(Dialogs::UnreadState state) const {
state.marksMuted = state.marks;
state.messagesMuted = state.messages;
state.reactionsMuted = state.reactions;
+ state.pollsMuted = state.polls;
}
return state;
}
@@ -3059,6 +3131,12 @@ void History::applyDialog(
setUnreadMark(data.is_unread_mark());
unreadMentions().setCount(data.vunread_mentions_count().v);
unreadReactions().setCount(data.vunread_reactions_count().v);
+ const auto pollVotesCount = data.vunread_poll_votes_count().v;
+ setUnreadPollVotesCount(pollVotesCount);
+ unreadPollVotes().setCount(pollVotesCount);
+ session().changes().historyUpdated(
+ this,
+ Data::HistoryUpdate::Flag::UnreadPollVotes);
if (const auto channel = peer->asChannel()) {
if (const auto pts = data.vpts()) {
channel->ptsReceived(pts->v);
diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h
index 63dac2ed2a..aec389e3f8 100644
--- a/Telegram/SourceFiles/history/history.h
+++ b/Telegram/SourceFiles/history/history.h
@@ -294,6 +294,11 @@ public:
void clearUnreadReactionsFor(
MsgId topicRootId,
Data::SavedSublist *sublist);
+ void clearUnreadPollVotesFor(MsgId topicRootId);
+
+ [[nodiscard]] int unreadPollVotesCount() const;
+ void setUnreadPollVotesCount(int count);
+ [[nodiscard]] rpl::producer unreadPollVotesCountChanges() const;
Data::Draft *draft(Data::DraftKey key) const;
void setDraft(Data::DraftKey key, std::unique_ptr &&draft);
@@ -619,6 +624,7 @@ private:
void hasUnreadMentionChanged(bool has) override;
void hasUnreadReactionChanged(bool has) override;
+ void hasUnreadPollVoteChanged(bool has) override;
[[nodiscard]] bool useMyUnreadInParent() const;
const std::unique_ptr _delegateMixin;
@@ -639,6 +645,8 @@ private:
std::optional _inboxReadBefore;
std::optional _outboxReadBefore;
std::optional _unreadCount;
+ int _unreadPollVotesCount = 0;
+ rpl::event_stream _unreadPollVotesCountChanges;
std::optional _lastMessage;
std::optional _lastServerMessage;
base::flat_set> _clientSideMessages;
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index 75a5ccabfb..b1a65787b2 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -1563,6 +1563,14 @@ bool HistoryItem::hasUnreadReaction() const {
return (_flags & MessageFlag::HasUnreadReaction);
}
+bool HistoryItem::hasUnreadPollVote() const {
+ return (_flags & MessageFlag::HasUnreadPollVote);
+}
+
+void HistoryItem::setHasUnreadPollVote() {
+ _flags |= MessageFlag::HasUnreadPollVote;
+}
+
bool HistoryItem::hasUnwatchedEffect() const {
return effectId() && !(_flags & MessageFlag::EffectWatched);
}
@@ -1642,6 +1650,16 @@ void HistoryItem::markReactionsRead() {
}
}
+void HistoryItem::markPollVotesRead() {
+ _flags &= ~MessageFlag::HasUnreadPollVote;
+ _history->updateChatListEntry();
+ _history->unreadPollVotes().erase(id);
+ if (const auto topic = this->topic()) {
+ topic->updateChatListEntry();
+ topic->unreadPollVotes().erase(id);
+ }
+}
+
bool HistoryItem::markContentsRead(bool fromThisClient) {
if (hasUnreadReaction()) {
if (fromThisClient) {
@@ -2429,7 +2447,8 @@ void HistoryItem::addToUnreadThings(HistoryUnreadThings::AddType type) {
}
const auto mention = isUnreadMention();
const auto reaction = hasUnreadReaction();
- if (!mention && !reaction) {
+ const auto pollVote = hasUnreadPollVote();
+ if (!mention && !reaction && !pollVote) {
return;
}
const auto topic = this->topic();
@@ -2479,6 +2498,23 @@ void HistoryItem::addToUnreadThings(HistoryUnreadThings::AddType type) {
}
}
}
+ if (pollVote) {
+ const auto toHistory = history->unreadPollVotes().add(id, type);
+ const auto toTopic = topic
+ && topic->unreadPollVotes().add(id, type);
+ if (toHistory || toTopic) {
+ if (toHistory) {
+ changes->historyUpdated(
+ history,
+ Data::HistoryUpdate::Flag::UnreadPollVotes);
+ }
+ if (toTopic) {
+ changes->topicUpdated(
+ topic,
+ Data::TopicUpdate::Flag::UnreadPollVotes);
+ }
+ }
+ }
}
void HistoryItem::destroyHistoryEntry() {
@@ -2496,6 +2532,12 @@ void HistoryItem::destroyHistoryEntry() {
sublist->unreadReactions().erase(id);
}
}
+ if (hasUnreadPollVote()) {
+ history()->unreadPollVotes().erase(id);
+ if (const auto topic = this->topic()) {
+ topic->unreadPollVotes().erase(id);
+ }
+ }
if (isRegular() && _history->peer->isMegagroup()) {
if (const auto reply = Get()) {
changeReplyToTopCounter(reply, -1);
diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h
index 8705b162c1..7f396c6336 100644
--- a/Telegram/SourceFiles/history/history_item.h
+++ b/Telegram/SourceFiles/history/history_item.h
@@ -260,12 +260,15 @@ public:
[[nodiscard]] bool mentionsMe() const;
[[nodiscard]] bool isUnreadMention() const;
[[nodiscard]] bool hasUnreadReaction() const;
+ [[nodiscard]] bool hasUnreadPollVote() const;
+ void setHasUnreadPollVote();
[[nodiscard]] bool hasUnwatchedEffect() const;
bool markEffectWatched();
[[nodiscard]] bool isUnreadMedia() const;
[[nodiscard]] bool isIncomingUnreadMedia() const;
[[nodiscard]] bool hasUnreadMediaFlag() const;
void markReactionsRead();
+ void markPollVotesRead();
void markMediaAndMentionRead();
bool markContentsRead(bool fromThisClient = false);
void setIsPinned(bool isPinned);
diff --git a/Telegram/SourceFiles/history/history_unread_things.cpp b/Telegram/SourceFiles/history/history_unread_things.cpp
index eeed5bddea..dc55d65697 100644
--- a/Telegram/SourceFiles/history/history_unread_things.cpp
+++ b/Telegram/SourceFiles/history/history_unread_things.cpp
@@ -27,6 +27,7 @@ template
switch (type) {
case Type::Mentions: return Flag::UnreadMentions;
case Type::Reactions: return Flag::UnreadReactions;
+ case Type::PollVotes: return Flag::UnreadPollVotes;
}
Unexpected("Type in HistoryUnreadThings::UpdateFlag.");
}
@@ -40,8 +41,11 @@ template
}
[[nodiscard]] Data::SublistUpdate::Flag SublistUpdateFlag(Type type) {
- Expects(type == Type::Reactions);
+ Expects(type == Type::Reactions || type == Type::PollVotes);
+ if (type == Type::PollVotes) {
+ return Data::SublistUpdate::Flag::UnreadPollVotes;
+ }
return Data::SublistUpdate::Flag::UnreadReactions;
}
@@ -58,6 +62,9 @@ void Proxy::setCount(int count) {
createData();
}
auto &list = resolveList();
+ if (!count) {
+ list.clear();
+ }
const auto loaded = list.loadedCount();
if (loaded > count) {
LOG(("API Warning: "
@@ -65,10 +72,23 @@ void Proxy::setCount(int count) {
count = loaded;
}
const auto had = (list.count() > 0);
- const auto &other = (_type == Type::Mentions)
- ? _data->reactions
- : _data->mentions;
- if (!count && other.count(-1) == 0) {
+ const auto othersEmpty = [&] {
+ for (auto t : { Type::Mentions, Type::Reactions, Type::PollVotes }) {
+ if (t == _type) {
+ continue;
+ }
+ const auto &other = (t == Type::Mentions)
+ ? _data->mentions
+ : (t == Type::Reactions)
+ ? _data->reactions
+ : _data->pollVotes;
+ if (other.count(-1) != 0) {
+ return false;
+ }
+ }
+ return true;
+ }();
+ if (!count && othersEmpty) {
_data = nullptr;
} else {
list.setCount(count);
@@ -79,6 +99,8 @@ void Proxy::setCount(int count) {
_thread->hasUnreadMentionChanged(has);
} else if (_type == Type::Reactions) {
_thread->hasUnreadReactionChanged(has);
+ } else if (_type == Type::PollVotes) {
+ _thread->hasUnreadPollVoteChanged(has);
}
}
}
@@ -183,10 +205,14 @@ void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
message,
localFlags,
type);
+ if (_type == Type::PollVotes) {
+ item->setHasUnreadPollVote();
+ }
const auto is = [&] {
switch (_type) {
case Type::Mentions: return item->isUnreadMention();
case Type::Reactions: return item->hasUnreadReaction();
+ case Type::PollVotes: return item->hasUnreadPollVote();
}
Unexpected("Type in Proxy::addSlice.");
}();
@@ -203,7 +229,7 @@ void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
}
void Proxy::checkAdd(MsgId msgId, bool resolved) {
- Expects(_type == Type::Reactions);
+ Expects(_type == Type::Reactions || _type == Type::PollVotes);
if (!_data) {
return;
@@ -215,11 +241,19 @@ void Proxy::checkAdd(MsgId msgId, bool resolved) {
const auto history = _thread->owningHistory();
const auto peer = history->peer;
const auto item = peer->owner().message(peer, msgId);
- if (item && item->hasUnreadReaction()) {
+ const auto matches = item
+ && ((_type == Type::Reactions) ? item->hasUnreadReaction()
+ : item->hasUnreadPollVote());
+ if (matches) {
item->addToUnreadThings(AddType::Existing);
} else if (!item && !resolved) {
+ const auto type = _type;
peer->session().api().requestMessageData(peer, msgId, [=] {
- history->unreadReactions().checkAdd(msgId, true);
+ if (type == Type::Reactions) {
+ history->unreadReactions().checkAdd(msgId, true);
+ } else {
+ history->unreadPollVotes().checkAdd(msgId, true);
+ }
});
}
}
@@ -245,6 +279,7 @@ void Proxy::createData() {
if (_known) {
_data->mentions.setCount(0);
_data->reactions.setCount(0);
+ _data->pollVotes.setCount(0);
}
}
@@ -254,6 +289,7 @@ List &Proxy::resolveList() {
switch (_type) {
case Type::Mentions: return _data->mentions;
case Type::Reactions: return _data->reactions;
+ case Type::PollVotes: return _data->pollVotes;
}
Unexpected("Unread things type in Proxy::resolveList.");
}
diff --git a/Telegram/SourceFiles/history/history_unread_things.h b/Telegram/SourceFiles/history/history_unread_things.h
index a8b874d11d..493b46c513 100644
--- a/Telegram/SourceFiles/history/history_unread_things.h
+++ b/Telegram/SourceFiles/history/history_unread_things.h
@@ -23,6 +23,7 @@ enum class AddType {
enum class Type {
Mentions,
Reactions,
+ PollVotes,
};
class List final {
@@ -70,6 +71,7 @@ private:
struct All {
List mentions;
List reactions;
+ List pollVotes;
};
class ConstProxy {
@@ -117,7 +119,9 @@ public:
? nullptr
: (type == Type::Mentions)
? &data->mentions
- : &data->reactions),
+ : (type == Type::Reactions)
+ ? &data->reactions
+ : &data->pollVotes),
known)
, _thread(thread)
, _data(data)
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 96c929ac0b..da0f63cfba 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -715,6 +715,7 @@ HistoryWidget::HistoryWidget(
| HistoryUpdateFlag::CloudDraft
| HistoryUpdateFlag::UnreadMentions
| HistoryUpdateFlag::UnreadReactions
+ | HistoryUpdateFlag::UnreadPollVotes
| HistoryUpdateFlag::UnreadView
| HistoryUpdateFlag::TopPromoted
| HistoryUpdateFlag::ClientSideMessages
@@ -735,7 +736,8 @@ HistoryWidget::HistoryWidget(
updateSendButtonType();
}
if ((flags & HistoryUpdateFlag::UnreadMentions)
- || (flags & HistoryUpdateFlag::UnreadReactions)) {
+ || (flags & HistoryUpdateFlag::UnreadReactions)
+ || (flags & HistoryUpdateFlag::UnreadPollVotes)) {
_cornerButtons.updateUnreadThingsVisibility();
}
if (flags & HistoryUpdateFlag::UnreadView) {
diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
index 7b36e69aa7..65f8778f9b 100644
--- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp
@@ -635,9 +635,13 @@ void ChatWidget::subscribeToTopic() {
_topic,
(Flag::UnreadMentions
| Flag::UnreadReactions
+ | Flag::UnreadPollVotes
| Flag::CloudDraft)
) | rpl::on_next([=](const Data::TopicUpdate &update) {
- if (update.flags & (Flag::UnreadMentions | Flag::UnreadReactions)) {
+ if (update.flags
+ & (Flag::UnreadMentions
+ | Flag::UnreadReactions
+ | Flag::UnreadPollVotes)) {
_cornerButtons.updateUnreadThingsVisibility();
}
if (update.flags & Flag::CloudDraft) {
@@ -2589,12 +2593,16 @@ void ChatWidget::subscribeToSublist() {
using Flag = Data::SublistUpdate::Flag;
session().changes().sublistUpdates(
_sublist,
- Flag::UnreadView | Flag::UnreadReactions | Flag::CloudDraft
+ (Flag::UnreadView
+ | Flag::UnreadReactions
+ | Flag::UnreadPollVotes
+ | Flag::CloudDraft)
) | rpl::on_next([=](const Data::SublistUpdate &update) {
if (update.flags & Flag::UnreadView) {
unreadCountUpdated();
}
- if (update.flags & Flag::UnreadReactions) {
+ if (update.flags
+ & (Flag::UnreadReactions | Flag::UnreadPollVotes)) {
_cornerButtons.updateUnreadThingsVisibility();
}
if (update.flags & Flag::CloudDraft) {
diff --git a/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp b/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp
index 8d9d7fed2d..270979e778 100644
--- a/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp
@@ -68,10 +68,14 @@ CornerButtons::CornerButtons(
st->value(_stLifetime, st::historyUnreadMentions))
, _reactions(
parent,
- st->value(_stLifetime, st::historyUnreadReactions)) {
+ st->value(_stLifetime, st::historyUnreadReactions))
+, _pollVotes(
+ parent,
+ st->value(_stLifetime, st::historyUnreadPollVotes)) {
_down.widget->addClickHandler([=] { downClick(); });
_mentions.widget->addClickHandler([=] { mentionsClick(); });
_reactions.widget->addClickHandler([=] { reactionsClick(); });
+ _pollVotes.widget->addClickHandler([=] { pollVotesClick(); });
const auto filterScroll = [&](CornerButton &button) {
button.widget->installEventFilter(this);
@@ -79,6 +83,7 @@ CornerButtons::CornerButtons(
filterScroll(_down);
filterScroll(_mentions);
filterScroll(_reactions);
+ filterScroll(_pollVotes);
SendMenu::SetupUnreadMentionsMenu(_mentions.widget.data(), [=] {
return _delegate->cornerButtonsThread();
@@ -86,13 +91,17 @@ CornerButtons::CornerButtons(
SendMenu::SetupUnreadReactionsMenu(_reactions.widget.data(), [=] {
return _delegate->cornerButtonsThread();
});
+ SendMenu::SetupUnreadPollVotesMenu(_pollVotes.widget.data(), [=] {
+ return _delegate->cornerButtonsThread();
+ });
}
bool CornerButtons::eventFilter(QObject *o, QEvent *e) {
if (e->type() == QEvent::Wheel
&& (o == _down.widget
|| o == _mentions.widget
- || o == _reactions.widget)) {
+ || o == _reactions.widget
+ || o == _pollVotes.widget)) {
return _scrollViewportEvent(e);
}
return QObject::eventFilter(o, e);
@@ -142,6 +151,15 @@ void CornerButtons::reactionsClick() {
showAt(thread->unreadReactions().minLoaded());
}
+void CornerButtons::pollVotesClick() {
+ const auto history = lookupHistory();
+ if (!history) {
+ return;
+ }
+ const auto thread = _delegate->cornerButtonsThread();
+ showAt(thread->unreadPollVotes().minLoaded());
+}
+
void CornerButtons::clearReplyReturns() {
_replyReturns.clear();
_replyReturn = nullptr;
@@ -208,6 +226,7 @@ CornerButton &CornerButtons::buttonByType(Type type) {
case Type::Down: return _down;
case Type::Mentions: return _mentions;
case Type::Reactions: return _reactions;
+ case Type::PollVotes: return _pollVotes;
}
Unexpected("Type in CornerButtons::buttonByType.");
}
@@ -245,6 +264,7 @@ void CornerButtons::updateUnreadThingsVisibility() {
if (!thread) {
updateVisibility(Type::Mentions, false);
updateVisibility(Type::Reactions, false);
+ updateVisibility(Type::PollVotes, false);
return;
}
auto &unreadThings = thread->session().api().unreadThings();
@@ -278,6 +298,18 @@ void CornerButtons::updateUnreadThingsVisibility() {
} else {
updateVisibility(Type::Reactions, false);
}
+
+ if (_delegate->cornerButtonsHas(Type::PollVotes)
+ && unreadThings.trackPollVotes(thread)) {
+ if (const auto count = thread->unreadPollVotes().count(0)) {
+ _pollVotes.widget->setUnreadCount(count);
+ }
+ updateWithCount(
+ Type::PollVotes,
+ thread->unreadPollVotes().loadedCount());
+ } else {
+ updateVisibility(Type::PollVotes, false);
+ }
}
void CornerButtons::updateJumpDownVisibility(std::optional counter) {
@@ -306,6 +338,7 @@ void CornerButtons::updatePositions() {
const auto historyDownShown = shown(_down);
const auto unreadMentionsShown = shown(_mentions);
const auto unreadReactionsShown = shown(_reactions);
+ const auto unreadPollVotesShown = shown(_pollVotes);
const auto skip = st::historyUnreadThingsSkip;
{
const auto top = anim::interpolate(
@@ -350,16 +383,41 @@ void CornerButtons::updatePositions() {
- shift;
_reactions.widget->moveToRight(right, top);
}
+ {
+ const auto right = anim::interpolate(
+ -_pollVotes.widget->width(),
+ st::historyToDownPosition.x(),
+ unreadPollVotesShown);
+ const auto shift = anim::interpolate(
+ 0,
+ _down.widget->height() + skip,
+ historyDownShown
+ ) + anim::interpolate(
+ 0,
+ _mentions.widget->height() + skip,
+ unreadMentionsShown
+ ) + anim::interpolate(
+ 0,
+ _reactions.widget->height() + skip,
+ unreadReactionsShown);
+ const auto top = _parent->height()
+ - _pollVotes.widget->height()
+ - st::historyToDownPosition.y()
+ - shift;
+ _pollVotes.widget->moveToRight(right, top);
+ }
checkVisibility(_down);
checkVisibility(_mentions);
checkVisibility(_reactions);
+ checkVisibility(_pollVotes);
}
void CornerButtons::finishAnimations() {
_down.animation.stop();
_mentions.animation.stop();
_reactions.animation.stop();
+ _pollVotes.animation.stop();
updatePositions();
}
diff --git a/Telegram/SourceFiles/history/view/history_view_corner_buttons.h b/Telegram/SourceFiles/history/view/history_view_corner_buttons.h
index ae7b5b110c..7d3d5aae2b 100644
--- a/Telegram/SourceFiles/history/view/history_view_corner_buttons.h
+++ b/Telegram/SourceFiles/history/view/history_view_corner_buttons.h
@@ -42,6 +42,7 @@ enum class CornerButtonType {
Down,
Mentions,
Reactions,
+ PollVotes,
};
class CornerButtonsDelegate {
@@ -72,6 +73,7 @@ public:
void downClick();
void mentionsClick();
void reactionsClick();
+ void pollVotesClick();
void clearReplyReturns();
[[nodiscard]] QVector replyReturns() const;
@@ -119,6 +121,7 @@ private:
CornerButton _down;
CornerButton _mentions;
CornerButton _reactions;
+ CornerButton _pollVotes;
HistoryItem *_replyReturn = nullptr;
QVector _replyReturns;
diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp
index 47e5ba184b..29262304b1 100644
--- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp
@@ -268,7 +268,8 @@ bool PinnedWidget::cornerButtonsUnreadMayBeShown() {
}
bool PinnedWidget::cornerButtonsHas(CornerButtonType type) {
- return (type == CornerButtonType::Down);
+ return (type == CornerButtonType::Down)
+ || (type == CornerButtonType::PollVotes);
}
void PinnedWidget::showAtPosition(
diff --git a/Telegram/SourceFiles/info/polls/info_polls_list_widget.cpp b/Telegram/SourceFiles/info/polls/info_polls_list_widget.cpp
index f9cd50bd62..b41cc76d2f 100644
--- a/Telegram/SourceFiles/info/polls/info_polls_list_widget.cpp
+++ b/Telegram/SourceFiles/info/polls/info_polls_list_widget.cpp
@@ -722,7 +722,8 @@ bool ListWidget::Inner::cornerButtonsUnreadMayBeShown() {
bool ListWidget::Inner::cornerButtonsHas(
HistoryView::CornerButtonType type) {
- return (type == HistoryView::CornerButtonType::Down);
+ return (type == HistoryView::CornerButtonType::Down)
+ || (type == HistoryView::CornerButtonType::PollVotes);
}
// --- ListMemento ---
diff --git a/Telegram/SourceFiles/menu/menu_send.cpp b/Telegram/SourceFiles/menu/menu_send.cpp
index 8f423fa3a7..6add7bccb9 100644
--- a/Telegram/SourceFiles/menu/menu_send.cpp
+++ b/Telegram/SourceFiles/menu/menu_send.cpp
@@ -1028,4 +1028,46 @@ void SetupUnreadReactionsMenu(
SetupReadAllMenu(button, currentThread, text, sendRequest);
}
+void SetupUnreadPollVotesMenu(
+ not_null button,
+ Fn currentThread) {
+ const auto text = tr::lng_context_mark_read_poll_votes_all(tr::now);
+ const auto sendOne = [=](
+ base::weak_ptr weakThread,
+ Fn done,
+ auto resend) -> void {
+ const auto thread = weakThread.get();
+ if (!thread) {
+ done();
+ return;
+ }
+ const auto topic = thread->asTopic();
+ const auto peer = thread->peer();
+ const auto rootId = topic ? topic->rootId() : 0;
+ using Flag = MTPmessages_ReadPollVotes::Flag;
+ peer->session().api().request(MTPmessages_ReadPollVotes(
+ MTP_flags(rootId ? Flag::f_top_msg_id : Flag(0)),
+ peer->input(),
+ MTP_int(rootId)
+ )).done([=](const MTPmessages_AffectedHistory &result) {
+ const auto offset = peer->session().api().applyAffectedHistory(
+ peer,
+ result);
+ if (offset > 0) {
+ resend(weakThread, done, resend);
+ } else {
+ done();
+ peer->owner().history(peer)->clearUnreadPollVotesFor(
+ rootId);
+ }
+ }).fail(done).send();
+ };
+ const auto sendRequest = [=](
+ not_null thread,
+ Fn done) {
+ sendOne(base::make_weak(thread), std::move(done), sendOne);
+ };
+ SetupReadAllMenu(button, currentThread, text, sendRequest);
+}
+
} // namespace SendMenu
diff --git a/Telegram/SourceFiles/menu/menu_send.h b/Telegram/SourceFiles/menu/menu_send.h
index 993dbffd1a..d748a57523 100644
--- a/Telegram/SourceFiles/menu/menu_send.h
+++ b/Telegram/SourceFiles/menu/menu_send.h
@@ -127,4 +127,8 @@ void SetupUnreadReactionsMenu(
not_null button,
Fn currentThread);
+void SetupUnreadPollVotesMenu(
+ not_null button,
+ Fn currentThread);
+
} // namespace SendMenu