Added api support of notify settings for reactions and poll votes.

This commit is contained in:
23rd
2026-03-29 19:46:10 +03:00
parent 094c43293d
commit 90191819bd
7 changed files with 291 additions and 6 deletions
+2
View File
@@ -165,6 +165,8 @@ PRIVATE
api/api_premium.h
api/api_premium_option.cpp
api/api_premium_option.h
api/api_reactions_notify_settings.cpp
api/api_reactions_notify_settings.h
api/api_read_metrics.cpp
api/api_read_metrics.h
api/api_report.cpp
@@ -0,0 +1,185 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_reactions_notify_settings.h"
#include "apiwrap.h"
#include "main/main_session.h"
namespace Api {
namespace {
[[nodiscard]] ReactionsNotifyFrom ParseFrom(
const MTPReactionNotificationsFrom &from) {
return from.match([](const MTPDreactionNotificationsFromContacts &) {
return ReactionsNotifyFrom::Contacts;
}, [](const MTPDreactionNotificationsFromAll &) {
return ReactionsNotifyFrom::All;
});
}
[[nodiscard]] MTPReactionNotificationsFrom SerializeFrom(
ReactionsNotifyFrom from) {
switch (from) {
case ReactionsNotifyFrom::Contacts:
return MTP_reactionNotificationsFromContacts();
case ReactionsNotifyFrom::All:
return MTP_reactionNotificationsFromAll();
}
Unexpected("Value in SerializeFrom.");
}
} // namespace
ReactionsNotifySettings::ReactionsNotifySettings(not_null<ApiWrap*> api)
: _session(&api->session())
, _api(&api->instance()) {
}
void ReactionsNotifySettings::reload(Fn<void()> callback) {
if (callback) {
_callbacks.push_back(std::move(callback));
}
if (_requestId) {
return;
}
_requestId = _api.request(MTPaccount_GetReactionsNotifySettings(
)).done([=](const MTPReactionsNotifySettings &result) {
_requestId = 0;
apply(result);
for (const auto &callback : base::take(_callbacks)) {
callback();
}
}).fail([=] {
_requestId = 0;
for (const auto &callback : base::take(_callbacks)) {
callback();
}
}).send();
}
void ReactionsNotifySettings::updateMessagesFrom(ReactionsNotifyFrom value) {
_messagesFrom = value;
save();
}
void ReactionsNotifySettings::updatePollVotesFrom(
ReactionsNotifyFrom value) {
_pollVotesFrom = value;
save();
}
void ReactionsNotifySettings::setAllFrom(ReactionsNotifyFrom value) {
_messagesFrom = value;
_pollVotesFrom = value;
save();
}
void ReactionsNotifySettings::updateShowPreviews(bool value) {
_showPreviews = value;
save();
}
ReactionsNotifyFrom ReactionsNotifySettings::messagesFromCurrent() const {
return _messagesFrom.current();
}
rpl::producer<ReactionsNotifyFrom> ReactionsNotifySettings::messagesFrom() const {
return _messagesFrom.value();
}
ReactionsNotifyFrom ReactionsNotifySettings::pollVotesFromCurrent() const {
return _pollVotesFrom.current();
}
rpl::producer<ReactionsNotifyFrom> ReactionsNotifySettings::pollVotesFrom() const {
return _pollVotesFrom.value();
}
bool ReactionsNotifySettings::showPreviewsCurrent() const {
return _showPreviews.current();
}
rpl::producer<bool> ReactionsNotifySettings::showPreviews() const {
return _showPreviews.value();
}
bool ReactionsNotifySettings::enabledCurrent() const {
return (_messagesFrom.current() != ReactionsNotifyFrom::None)
|| (_pollVotesFrom.current() != ReactionsNotifyFrom::None);
}
rpl::producer<bool> ReactionsNotifySettings::enabled() const {
return rpl::combine(
_messagesFrom.value(),
_pollVotesFrom.value()
) | rpl::map([](
ReactionsNotifyFrom messages,
ReactionsNotifyFrom pollVotes) {
return (messages != ReactionsNotifyFrom::None)
|| (pollVotes != ReactionsNotifyFrom::None);
}) | rpl::distinct_until_changed();
}
void ReactionsNotifySettings::apply(
const MTPReactionsNotifySettings &settings) {
const auto &data = settings.data();
const auto messages = data.vmessages_notify_from();
const auto stories = data.vstories_notify_from();
const auto pollVotes = data.vpoll_votes_notify_from();
_messagesFrom = messages
? ParseFrom(*messages)
: ReactionsNotifyFrom::None;
_storiesFrom = stories
? ParseFrom(*stories)
: ReactionsNotifyFrom::None;
_pollVotesFrom = pollVotes
? ParseFrom(*pollVotes)
: ReactionsNotifyFrom::None;
_showPreviews = mtpIsTrue(data.vshow_previews());
}
void ReactionsNotifySettings::save() {
using Flag = MTPDreactionsNotifySettings::Flag;
const auto messages = _messagesFrom.current();
const auto stories = _storiesFrom.current();
const auto pollVotes = _pollVotesFrom.current();
const auto previews = _showPreviews.current();
const auto flags = Flag()
| ((messages != ReactionsNotifyFrom::None)
? Flag::f_messages_notify_from
: Flag())
| ((stories != ReactionsNotifyFrom::None)
? Flag::f_stories_notify_from
: Flag())
| ((pollVotes != ReactionsNotifyFrom::None)
? Flag::f_poll_votes_notify_from
: Flag());
_api.request(base::take(_requestId)).cancel();
_requestId = _api.request(MTPaccount_SetReactionsNotifySettings(
MTP_reactionsNotifySettings(
MTP_flags(flags),
((messages != ReactionsNotifyFrom::None)
? SerializeFrom(messages)
: MTPReactionNotificationsFrom()),
((stories != ReactionsNotifyFrom::None)
? SerializeFrom(stories)
: MTPReactionNotificationsFrom()),
((pollVotes != ReactionsNotifyFrom::None)
? SerializeFrom(pollVotes)
: MTPReactionNotificationsFrom()),
MTP_notificationSoundDefault(),
MTP_bool(previews))
)).done([=](const MTPReactionsNotifySettings &result) {
_requestId = 0;
apply(result);
}).fail([=] {
_requestId = 0;
}).send();
}
} // namespace Api
@@ -0,0 +1,65 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/sender.h"
class ApiWrap;
namespace Main {
class Session;
} // namespace Main
namespace Api {
enum class ReactionsNotifyFrom : uchar {
None,
Contacts,
All,
};
class ReactionsNotifySettings final {
public:
explicit ReactionsNotifySettings(not_null<ApiWrap*> api);
void reload(Fn<void()> callback = nullptr);
void updateMessagesFrom(ReactionsNotifyFrom value);
void updatePollVotesFrom(ReactionsNotifyFrom value);
void setAllFrom(ReactionsNotifyFrom value);
void updateShowPreviews(bool value);
[[nodiscard]] ReactionsNotifyFrom messagesFromCurrent() const;
[[nodiscard]] rpl::producer<ReactionsNotifyFrom> messagesFrom() const;
[[nodiscard]] ReactionsNotifyFrom pollVotesFromCurrent() const;
[[nodiscard]] rpl::producer<ReactionsNotifyFrom> pollVotesFrom() const;
[[nodiscard]] bool showPreviewsCurrent() const;
[[nodiscard]] rpl::producer<bool> showPreviews() const;
[[nodiscard]] bool enabledCurrent() const;
[[nodiscard]] rpl::producer<bool> enabled() const;
private:
void apply(const MTPReactionsNotifySettings &settings);
void save();
const not_null<Main::Session*> _session;
MTP::Sender _api;
mtpRequestId _requestId = 0;
rpl::variable<ReactionsNotifyFrom> _messagesFrom
= ReactionsNotifyFrom::All;
rpl::variable<ReactionsNotifyFrom> _storiesFrom
= ReactionsNotifyFrom::All;
rpl::variable<ReactionsNotifyFrom> _pollVotesFrom
= ReactionsNotifyFrom::All;
rpl::variable<bool> _showPreviews = true;
std::vector<Fn<void()>> _callbacks;
};
} // namespace Api
+8
View File
@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_self_destruct.h"
#include "api/api_sensitive_content.h"
#include "api/api_global_privacy.h"
#include "api/api_reactions_notify_settings.h"
#include "api/api_updates.h"
#include "api/api_user_privacy.h"
#include "api/api_read_metrics.h"
@@ -179,6 +180,8 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
, _selfDestruct(std::make_unique<Api::SelfDestruct>(this))
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this))
, _globalPrivacy(std::make_unique<Api::GlobalPrivacy>(this))
, _reactionsNotifySettings(
std::make_unique<Api::ReactionsNotifySettings>(this))
, _userPrivacy(std::make_unique<Api::UserPrivacy>(this))
, _inviteLinks(std::make_unique<Api::InviteLinks>(this))
, _chatLinks(std::make_unique<Api::ChatLinks>(this))
@@ -207,6 +210,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
requestMoreDialogsIfNeeded();
}, _session->lifetime());
_reactionsNotifySettings->reload();
setupSupportMode();
});
}
@@ -4968,6 +4972,10 @@ Api::GlobalPrivacy &ApiWrap::globalPrivacy() {
return *_globalPrivacy;
}
Api::ReactionsNotifySettings &ApiWrap::reactionsNotifySettings() {
return *_reactionsNotifySettings;
}
Api::UserPrivacy &ApiWrap::userPrivacy() {
return *_userPrivacy;
}
+3
View File
@@ -69,6 +69,7 @@ class CloudPassword;
class SelfDestruct;
class SensitiveContent;
class GlobalPrivacy;
class ReactionsNotifySettings;
class UserPrivacy;
class InviteLinks;
class ChatLinks;
@@ -412,6 +413,7 @@ public:
[[nodiscard]] Api::SelfDestruct &selfDestruct();
[[nodiscard]] Api::SensitiveContent &sensitiveContent();
[[nodiscard]] Api::GlobalPrivacy &globalPrivacy();
[[nodiscard]] Api::ReactionsNotifySettings &reactionsNotifySettings();
[[nodiscard]] Api::UserPrivacy &userPrivacy();
[[nodiscard]] Api::InviteLinks &inviteLinks();
[[nodiscard]] Api::ChatLinks &chatLinks();
@@ -772,6 +774,7 @@ private:
const std::unique_ptr<Api::SelfDestruct> _selfDestruct;
const std::unique_ptr<Api::SensitiveContent> _sensitiveContent;
const std::unique_ptr<Api::GlobalPrivacy> _globalPrivacy;
const std::unique_ptr<Api::ReactionsNotifySettings> _reactionsNotifySettings;
const std::unique_ptr<Api::UserPrivacy> _userPrivacy;
const std::unique_ptr<Api::InviteLinks> _inviteLinks;
const std::unique_ptr<Api::ChatLinks> _chatLinks;
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/history_item_helpers.h"
#include "api/api_reactions_notify_settings.h"
#include "api/api_text_entities.h"
#include "boxes/premium_preview_box.h"
#include "calls/calls_instance.h"
@@ -1175,15 +1176,22 @@ void CheckReactionNotificationSchedule(
if (!item->hasUnreadReaction()) {
return;
}
const auto from = item->history()->session().api()
.reactionsNotifySettings().messagesFromCurrent();
if (from == Api::ReactionsNotifyFrom::None) {
return;
}
for (const auto &[emoji, reactions] : item->recentReactions()) {
for (const auto &reaction : reactions) {
if (!reaction.unread) {
continue;
}
const auto user = reaction.peer->asUser();
if (!user
|| !user->isContact()
|| ranges::contains(wasUsers, user)) {
if (!user || ranges::contains(wasUsers, user)) {
continue;
}
if (from == Api::ReactionsNotifyFrom::Contacts
&& !user->isContact()) {
continue;
}
using Status = PeerData::BlockStatus;
@@ -1210,11 +1218,19 @@ void CheckPollVoteNotificationSchedule(
if (!poll || !poll->creator()) {
return;
}
const auto from = item->history()->session().api()
.reactionsNotifySettings().pollVotesFromCurrent();
if (from == Api::ReactionsNotifyFrom::None) {
return;
}
for (const auto &answer : poll->answers) {
for (const auto &voter : answer.recentVoters) {
const auto user = voter->asUser();
if (!user
|| ranges::contains(wasRecentVoters, voter)) {
if (!user || ranges::contains(wasRecentVoters, voter)) {
continue;
}
if (from == Api::ReactionsNotifyFrom::Contacts
&& !user->isContact()) {
continue;
}
using Status = PeerData::BlockStatus;
@@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h"
#include "core/application.h"
#include "mainwindow.h"
#include "api/api_reactions_notify_settings.h"
#include "api/api_updates.h"
#include "apiwrap.h"
#include "main/main_account.h"
@@ -1482,8 +1483,13 @@ void NativeManager::doShowNotification(NotificationFields &&fields) {
? tr::lng_notification_reminder(tr::now)
: subWithChat();
const auto fullTitle = addTargetAccountName(title, &peer->session());
const auto hideReactionSender = reactionFrom
&& !peer->session().api().reactionsNotifySettings()
.showPreviewsCurrent();
const auto subtitle = reactionFrom
? (reactionFrom != peer ? reactionFrom->name() : QString())
? ((!hideReactionSender && reactionFrom != peer)
? reactionFrom->name()
: QString())
: options.hideNameAndPhoto
? QString()
: item->notificationHeader();