2022-04-01 10:18:07 +00:00
|
|
|
/*
|
|
|
|
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 "data/notify/data_notify_settings.h"
|
|
|
|
|
|
|
|
#include "apiwrap.h"
|
2022-04-05 12:26:18 +00:00
|
|
|
#include "api/api_ringtones.h"
|
2022-04-01 10:18:07 +00:00
|
|
|
#include "base/unixtime.h"
|
|
|
|
#include "core/application.h"
|
|
|
|
#include "data/data_changes.h"
|
|
|
|
#include "data/data_channel.h"
|
|
|
|
#include "data/data_chat.h"
|
2022-04-05 12:26:18 +00:00
|
|
|
#include "data/data_document.h"
|
|
|
|
#include "data/data_file_origin.h"
|
2022-04-01 10:18:07 +00:00
|
|
|
#include "data/data_peer.h"
|
2022-10-13 18:02:31 +00:00
|
|
|
#include "data/data_forum.h"
|
2022-10-12 20:23:14 +00:00
|
|
|
#include "data/data_forum_topic.h"
|
2022-04-01 10:18:07 +00:00
|
|
|
#include "data/data_session.h"
|
|
|
|
#include "data/data_user.h"
|
2022-04-05 12:26:18 +00:00
|
|
|
#include "main/main_session.h"
|
2022-04-01 10:18:07 +00:00
|
|
|
#include "history/history.h"
|
|
|
|
#include "main/main_session.h"
|
|
|
|
#include "window/notifications_manager.h"
|
|
|
|
|
|
|
|
namespace Data {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
constexpr auto kMaxNotifyCheckDelay = 24 * 3600 * crl::time(1000);
|
|
|
|
|
2022-10-12 20:23:14 +00:00
|
|
|
[[nodiscard]] bool MutedFromUntil(TimeId until, crl::time *changesIn) {
|
|
|
|
const auto now = base::unixtime::now();
|
|
|
|
const auto result = (until > now) ? (until - now) : 0;
|
|
|
|
if (changesIn) {
|
|
|
|
*changesIn = (result > 0)
|
|
|
|
? std::min(result * crl::time(1000), kMaxNotifyCheckDelay)
|
|
|
|
: kMaxNotifyCheckDelay;
|
|
|
|
}
|
|
|
|
return (result > 0);
|
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
[[nodiscard]] bool SkipAddException(not_null<PeerData*> peer) {
|
|
|
|
if (const auto user = peer->asUser()) {
|
2023-09-01 06:52:30 +00:00
|
|
|
return user->isInaccessible() || user->isSelf();
|
2023-08-23 11:20:41 +00:00
|
|
|
} else if (const auto chat = peer->asChat()) {
|
|
|
|
return chat->isDeactivated() || chat->isForbidden();
|
|
|
|
} else if (const auto channel = peer->asChannel()) {
|
|
|
|
return channel->isForbidden();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-04-01 10:18:07 +00:00
|
|
|
} // namespace
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
DefaultNotify DefaultNotifyType(not_null<const PeerData*> peer) {
|
|
|
|
return peer->isUser()
|
|
|
|
? DefaultNotify::User
|
|
|
|
: (peer->isChat() || peer->isMegagroup())
|
|
|
|
? DefaultNotify::Group
|
|
|
|
: DefaultNotify::Broadcast;
|
|
|
|
}
|
|
|
|
|
|
|
|
MTPInputNotifyPeer DefaultNotifyToMTP(DefaultNotify type) {
|
|
|
|
switch (type) {
|
|
|
|
case DefaultNotify::User: return MTP_inputNotifyUsers();
|
|
|
|
case DefaultNotify::Group: return MTP_inputNotifyChats();
|
|
|
|
case DefaultNotify::Broadcast: return MTP_inputNotifyBroadcasts();
|
|
|
|
}
|
|
|
|
Unexpected("Default notify type in sendNotifySettingsUpdates");
|
|
|
|
}
|
|
|
|
|
2022-04-01 10:18:07 +00:00
|
|
|
NotifySettings::NotifySettings(not_null<Session*> owner)
|
2023-08-23 11:20:41 +00:00
|
|
|
: _owner(owner)
|
|
|
|
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
|
2022-04-01 10:18:07 +00:00
|
|
|
}
|
|
|
|
|
2022-04-05 06:16:16 +00:00
|
|
|
void NotifySettings::request(not_null<PeerData*> peer) {
|
2022-10-12 20:23:14 +00:00
|
|
|
if (peer->notify().settingsUnknown()) {
|
2022-04-01 10:18:07 +00:00
|
|
|
peer->session().api().requestNotifySettings(
|
|
|
|
MTP_inputNotifyPeer(peer->input));
|
|
|
|
}
|
2022-04-06 15:23:41 +00:00
|
|
|
if (defaultSettings(peer).settingsUnknown()) {
|
2022-04-01 10:18:07 +00:00
|
|
|
peer->session().api().requestNotifySettings(peer->isUser()
|
|
|
|
? MTP_inputNotifyUsers()
|
|
|
|
: (peer->isChat() || peer->isMegagroup())
|
|
|
|
? MTP_inputNotifyChats()
|
|
|
|
: MTP_inputNotifyBroadcasts());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
void NotifySettings::request(not_null<Thread*> thread) {
|
2022-10-13 17:34:04 +00:00
|
|
|
if (const auto topic = thread->asTopic()) {
|
|
|
|
if (topic->notify().settingsUnknown()) {
|
|
|
|
topic->session().api().requestNotifySettings(
|
|
|
|
MTP_inputNotifyForumTopic(
|
|
|
|
topic->channel()->input,
|
|
|
|
MTP_int(topic->rootId())));
|
|
|
|
}
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
2022-10-13 17:34:04 +00:00
|
|
|
request(thread->peer());
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
2022-04-05 06:16:16 +00:00
|
|
|
void NotifySettings::apply(
|
2022-04-01 10:18:07 +00:00
|
|
|
const MTPNotifyPeer ¬ifyPeer,
|
|
|
|
const MTPPeerNotifySettings &settings) {
|
2022-10-13 17:34:04 +00:00
|
|
|
notifyPeer.match([&](const MTPDnotifyUsers &) {
|
|
|
|
apply(DefaultNotify::User, settings);
|
|
|
|
}, [&](const MTPDnotifyChats &) {
|
|
|
|
apply(DefaultNotify::Group, settings);
|
|
|
|
}, [&](const MTPDnotifyBroadcasts &) {
|
|
|
|
apply(DefaultNotify::Broadcast, settings);
|
|
|
|
}, [&](const MTPDnotifyPeer &data) {
|
|
|
|
apply(peerFromMTP(data.vpeer()), settings);
|
|
|
|
}, [&](const MTPDnotifyForumTopic &data) {
|
|
|
|
apply(peerFromMTP(data.vpeer()), data.vtop_msg_id().v, settings);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::apply(
|
|
|
|
const MTPInputNotifyPeer ¬ifyPeer,
|
|
|
|
const MTPPeerNotifySettings &settings) {
|
|
|
|
const auto peerFromInput = [&](const MTPInputPeer &peer) {
|
|
|
|
return peer.match([&](const MTPDinputPeerSelf &) {
|
|
|
|
return _owner->session().userPeerId();
|
|
|
|
}, [](const MTPDinputPeerUser &data) {
|
|
|
|
return peerFromUser(data.vuser_id());
|
|
|
|
}, [](const MTPDinputPeerChat &data) {
|
|
|
|
return peerFromChat(data.vchat_id());
|
|
|
|
}, [](const MTPDinputPeerChannel &data) {
|
|
|
|
return peerFromChannel(data.vchannel_id());
|
|
|
|
}, [](const MTPDinputPeerUserFromMessage &data) -> PeerId {
|
|
|
|
Unexpected("From message peer in NotifySettings::apply.");
|
|
|
|
}, [](const MTPDinputPeerChannelFromMessage &data) -> PeerId {
|
|
|
|
Unexpected("From message peer in NotifySettings::apply.");
|
|
|
|
}, [](const MTPDinputPeerEmpty &) -> PeerId {
|
|
|
|
Unexpected("Empty peer in NotifySettings::apply.");
|
|
|
|
});
|
2022-04-01 10:18:07 +00:00
|
|
|
};
|
2022-10-13 17:34:04 +00:00
|
|
|
notifyPeer.match([&](const MTPDinputNotifyUsers &) {
|
|
|
|
apply(DefaultNotify::User, settings);
|
|
|
|
}, [&](const MTPDinputNotifyChats &) {
|
|
|
|
apply(DefaultNotify::Group, settings);
|
|
|
|
}, [&](const MTPDinputNotifyBroadcasts &) {
|
|
|
|
apply(DefaultNotify::Broadcast, settings);
|
|
|
|
}, [&](const MTPDinputNotifyPeer &data) {
|
|
|
|
apply(peerFromInput(data.vpeer()), settings);
|
|
|
|
}, [&](const MTPDinputNotifyForumTopic &data) {
|
|
|
|
apply(peerFromInput(data.vpeer()), data.vtop_msg_id().v, settings);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::apply(
|
|
|
|
DefaultNotify type,
|
|
|
|
const MTPPeerNotifySettings &settings) {
|
|
|
|
if (defaultValue(type).settings.change(settings)) {
|
|
|
|
updateLocal(type);
|
|
|
|
Core::App().notifications().checkDelayed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::apply(
|
|
|
|
PeerId peerId,
|
|
|
|
const MTPPeerNotifySettings &settings) {
|
|
|
|
if (const auto peer = _owner->peerLoaded(peerId)) {
|
|
|
|
apply(peer, settings);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::apply(
|
|
|
|
not_null<PeerData*> peer,
|
|
|
|
const MTPPeerNotifySettings &settings) {
|
|
|
|
if (peer->notify().change(settings)) {
|
2023-08-23 11:20:41 +00:00
|
|
|
updateException(peer);
|
2022-10-13 17:34:04 +00:00
|
|
|
updateLocal(peer);
|
|
|
|
Core::App().notifications().checkDelayed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::apply(
|
|
|
|
PeerId peerId,
|
|
|
|
MsgId topicRootId,
|
|
|
|
const MTPPeerNotifySettings &settings) {
|
|
|
|
if (const auto peer = _owner->peerLoaded(peerId)) {
|
|
|
|
if (const auto topic = peer->forumTopicFor(topicRootId)) {
|
|
|
|
apply(topic, settings);
|
2022-04-01 10:18:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-13 17:34:04 +00:00
|
|
|
void NotifySettings::apply(
|
2023-08-23 11:20:41 +00:00
|
|
|
not_null<ForumTopic*> topic,
|
2022-10-13 17:34:04 +00:00
|
|
|
const MTPPeerNotifySettings &settings) {
|
|
|
|
if (topic->notify().change(settings)) {
|
|
|
|
updateLocal(topic);
|
|
|
|
Core::App().notifications().checkDelayed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::update(
|
2023-08-23 11:20:41 +00:00
|
|
|
not_null<Thread*> thread,
|
|
|
|
MuteValue muteForSeconds,
|
2022-10-13 17:34:04 +00:00
|
|
|
std::optional<bool> silentPosts,
|
2023-06-09 15:31:51 +00:00
|
|
|
std::optional<NotifySound> sound,
|
|
|
|
std::optional<bool> storiesMuted) {
|
|
|
|
if (thread->notify().change(
|
|
|
|
muteForSeconds,
|
|
|
|
silentPosts,
|
|
|
|
sound,
|
|
|
|
storiesMuted)) {
|
2023-08-23 11:20:41 +00:00
|
|
|
if (const auto history = thread->asHistory()) {
|
|
|
|
updateException(history->peer);
|
|
|
|
}
|
2022-10-13 17:34:04 +00:00
|
|
|
updateLocal(thread);
|
|
|
|
thread->session().api().updateNotifySettingsDelayed(thread);
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
void NotifySettings::resetToDefault(not_null<Thread*> thread) {
|
|
|
|
// Duplicated in clearExceptions(type) and resetToDefault(peer).
|
|
|
|
if (thread->notify().resetToDefault()) {
|
|
|
|
if (const auto history = thread->asHistory()) {
|
|
|
|
updateException(history->peer);
|
|
|
|
}
|
2022-10-13 17:34:04 +00:00
|
|
|
updateLocal(thread);
|
|
|
|
thread->session().api().updateNotifySettingsDelayed(thread);
|
2023-08-23 11:20:41 +00:00
|
|
|
Core::App().notifications().checkDelayed();
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 06:16:16 +00:00
|
|
|
void NotifySettings::update(
|
2022-04-01 10:18:07 +00:00
|
|
|
not_null<PeerData*> peer,
|
2023-08-23 11:20:41 +00:00
|
|
|
MuteValue muteForSeconds,
|
2022-04-01 10:18:07 +00:00
|
|
|
std::optional<bool> silentPosts,
|
2023-06-09 15:31:51 +00:00
|
|
|
std::optional<NotifySound> sound,
|
|
|
|
std::optional<bool> storiesMuted) {
|
|
|
|
if (peer->notify().change(
|
|
|
|
muteForSeconds,
|
|
|
|
silentPosts,
|
|
|
|
sound,
|
|
|
|
storiesMuted)) {
|
2023-08-23 11:20:41 +00:00
|
|
|
updateException(peer);
|
2022-04-05 06:16:16 +00:00
|
|
|
updateLocal(peer);
|
2022-04-01 10:18:07 +00:00
|
|
|
peer->session().api().updateNotifySettingsDelayed(peer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 06:16:16 +00:00
|
|
|
void NotifySettings::resetToDefault(not_null<PeerData*> peer) {
|
2023-08-23 11:20:41 +00:00
|
|
|
// Duplicated in clearExceptions(type) and resetToDefault(thread).
|
|
|
|
if (peer->notify().resetToDefault()) {
|
|
|
|
updateException(peer);
|
2022-04-05 06:16:16 +00:00
|
|
|
updateLocal(peer);
|
2022-04-01 10:18:07 +00:00
|
|
|
peer->session().api().updateNotifySettingsDelayed(peer);
|
2023-08-23 11:20:41 +00:00
|
|
|
Core::App().notifications().checkDelayed();
|
2022-04-01 10:18:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
void NotifySettings::forumParentMuteUpdated(not_null<Forum*> forum) {
|
|
|
|
forum->enumerateTopics([&](not_null<ForumTopic*> topic) {
|
2022-10-13 18:02:31 +00:00
|
|
|
if (!topic->notify().settingsUnknown()) {
|
|
|
|
updateLocal(topic);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-04-06 15:23:41 +00:00
|
|
|
auto NotifySettings::defaultValue(DefaultNotify type)
|
|
|
|
-> DefaultValue & {
|
|
|
|
const auto index = static_cast<int>(type);
|
|
|
|
Assert(index >= 0 && index < base::array_size(_defaultValues));
|
|
|
|
return _defaultValues[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
auto NotifySettings::defaultValue(DefaultNotify type) const
|
|
|
|
-> const DefaultValue & {
|
|
|
|
const auto index = static_cast<int>(type);
|
|
|
|
Assert(index >= 0 && index < base::array_size(_defaultValues));
|
|
|
|
return _defaultValues[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
const PeerNotifySettings &NotifySettings::defaultSettings(
|
2022-04-01 10:18:07 +00:00
|
|
|
not_null<const PeerData*> peer) const {
|
2023-08-23 11:20:41 +00:00
|
|
|
return defaultSettings(DefaultNotifyType(peer));
|
2022-04-06 15:23:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const PeerNotifySettings &NotifySettings::defaultSettings(
|
|
|
|
DefaultNotify type) const {
|
|
|
|
return defaultValue(type).settings;
|
|
|
|
}
|
|
|
|
|
2023-08-23 17:29:56 +00:00
|
|
|
bool NotifySettings::isMuted(DefaultNotify type) const {
|
|
|
|
if (const auto until = defaultSettings(type).muteUntil()) {
|
|
|
|
return MutedFromUntil(*until, nullptr);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-04-06 15:23:41 +00:00
|
|
|
void NotifySettings::defaultUpdate(
|
|
|
|
DefaultNotify type,
|
2023-08-23 11:20:41 +00:00
|
|
|
MuteValue muteForSeconds,
|
2022-04-06 15:23:41 +00:00
|
|
|
std::optional<bool> silentPosts,
|
2023-06-09 15:31:51 +00:00
|
|
|
std::optional<NotifySound> sound,
|
|
|
|
std::optional<bool> storiesMuted) {
|
2022-04-06 15:23:41 +00:00
|
|
|
auto &settings = defaultValue(type).settings;
|
2023-06-09 15:31:51 +00:00
|
|
|
if (settings.change(muteForSeconds, silentPosts, sound, storiesMuted)) {
|
2022-04-06 15:23:41 +00:00
|
|
|
updateLocal(type);
|
2022-10-12 20:23:14 +00:00
|
|
|
_owner->session().api().updateNotifySettingsDelayed(type);
|
2022-04-06 15:23:41 +00:00
|
|
|
}
|
2022-04-01 10:18:07 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
void NotifySettings::updateLocal(not_null<Thread*> thread) {
|
2022-10-13 17:34:04 +00:00
|
|
|
const auto topic = thread->asTopic();
|
|
|
|
if (!topic) {
|
|
|
|
return updateLocal(thread->peer());
|
|
|
|
}
|
2022-10-12 20:23:14 +00:00
|
|
|
auto changesIn = crl::time(0);
|
|
|
|
const auto muted = isMuted(topic, &changesIn);
|
2022-10-13 10:32:03 +00:00
|
|
|
topic->setMuted(muted);
|
2022-10-12 20:23:14 +00:00
|
|
|
if (muted) {
|
|
|
|
auto &lifetime = _mutedTopics.emplace(
|
|
|
|
topic,
|
|
|
|
rpl::lifetime()).first->second;
|
|
|
|
topic->destroyed() | rpl::start_with_next([=] {
|
|
|
|
_mutedTopics.erase(topic);
|
|
|
|
}, lifetime);
|
|
|
|
unmuteByFinishedDelayed(changesIn);
|
|
|
|
Core::App().notifications().clearIncomingFromTopic(topic);
|
|
|
|
} else {
|
|
|
|
_mutedTopics.erase(topic);
|
|
|
|
}
|
|
|
|
cacheSound(topic->notify().sound());
|
|
|
|
}
|
|
|
|
|
2022-04-05 06:16:16 +00:00
|
|
|
void NotifySettings::updateLocal(not_null<PeerData*> peer) {
|
2022-04-01 10:18:07 +00:00
|
|
|
const auto history = _owner->historyLoaded(peer->id);
|
|
|
|
auto changesIn = crl::time(0);
|
2022-04-01 10:36:33 +00:00
|
|
|
const auto muted = isMuted(peer, &changesIn);
|
2022-10-13 10:32:03 +00:00
|
|
|
const auto changeInHistory = history && (history->muted() != muted);
|
|
|
|
if (changeInHistory) {
|
|
|
|
history->setMuted(muted);
|
2022-04-01 10:18:07 +00:00
|
|
|
// Notification already sent.
|
|
|
|
} else {
|
|
|
|
peer->session().changes().peerUpdated(
|
|
|
|
peer,
|
|
|
|
PeerUpdate::Flag::Notifications);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (muted) {
|
|
|
|
_mutedPeers.emplace(peer);
|
|
|
|
unmuteByFinishedDelayed(changesIn);
|
|
|
|
if (history) {
|
|
|
|
Core::App().notifications().clearIncomingFromHistory(history);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_mutedPeers.erase(peer);
|
|
|
|
}
|
2022-10-12 20:23:14 +00:00
|
|
|
cacheSound(peer->notify().sound());
|
2022-04-05 12:26:18 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 07:34:29 +00:00
|
|
|
void NotifySettings::cacheSound(DocumentId id) {
|
|
|
|
cacheSound(_owner->document(id));
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::cacheSound(not_null<DocumentData*> document) {
|
|
|
|
if (document->isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const auto view = document->createMediaView();
|
|
|
|
_ringtones.views.emplace(document->id, view);
|
|
|
|
document->forceToCache(true);
|
2023-08-23 11:20:41 +00:00
|
|
|
document->save(FileOriginRingtones(), QString());
|
2022-04-07 07:34:29 +00:00
|
|
|
}
|
|
|
|
|
2022-05-03 12:23:39 +00:00
|
|
|
void NotifySettings::cacheSound(const std::optional<NotifySound> &sound) {
|
|
|
|
if (!sound || !sound->id) {
|
|
|
|
return;
|
|
|
|
} else if (const auto doc = _owner->document(sound->id); !doc->isNull()) {
|
|
|
|
cacheSound(doc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_ringtones.pendingIds.push_back(sound->id);
|
|
|
|
if (_ringtones.pendingLifetime) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Not requested yet.
|
|
|
|
_owner->session().api().ringtones().listUpdates(
|
|
|
|
) | rpl::start_with_next([=] {
|
|
|
|
for (const auto id : base::take(_ringtones.pendingIds)) {
|
|
|
|
cacheSound(id);
|
|
|
|
}
|
|
|
|
_ringtones.pendingLifetime.destroy();
|
|
|
|
}, _ringtones.pendingLifetime);
|
|
|
|
_owner->session().api().ringtones().requestList();
|
|
|
|
}
|
|
|
|
|
2022-04-06 15:23:41 +00:00
|
|
|
void NotifySettings::updateLocal(DefaultNotify type) {
|
|
|
|
defaultValue(type).updates.fire({});
|
|
|
|
|
|
|
|
const auto goodForUpdate = [&](
|
|
|
|
not_null<const PeerData*> peer,
|
|
|
|
const PeerNotifySettings &settings) {
|
2022-10-12 20:23:14 +00:00
|
|
|
auto &peers = peer->notify();
|
|
|
|
return !peers.settingsUnknown()
|
|
|
|
&& ((!peers.muteUntil() && settings.muteUntil())
|
|
|
|
|| (!peers.silentPosts() && settings.silentPosts())
|
|
|
|
|| (!peers.sound() && settings.sound()));
|
2022-04-06 15:23:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const auto callback = [&](not_null<PeerData*> peer) {
|
|
|
|
if (goodForUpdate(peer, defaultSettings(type))) {
|
|
|
|
updateLocal(peer);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
switch (type) {
|
|
|
|
case DefaultNotify::User: _owner->enumerateUsers(callback); break;
|
|
|
|
case DefaultNotify::Group: _owner->enumerateGroups(callback); break;
|
|
|
|
case DefaultNotify::Broadcast:
|
|
|
|
_owner->enumerateBroadcasts(callback);
|
|
|
|
break;
|
|
|
|
}
|
2022-05-03 12:23:39 +00:00
|
|
|
cacheSound(defaultValue(type).settings.sound());
|
2022-04-06 15:23:41 +00:00
|
|
|
}
|
|
|
|
|
2022-04-05 12:26:18 +00:00
|
|
|
std::shared_ptr<DocumentMedia> NotifySettings::lookupRingtone(
|
|
|
|
DocumentId id) const {
|
|
|
|
if (!id) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
const auto it = _ringtones.views.find(id);
|
|
|
|
return (it == end(_ringtones.views)) ? nullptr : it->second;
|
2022-04-01 10:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::unmuteByFinishedDelayed(crl::time delay) {
|
|
|
|
accumulate_min(delay, kMaxNotifyCheckDelay);
|
|
|
|
if (!_unmuteByFinishedTimer.isActive()
|
|
|
|
|| _unmuteByFinishedTimer.remainingTime() > delay) {
|
|
|
|
_unmuteByFinishedTimer.callOnce(delay);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::unmuteByFinished() {
|
|
|
|
auto changesInMin = crl::time(0);
|
|
|
|
for (auto i = begin(_mutedPeers); i != end(_mutedPeers);) {
|
|
|
|
const auto history = _owner->historyLoaded((*i)->id);
|
|
|
|
auto changesIn = crl::time(0);
|
2022-04-01 10:36:33 +00:00
|
|
|
const auto muted = isMuted(*i, &changesIn);
|
2022-10-13 10:32:03 +00:00
|
|
|
if (history) {
|
|
|
|
history->setMuted(muted);
|
|
|
|
}
|
2022-04-01 10:18:07 +00:00
|
|
|
if (muted) {
|
|
|
|
if (!changesInMin || changesInMin > changesIn) {
|
|
|
|
changesInMin = changesIn;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
} else {
|
|
|
|
i = _mutedPeers.erase(i);
|
|
|
|
}
|
|
|
|
}
|
2022-10-12 20:23:14 +00:00
|
|
|
for (auto i = begin(_mutedTopics); i != end(_mutedTopics);) {
|
|
|
|
auto changesIn = crl::time(0);
|
|
|
|
const auto topic = i->first;
|
|
|
|
const auto muted = isMuted(topic, &changesIn);
|
2022-10-13 10:32:03 +00:00
|
|
|
topic->setMuted(muted);
|
2022-10-12 20:23:14 +00:00
|
|
|
if (muted) {
|
|
|
|
if (!changesInMin || changesInMin > changesIn) {
|
|
|
|
changesInMin = changesIn;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
} else {
|
|
|
|
i = _mutedTopics.erase(i);
|
|
|
|
}
|
|
|
|
}
|
2022-04-01 10:18:07 +00:00
|
|
|
if (changesInMin) {
|
|
|
|
unmuteByFinishedDelayed(changesInMin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-12 20:23:14 +00:00
|
|
|
bool NotifySettings::isMuted(
|
2023-08-23 11:20:41 +00:00
|
|
|
not_null<const Thread*> thread,
|
2022-10-12 20:23:14 +00:00
|
|
|
crl::time *changesIn) const {
|
2022-10-13 17:34:04 +00:00
|
|
|
const auto topic = thread->asTopic();
|
|
|
|
const auto until = topic ? topic->notify().muteUntil() : std::nullopt;
|
2022-10-12 20:23:14 +00:00
|
|
|
return until
|
|
|
|
? MutedFromUntil(*until, changesIn)
|
2022-10-13 17:34:04 +00:00
|
|
|
: isMuted(thread->peer(), changesIn);
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
bool NotifySettings::isMuted(not_null<const Thread*> thread) const {
|
2022-10-13 17:34:04 +00:00
|
|
|
return isMuted(thread, nullptr);
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
NotifySound NotifySettings::sound(not_null<const Thread*> thread) const {
|
2022-10-13 17:34:04 +00:00
|
|
|
const auto topic = thread->asTopic();
|
|
|
|
const auto sound = topic ? topic->notify().sound() : std::nullopt;
|
|
|
|
return sound ? *sound : this->sound(thread->peer());
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
bool NotifySettings::muteUnknown(not_null<const Thread*> thread) const {
|
2022-10-13 17:34:04 +00:00
|
|
|
const auto topic = thread->asTopic();
|
|
|
|
return (topic && topic->notify().settingsUnknown())
|
|
|
|
|| ((!topic || !topic->notify().muteUntil().has_value())
|
|
|
|
&& muteUnknown(thread->peer()));
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
bool NotifySettings::soundUnknown(not_null<const Thread*> thread) const {
|
2022-10-13 17:34:04 +00:00
|
|
|
const auto topic = thread->asTopic();
|
|
|
|
return (topic && topic->notify().settingsUnknown())
|
|
|
|
|| ((!topic || !topic->notify().sound().has_value())
|
2022-10-12 20:23:14 +00:00
|
|
|
&& soundUnknown(topic->channel()));
|
|
|
|
}
|
|
|
|
|
2022-04-01 10:36:33 +00:00
|
|
|
bool NotifySettings::isMuted(
|
2022-04-01 10:18:07 +00:00
|
|
|
not_null<const PeerData*> peer,
|
|
|
|
crl::time *changesIn) const {
|
2022-10-12 20:23:14 +00:00
|
|
|
if (const auto until = peer->notify().muteUntil()) {
|
|
|
|
return MutedFromUntil(*until, changesIn);
|
|
|
|
} else if (const auto until = defaultSettings(peer).muteUntil()) {
|
|
|
|
return MutedFromUntil(*until, changesIn);
|
2022-04-01 10:18:07 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-04-01 10:36:33 +00:00
|
|
|
bool NotifySettings::isMuted(not_null<const PeerData*> peer) const {
|
|
|
|
return isMuted(peer, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NotifySettings::silentPosts(not_null<const PeerData*> peer) const {
|
2022-10-12 20:23:14 +00:00
|
|
|
if (const auto silent = peer->notify().silentPosts()) {
|
2022-04-01 10:36:33 +00:00
|
|
|
return *silent;
|
2022-10-12 20:23:14 +00:00
|
|
|
} else if (const auto silent = defaultSettings(peer).silentPosts()) {
|
2022-04-01 10:36:33 +00:00
|
|
|
return *silent;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-04-04 21:10:15 +00:00
|
|
|
NotifySound NotifySettings::sound(not_null<const PeerData*> peer) const {
|
2022-11-10 08:55:17 +00:00
|
|
|
// Explicitly ignore a notify sound for Saved Messages
|
|
|
|
// to follow the global notify sound.
|
|
|
|
if (const auto sound = peer->notify().sound(); !peer->isSelf() && sound) {
|
2022-04-04 21:10:15 +00:00
|
|
|
return *sound;
|
2022-10-12 20:23:14 +00:00
|
|
|
} else if (const auto sound = defaultSettings(peer).sound()) {
|
2022-04-04 21:10:15 +00:00
|
|
|
return *sound;
|
2022-04-01 10:36:33 +00:00
|
|
|
}
|
2022-04-04 21:10:15 +00:00
|
|
|
return {};
|
2022-04-01 10:36:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool NotifySettings::muteUnknown(not_null<const PeerData*> peer) const {
|
2022-10-12 20:23:14 +00:00
|
|
|
return peer->notify().settingsUnknown()
|
|
|
|
|| (!peer->notify().muteUntil().has_value()
|
|
|
|
&& defaultSettings(peer).settingsUnknown());
|
2022-04-01 10:36:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool NotifySettings::silentPostsUnknown(
|
|
|
|
not_null<const PeerData*> peer) const {
|
2022-10-12 20:23:14 +00:00
|
|
|
return peer->notify().settingsUnknown()
|
|
|
|
|| (!peer->notify().silentPosts().has_value()
|
|
|
|
&& defaultSettings(peer).settingsUnknown());
|
2022-04-01 10:36:33 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
bool NotifySettings::soundUnknown(not_null<const PeerData*> peer) const {
|
2022-10-12 20:23:14 +00:00
|
|
|
return peer->notify().settingsUnknown()
|
|
|
|
|| (!peer->notify().sound().has_value()
|
|
|
|
&& defaultSettings(peer).settingsUnknown());
|
2022-04-01 10:36:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool NotifySettings::settingsUnknown(not_null<const PeerData*> peer) const {
|
|
|
|
return muteUnknown(peer)
|
|
|
|
|| silentPostsUnknown(peer)
|
2022-04-04 21:10:15 +00:00
|
|
|
|| soundUnknown(peer);
|
2022-04-01 10:36:33 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
bool NotifySettings::settingsUnknown(not_null<const Thread*> thread) const {
|
2022-10-13 17:34:04 +00:00
|
|
|
const auto topic = thread->asTopic();
|
|
|
|
return muteUnknown(thread)
|
|
|
|
|| soundUnknown(thread)
|
|
|
|
|| (!topic && silentPostsUnknown(thread->peer()));
|
2022-10-12 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
2022-04-06 15:23:41 +00:00
|
|
|
rpl::producer<> NotifySettings::defaultUpdates(DefaultNotify type) const {
|
|
|
|
return defaultValue(type).updates.events();
|
2022-04-01 10:18:07 +00:00
|
|
|
}
|
|
|
|
|
2022-04-06 15:23:41 +00:00
|
|
|
rpl::producer<> NotifySettings::defaultUpdates(
|
2022-04-01 10:18:07 +00:00
|
|
|
not_null<const PeerData*> peer) const {
|
2022-04-06 15:23:41 +00:00
|
|
|
return defaultUpdates(peer->isUser()
|
|
|
|
? DefaultNotify::User
|
2022-04-01 10:18:07 +00:00
|
|
|
: (peer->isChat() || peer->isMegagroup())
|
2022-04-06 15:23:41 +00:00
|
|
|
? DefaultNotify::Group
|
|
|
|
: DefaultNotify::Broadcast);
|
2022-04-01 10:18:07 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 11:20:41 +00:00
|
|
|
void NotifySettings::loadExceptions() {
|
|
|
|
for (auto i = 0; i != kDefaultNotifyTypes; ++i) {
|
|
|
|
if (_exceptionsRequestId[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const auto type = static_cast<DefaultNotify>(i);
|
|
|
|
const auto api = &_owner->session().api();
|
|
|
|
const auto requestId = api->request(MTPaccount_GetNotifyExceptions(
|
|
|
|
MTP_flags(MTPaccount_GetNotifyExceptions::Flag::f_peer),
|
|
|
|
DefaultNotifyToMTP(type)
|
|
|
|
)).done([=](const MTPUpdates &result) {
|
|
|
|
api->applyUpdates(result);
|
|
|
|
}).send();
|
|
|
|
_exceptionsRequestId[i] = requestId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::updateException(not_null<PeerData*> peer) {
|
|
|
|
const auto type = DefaultNotifyType(peer);
|
|
|
|
const auto index = static_cast<int>(type);
|
|
|
|
const auto exception = peer->notify().muteUntil().has_value();
|
|
|
|
if (!exception) {
|
|
|
|
if (_exceptions[index].remove(peer)) {
|
|
|
|
exceptionsUpdated(type);
|
|
|
|
}
|
|
|
|
} else if (SkipAddException(peer)) {
|
|
|
|
return;
|
|
|
|
} else if (_exceptions[index].emplace(peer).second) {
|
|
|
|
exceptionsUpdated(type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::exceptionsUpdated(DefaultNotify type) {
|
|
|
|
if (!ranges::contains(_exceptionsUpdatesScheduled, true)) {
|
|
|
|
crl::on_main(&_owner->session(), [=] {
|
|
|
|
const auto scheduled = base::take(_exceptionsUpdatesScheduled);
|
|
|
|
for (auto i = 0; i != kDefaultNotifyTypes; ++i) {
|
|
|
|
if (scheduled[i]) {
|
|
|
|
_exceptionsUpdates.fire(static_cast<DefaultNotify>(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
_exceptionsUpdatesScheduled[static_cast<int>(type)] = true;
|
|
|
|
_exceptionsUpdatesRealtime.fire_copy(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl::producer<DefaultNotify> NotifySettings::exceptionsUpdates() const {
|
|
|
|
return _exceptionsUpdates.events();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto NotifySettings::exceptionsUpdatesRealtime() const
|
|
|
|
-> rpl::producer<DefaultNotify> {
|
|
|
|
return _exceptionsUpdatesRealtime.events();
|
|
|
|
}
|
|
|
|
|
|
|
|
const base::flat_set<not_null<PeerData*>> &NotifySettings::exceptions(
|
|
|
|
DefaultNotify type) const {
|
|
|
|
const auto index = static_cast<int>(type);
|
|
|
|
Assert(index >= 0 && index < kDefaultNotifyTypes);
|
|
|
|
|
|
|
|
return _exceptions[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifySettings::clearExceptions(DefaultNotify type) {
|
|
|
|
const auto index = static_cast<int>(type);
|
|
|
|
const auto list = base::take(_exceptions[index]);
|
|
|
|
if (list.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (const auto &peer : list) {
|
|
|
|
// Duplicated in resetToDefault(peer / thread).
|
|
|
|
if (peer->notify().resetToDefault()) {
|
|
|
|
updateLocal(peer);
|
|
|
|
peer->session().api().updateNotifySettingsDelayed(peer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Core::App().notifications().checkDelayed();
|
|
|
|
exceptionsUpdated(type);
|
|
|
|
}
|
|
|
|
|
2022-04-01 10:18:07 +00:00
|
|
|
} // namespace Data
|