mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Manage notifications exceptions in Settings.
This commit is contained in:
parent
518f0e22cd
commit
b80f5f9706
14 changed files with 646 additions and 118 deletions
|
@ -498,6 +498,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_notification_title_channels" = "Notifications for channels";
|
||||
"lng_notification_about_channels#one" = "Please note that **{count} channel** is listed as an exception and won't be affected by this change.";
|
||||
"lng_notification_about_channels#other" = "Please note that **{count} channels** are listed as exceptions and won't be affected by this change.";
|
||||
"lng_notification_exceptions_view" = "View exceptions";
|
||||
"lng_notification_enable" = "Enable notifications";
|
||||
"lng_notification_sound" = "Sound";
|
||||
"lng_notification_tone" = "Notification tone";
|
||||
|
@ -505,6 +506,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_notification_exceptions_unmuted" = "Unmuted";
|
||||
"lng_notification_exceptions_add" = "Add an exception";
|
||||
"lng_notification_exceptions_clear" = "Delete all exceptions";
|
||||
"lng_notification_exceptions_clear_sure" = "Are you sure you want to delete all exceptions?";
|
||||
"lng_notification_exceptions_clear_button" = "Delete";
|
||||
"lng_notification_exceptions_remove" = "Remove";
|
||||
"lng_notification_context_remove" = "Remove exception";
|
||||
|
||||
"lng_reaction_text" = "{reaction} to your «{text}»";
|
||||
"lng_reaction_notext" = "{reaction} to your message";
|
||||
|
|
|
@ -1887,17 +1887,8 @@ void ApiWrap::sendNotifySettingsUpdates() {
|
|||
}
|
||||
const auto &settings = session().data().notifySettings();
|
||||
for (const auto type : base::take(_updateNotifyDefaults)) {
|
||||
const auto input = [&] {
|
||||
switch (type) {
|
||||
case Data::DefaultNotify::User: return MTP_inputNotifyUsers();
|
||||
case Data::DefaultNotify::Group: return MTP_inputNotifyChats();
|
||||
case Data::DefaultNotify::Broadcast:
|
||||
return MTP_inputNotifyBroadcasts();
|
||||
}
|
||||
Unexpected("Default notify type in sendNotifySettingsUpdates");
|
||||
}();
|
||||
request(MTPaccount_UpdateNotifySettings(
|
||||
input,
|
||||
Data::DefaultNotifyToMTP(type),
|
||||
settings.defaultSettings(type).serialize()
|
||||
)).afterDelay(kSmallDelayMs).send();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "boxes/peer_list_box.h"
|
||||
|
||||
#include "history/history.h" // chatListNameSortKey.
|
||||
#include "main/session/session_show.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwidget.h"
|
||||
|
@ -396,6 +397,27 @@ void PeerListController::setSearchNoResultsText(const QString &text) {
|
|||
}
|
||||
}
|
||||
|
||||
void PeerListController::sortByName() {
|
||||
auto keys = base::flat_map<PeerListRowId, QString>();
|
||||
keys.reserve(delegate()->peerListFullRowsCount());
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto id = row.id();
|
||||
const auto i = keys.find(id);
|
||||
if (i != end(keys)) {
|
||||
return i->second;
|
||||
}
|
||||
const auto peer = row.peer();
|
||||
const auto history = peer->owner().history(peer);
|
||||
return keys.emplace(
|
||||
id,
|
||||
history->chatListNameSortKey()).first->second;
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return (key(a).compare(key(b)) < 0);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> PeerListController::rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) {
|
||||
|
|
|
@ -560,6 +560,8 @@ protected:
|
|||
delegate()->peerListSetSearchNoResults(std::move(noResults));
|
||||
}
|
||||
|
||||
void sortByName();
|
||||
|
||||
private:
|
||||
PeerListDelegate *_delegate = nullptr;
|
||||
std::unique_ptr<PeerListSearchController> _searchController = nullptr;
|
||||
|
|
|
@ -594,25 +594,6 @@ void ContactsBoxController::sort() {
|
|||
}
|
||||
}
|
||||
|
||||
void ContactsBoxController::sortByName() {
|
||||
auto keys = base::flat_map<PeerListRowId, QString>();
|
||||
keys.reserve(delegate()->peerListFullRowsCount());
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto id = row.id();
|
||||
const auto i = keys.find(id);
|
||||
if (i != end(keys)) {
|
||||
return i->second;
|
||||
}
|
||||
const auto peer = row.peer();
|
||||
const auto history = peer->owner().history(peer);
|
||||
return keys.emplace(id, history->chatListNameSortKey()).first->second;
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return (key(a).compare(key(b)) < 0);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
void ContactsBoxController::sortByOnline() {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
|
|
|
@ -192,7 +192,6 @@ protected:
|
|||
|
||||
private:
|
||||
void sort();
|
||||
void sortByName();
|
||||
void sortByOnline();
|
||||
void rebuildRows();
|
||||
void checkForEmptyRows();
|
||||
|
|
|
@ -42,11 +42,39 @@ constexpr auto kMaxNotifyCheckDelay = 24 * 3600 * crl::time(1000);
|
|||
return (result > 0);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool SkipAddException(not_null<PeerData*> peer) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
return user->isInaccessible();
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
return chat->isDeactivated() || chat->isForbidden();
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
return channel->isForbidden();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
NotifySettings::NotifySettings(not_null<Session*> owner)
|
||||
: _owner(owner)
|
||||
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
|
||||
: _owner(owner)
|
||||
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
|
||||
}
|
||||
|
||||
void NotifySettings::request(not_null<PeerData*> peer) {
|
||||
|
@ -63,7 +91,7 @@ void NotifySettings::request(not_null<PeerData*> peer) {
|
|||
}
|
||||
}
|
||||
|
||||
void NotifySettings::request(not_null<Data::Thread*> thread) {
|
||||
void NotifySettings::request(not_null<Thread*> thread) {
|
||||
if (const auto topic = thread->asTopic()) {
|
||||
if (topic->notify().settingsUnknown()) {
|
||||
topic->session().api().requestNotifySettings(
|
||||
|
@ -145,6 +173,7 @@ void NotifySettings::apply(
|
|||
not_null<PeerData*> peer,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (peer->notify().change(settings)) {
|
||||
updateException(peer);
|
||||
updateLocal(peer);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
|
@ -162,7 +191,7 @@ void NotifySettings::apply(
|
|||
}
|
||||
|
||||
void NotifySettings::apply(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
not_null<ForumTopic*> topic,
|
||||
const MTPPeerNotifySettings &settings) {
|
||||
if (topic->notify().change(settings)) {
|
||||
updateLocal(topic);
|
||||
|
@ -171,8 +200,8 @@ void NotifySettings::apply(
|
|||
}
|
||||
|
||||
void NotifySettings::update(
|
||||
not_null<Data::Thread*> thread,
|
||||
Data::MuteValue muteForSeconds,
|
||||
not_null<Thread*> thread,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound,
|
||||
std::optional<bool> storiesMuted) {
|
||||
|
@ -181,34 +210,29 @@ void NotifySettings::update(
|
|||
silentPosts,
|
||||
sound,
|
||||
storiesMuted)) {
|
||||
if (const auto history = thread->asHistory()) {
|
||||
updateException(history->peer);
|
||||
}
|
||||
updateLocal(thread);
|
||||
thread->session().api().updateNotifySettingsDelayed(thread);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::resetToDefault(not_null<Data::Thread*> thread) {
|
||||
const auto empty = MTP_peerNotifySettings(
|
||||
MTP_flags(0),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPint(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound());
|
||||
if (thread->notify().change(empty)) {
|
||||
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);
|
||||
}
|
||||
updateLocal(thread);
|
||||
thread->session().api().updateNotifySettingsDelayed(thread);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::update(
|
||||
not_null<PeerData*> peer,
|
||||
Data::MuteValue muteForSeconds,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound,
|
||||
std::optional<bool> storiesMuted) {
|
||||
|
@ -217,33 +241,24 @@ void NotifySettings::update(
|
|||
silentPosts,
|
||||
sound,
|
||||
storiesMuted)) {
|
||||
updateException(peer);
|
||||
updateLocal(peer);
|
||||
peer->session().api().updateNotifySettingsDelayed(peer);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::resetToDefault(not_null<PeerData*> peer) {
|
||||
const auto empty = MTP_peerNotifySettings(
|
||||
MTP_flags(0),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPint(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPBool(),
|
||||
MTPBool(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound(),
|
||||
MTPNotificationSound());
|
||||
if (peer->notify().change(empty)) {
|
||||
// Duplicated in clearExceptions(type) and resetToDefault(thread).
|
||||
if (peer->notify().resetToDefault()) {
|
||||
updateException(peer);
|
||||
updateLocal(peer);
|
||||
peer->session().api().updateNotifySettingsDelayed(peer);
|
||||
Core::App().notifications().checkDelayed();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifySettings::forumParentMuteUpdated(not_null<Data::Forum*> forum) {
|
||||
forum->enumerateTopics([&](not_null<Data::ForumTopic*> topic) {
|
||||
void NotifySettings::forumParentMuteUpdated(not_null<Forum*> forum) {
|
||||
forum->enumerateTopics([&](not_null<ForumTopic*> topic) {
|
||||
if (!topic->notify().settingsUnknown()) {
|
||||
updateLocal(topic);
|
||||
}
|
||||
|
@ -266,11 +281,7 @@ auto NotifySettings::defaultValue(DefaultNotify type) const
|
|||
|
||||
const PeerNotifySettings &NotifySettings::defaultSettings(
|
||||
not_null<const PeerData*> peer) const {
|
||||
return defaultSettings(peer->isUser()
|
||||
? DefaultNotify::User
|
||||
: (peer->isChat() || peer->isMegagroup())
|
||||
? DefaultNotify::Group
|
||||
: DefaultNotify::Broadcast);
|
||||
return defaultSettings(DefaultNotifyType(peer));
|
||||
}
|
||||
|
||||
const PeerNotifySettings &NotifySettings::defaultSettings(
|
||||
|
@ -280,7 +291,7 @@ const PeerNotifySettings &NotifySettings::defaultSettings(
|
|||
|
||||
void NotifySettings::defaultUpdate(
|
||||
DefaultNotify type,
|
||||
Data::MuteValue muteForSeconds,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound,
|
||||
std::optional<bool> storiesMuted) {
|
||||
|
@ -291,7 +302,7 @@ void NotifySettings::defaultUpdate(
|
|||
}
|
||||
}
|
||||
|
||||
void NotifySettings::updateLocal(not_null<Data::Thread*> thread) {
|
||||
void NotifySettings::updateLocal(not_null<Thread*> thread) {
|
||||
const auto topic = thread->asTopic();
|
||||
if (!topic) {
|
||||
return updateLocal(thread->peer());
|
||||
|
@ -351,7 +362,7 @@ void NotifySettings::cacheSound(not_null<DocumentData*> document) {
|
|||
const auto view = document->createMediaView();
|
||||
_ringtones.views.emplace(document->id, view);
|
||||
document->forceToCache(true);
|
||||
document->save(Data::FileOriginRingtones(), QString());
|
||||
document->save(FileOriginRingtones(), QString());
|
||||
}
|
||||
|
||||
void NotifySettings::cacheSound(const std::optional<NotifySound> &sound) {
|
||||
|
@ -459,7 +470,7 @@ void NotifySettings::unmuteByFinished() {
|
|||
}
|
||||
|
||||
bool NotifySettings::isMuted(
|
||||
not_null<const Data::Thread*> thread,
|
||||
not_null<const Thread*> thread,
|
||||
crl::time *changesIn) const {
|
||||
const auto topic = thread->asTopic();
|
||||
const auto until = topic ? topic->notify().muteUntil() : std::nullopt;
|
||||
|
@ -468,27 +479,24 @@ bool NotifySettings::isMuted(
|
|||
: isMuted(thread->peer(), changesIn);
|
||||
}
|
||||
|
||||
bool NotifySettings::isMuted(not_null<const Data::Thread*> thread) const {
|
||||
bool NotifySettings::isMuted(not_null<const Thread*> thread) const {
|
||||
return isMuted(thread, nullptr);
|
||||
}
|
||||
|
||||
NotifySound NotifySettings::sound(
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
NotifySound NotifySettings::sound(not_null<const Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
const auto sound = topic ? topic->notify().sound() : std::nullopt;
|
||||
return sound ? *sound : this->sound(thread->peer());
|
||||
}
|
||||
|
||||
bool NotifySettings::muteUnknown(
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
bool NotifySettings::muteUnknown(not_null<const Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return (topic && topic->notify().settingsUnknown())
|
||||
|| ((!topic || !topic->notify().muteUntil().has_value())
|
||||
&& muteUnknown(thread->peer()));
|
||||
}
|
||||
|
||||
bool NotifySettings::soundUnknown(
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
bool NotifySettings::soundUnknown(not_null<const Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return (topic && topic->notify().settingsUnknown())
|
||||
|| ((!topic || !topic->notify().sound().has_value())
|
||||
|
@ -543,8 +551,7 @@ bool NotifySettings::silentPostsUnknown(
|
|||
&& defaultSettings(peer).settingsUnknown());
|
||||
}
|
||||
|
||||
bool NotifySettings::soundUnknown(
|
||||
not_null<const PeerData*> peer) const {
|
||||
bool NotifySettings::soundUnknown(not_null<const PeerData*> peer) const {
|
||||
return peer->notify().settingsUnknown()
|
||||
|| (!peer->notify().sound().has_value()
|
||||
&& defaultSettings(peer).settingsUnknown());
|
||||
|
@ -556,8 +563,7 @@ bool NotifySettings::settingsUnknown(not_null<const PeerData*> peer) const {
|
|||
|| soundUnknown(peer);
|
||||
}
|
||||
|
||||
bool NotifySettings::settingsUnknown(
|
||||
not_null<const Data::Thread*> thread) const {
|
||||
bool NotifySettings::settingsUnknown(not_null<const Thread*> thread) const {
|
||||
const auto topic = thread->asTopic();
|
||||
return muteUnknown(thread)
|
||||
|| soundUnknown(thread)
|
||||
|
@ -577,4 +583,85 @@ rpl::producer<> NotifySettings::defaultUpdates(
|
|||
: DefaultNotify::Broadcast);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -26,13 +26,17 @@ enum class DefaultNotify {
|
|||
Group,
|
||||
Broadcast,
|
||||
};
|
||||
[[nodiscard]] DefaultNotify DefaultNotifyType(
|
||||
not_null<const PeerData*> peer);
|
||||
|
||||
[[nodiscard]] MTPInputNotifyPeer DefaultNotifyToMTP(DefaultNotify type);
|
||||
|
||||
class NotifySettings final {
|
||||
public:
|
||||
NotifySettings(not_null<Session*> owner);
|
||||
|
||||
void request(not_null<PeerData*> peer);
|
||||
void request(not_null<Data::Thread*> thread);
|
||||
void request(not_null<Thread*> thread);
|
||||
|
||||
void apply(
|
||||
const MTPNotifyPeer ¬ifyPeer,
|
||||
|
@ -50,25 +54,25 @@ public:
|
|||
MsgId topicRootId,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
void apply(
|
||||
not_null<Data::ForumTopic*> topic,
|
||||
not_null<ForumTopic*> topic,
|
||||
const MTPPeerNotifySettings &settings);
|
||||
|
||||
void update(
|
||||
not_null<Data::Thread*> thread,
|
||||
Data::MuteValue muteForSeconds,
|
||||
not_null<Thread*> thread,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt,
|
||||
std::optional<bool> storiesMuted = std::nullopt);
|
||||
void resetToDefault(not_null<Data::Thread*> thread);
|
||||
void resetToDefault(not_null<Thread*> thread);
|
||||
void update(
|
||||
not_null<PeerData*> peer,
|
||||
Data::MuteValue muteForSeconds,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt,
|
||||
std::optional<bool> storiesMuted = std::nullopt);
|
||||
void resetToDefault(not_null<PeerData*> peer);
|
||||
|
||||
void forumParentMuteUpdated(not_null<Data::Forum*> forum);
|
||||
void forumParentMuteUpdated(not_null<Forum*> forum);
|
||||
|
||||
void cacheSound(DocumentId id);
|
||||
void cacheSound(not_null<DocumentData*> document);
|
||||
|
@ -84,18 +88,15 @@ public:
|
|||
|
||||
void defaultUpdate(
|
||||
DefaultNotify type,
|
||||
Data::MuteValue muteForSeconds,
|
||||
MuteValue muteForSeconds,
|
||||
std::optional<bool> silentPosts = std::nullopt,
|
||||
std::optional<NotifySound> sound = std::nullopt,
|
||||
std::optional<bool> storiesMuted = std::nullopt);
|
||||
|
||||
[[nodiscard]] bool isMuted(not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] NotifySound sound(
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] bool muteUnknown(
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] bool soundUnknown(
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
[[nodiscard]] bool isMuted(not_null<const Thread*> thread) const;
|
||||
[[nodiscard]] NotifySound sound(not_null<const Thread*> thread) const;
|
||||
[[nodiscard]] bool muteUnknown(not_null<const Thread*> thread) const;
|
||||
[[nodiscard]] bool soundUnknown(not_null<const Thread*> thread) const;
|
||||
|
||||
[[nodiscard]] bool isMuted(not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool silentPosts(not_null<const PeerData*> peer) const;
|
||||
|
@ -105,7 +106,17 @@ public:
|
|||
not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool soundUnknown(not_null<const PeerData*> peer) const;
|
||||
|
||||
void loadExceptions();
|
||||
[[nodiscard]] rpl::producer<DefaultNotify> exceptionsUpdates() const;
|
||||
[[nodiscard]] auto exceptionsUpdatesRealtime() const
|
||||
-> rpl::producer<DefaultNotify>;
|
||||
[[nodiscard]] const base::flat_set<not_null<PeerData*>> &exceptions(
|
||||
DefaultNotify type) const;
|
||||
void clearExceptions(DefaultNotify type);
|
||||
|
||||
private:
|
||||
static constexpr auto kDefaultNotifyTypes = 3;
|
||||
|
||||
struct DefaultValue {
|
||||
PeerNotifySettings settings;
|
||||
rpl::event_stream<> updates;
|
||||
|
@ -114,7 +125,7 @@ private:
|
|||
void cacheSound(const std::optional<NotifySound> &sound);
|
||||
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const Data::Thread*> thread,
|
||||
not_null<const Thread*> thread,
|
||||
crl::time *changesIn) const;
|
||||
[[nodiscard]] bool isMuted(
|
||||
not_null<const PeerData*> peer,
|
||||
|
@ -126,21 +137,22 @@ private:
|
|||
not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool settingsUnknown(not_null<const PeerData*> peer) const;
|
||||
[[nodiscard]] bool settingsUnknown(
|
||||
not_null<const Data::Thread*> thread) const;
|
||||
not_null<const Thread*> thread) const;
|
||||
|
||||
void unmuteByFinished();
|
||||
void unmuteByFinishedDelayed(crl::time delay);
|
||||
void updateLocal(not_null<Data::Thread*> thread);
|
||||
void updateLocal(not_null<Thread*> thread);
|
||||
void updateLocal(not_null<PeerData*> peer);
|
||||
void updateLocal(DefaultNotify type);
|
||||
|
||||
void updateException(not_null<PeerData*> peer);
|
||||
void exceptionsUpdated(DefaultNotify type);
|
||||
|
||||
const not_null<Session*> _owner;
|
||||
|
||||
DefaultValue _defaultValues[3];
|
||||
std::unordered_set<not_null<const PeerData*>> _mutedPeers;
|
||||
std::unordered_map<
|
||||
not_null<Data::ForumTopic*>,
|
||||
rpl::lifetime> _mutedTopics;
|
||||
std::unordered_map<not_null<ForumTopic*>, rpl::lifetime> _mutedTopics;
|
||||
base::Timer _unmuteByFinishedTimer;
|
||||
|
||||
struct {
|
||||
|
@ -151,6 +163,14 @@ private:
|
|||
rpl::lifetime pendingLifetime;
|
||||
} _ringtones;
|
||||
|
||||
rpl::event_stream<DefaultNotify> _exceptionsUpdates;
|
||||
rpl::event_stream<DefaultNotify> _exceptionsUpdatesRealtime;
|
||||
std::array<
|
||||
base::flat_set<not_null<PeerData*>>,
|
||||
kDefaultNotifyTypes> _exceptions;
|
||||
std::array<mtpRequestId, kDefaultNotifyTypes> _exceptionsRequestId = {};
|
||||
std::array<bool, kDefaultNotifyTypes> _exceptionsUpdatesScheduled = {};
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -256,6 +256,15 @@ bool PeerNotifySettings::change(
|
|||
SerializeSound(std::nullopt))); // stories_sound
|
||||
}
|
||||
|
||||
bool PeerNotifySettings::resetToDefault() {
|
||||
if (_known && !_value) {
|
||||
return false;
|
||||
}
|
||||
_known = true;
|
||||
_value = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<TimeId> PeerNotifySettings::muteUntil() const {
|
||||
return _value
|
||||
? _value->muteUntil()
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
std::optional<bool> silentPosts,
|
||||
std::optional<NotifySound> sound,
|
||||
std::optional<bool> storiesMuted);
|
||||
bool resetToDefault();
|
||||
|
||||
bool settingsUnknown() const;
|
||||
std::optional<TimeId> muteUntil() const;
|
||||
|
|
|
@ -80,7 +80,7 @@ QPointer<Ui::RpWidget> Blocked::createPinnedToTop(not_null<QWidget*> parent) {
|
|||
content,
|
||||
tr::lng_blocked_list_add(),
|
||||
st::settingsButtonActive,
|
||||
{ &st::menuIconBlockSettings, IconType::Round, &st::transparent }
|
||||
{ &st::menuIconBlockSettings }
|
||||
)->addClickHandler([=] {
|
||||
BlockedBoxController::BlockNewPeer(_controller);
|
||||
});
|
||||
|
|
|
@ -172,10 +172,30 @@ void AddTypeButton(
|
|||
showOther(NotificationsTypeId(type));
|
||||
});
|
||||
|
||||
const auto session = &controller->session();
|
||||
const auto settings = &session->data().notifySettings();
|
||||
const auto &st = st::settingsNotificationType;
|
||||
auto status = rpl::combine(
|
||||
NotificationsEnabledForTypeValue(session, type),
|
||||
rpl::single(
|
||||
type
|
||||
) | rpl::then(settings->exceptionsUpdates(
|
||||
) | rpl::filter(rpl::mappers::_1 == type))
|
||||
) | rpl::map([=](bool enabled, const auto &) {
|
||||
const auto count = int(settings->exceptions(type).size());
|
||||
return !count
|
||||
? tr::lng_notification_click_to_change()
|
||||
: (enabled
|
||||
? tr::lng_notification_on
|
||||
: tr::lng_notification_off)(
|
||||
lt_exceptions,
|
||||
tr::lng_notification_exceptions(
|
||||
lt_count,
|
||||
rpl::single(float64(count))));
|
||||
}) | rpl::flatten_latest();
|
||||
const auto details = Ui::CreateChild<Ui::FlatLabel>(
|
||||
button.get(),
|
||||
tr::lng_notification_click_to_change(),
|
||||
std::move(status),
|
||||
st::settingsNotificationTypeDetails);
|
||||
details->show();
|
||||
details->moveToLeft(
|
||||
|
@ -183,12 +203,11 @@ void AddTypeButton(
|
|||
st.padding.top() + st.height - details->height());
|
||||
details->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
const auto session = &controller->session();
|
||||
const auto toggleButton = Ui::CreateChild<Ui::SettingsButton>(
|
||||
container.get(),
|
||||
nullptr,
|
||||
st);
|
||||
const auto checkView = toggleButton->lifetime().make_state<Ui::ToggleView>(
|
||||
const auto checkView = button->lifetime().make_state<Ui::ToggleView>(
|
||||
st.toggle,
|
||||
NotificationsEnabledForType(session, type),
|
||||
[=] { toggleButton->update(); });
|
||||
|
@ -971,6 +990,8 @@ void SetupNotificationsContent(
|
|||
previewWrap->toggle(settings.desktopNotify(), anim::type::instant);
|
||||
previewDivider->toggle(!settings.desktopNotify(), anim::type::instant);
|
||||
|
||||
controller->session().data().notifySettings().loadExceptions();
|
||||
|
||||
AddSkip(container, st::notifyPreviewBottomSkip);
|
||||
AddSubsectionTitle(container, tr::lng_settings_notify_title());
|
||||
const auto addType = [&](Data::DefaultNotify type) {
|
||||
|
|
|
@ -11,14 +11,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "apiwrap.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/ringtones_box.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "menu/menu_mute.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
|
@ -27,6 +36,321 @@ namespace {
|
|||
|
||||
using Notify = Data::DefaultNotify;
|
||||
|
||||
class AddExceptionBoxController final
|
||||
: public ChatsListBoxController
|
||||
, public base::has_weak_ptr {
|
||||
public:
|
||||
AddExceptionBoxController(
|
||||
not_null<Main::Session*> session,
|
||||
Notify type,
|
||||
Fn<void(not_null<PeerData*>)> done);
|
||||
|
||||
Main::Session &session() const override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) override;
|
||||
|
||||
private:
|
||||
void prepareViewHook() override;
|
||||
std::unique_ptr<Row> createRow(not_null<History*> history) override;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
const Notify _type;
|
||||
const Fn<void(not_null<PeerData*>)> _done;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
PeerData *_lastClickedPeer = nullptr;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
class ExceptionsController final : public PeerListController {
|
||||
public:
|
||||
ExceptionsController(
|
||||
not_null<Window::SessionController*> window,
|
||||
Notify type);
|
||||
|
||||
Main::Session &session() const override;
|
||||
void prepare() override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) override;
|
||||
void rowRightActionClicked(not_null<PeerListRow*> row) override;
|
||||
void loadMoreRows() override;
|
||||
|
||||
void bringToTop(not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] rpl::producer<int> countValue() const;
|
||||
|
||||
private:
|
||||
void refreshRows();
|
||||
bool appendRow(not_null<PeerData*> peer);
|
||||
std::unique_ptr<PeerListRow> createRow(not_null<PeerData*> peer) const;
|
||||
void refreshStatus(not_null<PeerListRow*> row) const;
|
||||
|
||||
void sort();
|
||||
|
||||
const not_null<Window::SessionController*> _window;
|
||||
const Notify _type;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
|
||||
base::flat_map<not_null<PeerData*>, int> _topOrdered;
|
||||
int _topOrder = 0;
|
||||
|
||||
rpl::variable<int> _count;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
AddExceptionBoxController::AddExceptionBoxController(
|
||||
not_null<Main::Session*> session,
|
||||
Notify type,
|
||||
Fn<void(not_null<PeerData*>)> done)
|
||||
: ChatsListBoxController(session)
|
||||
, _session(session)
|
||||
, _type(type)
|
||||
, _done(std::move(done)) {
|
||||
}
|
||||
|
||||
Main::Session &AddExceptionBoxController::session() const {
|
||||
return *_session;
|
||||
}
|
||||
|
||||
void AddExceptionBoxController::prepareViewHook() {
|
||||
delegate()->peerListSetTitle(tr::lng_notification_exceptions_add());
|
||||
|
||||
_session->changes().peerUpdates(
|
||||
Data::PeerUpdate::Flag::Notifications
|
||||
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
||||
return update.peer == _lastClickedPeer;
|
||||
}) | rpl::start_with_next([=] {
|
||||
if (const auto onstack = _done) {
|
||||
onstack(_lastClickedPeer);
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void AddExceptionBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
delegate()->peerListShowRowMenu(row, true);
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> AddExceptionBoxController::rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) {
|
||||
const auto peer = row->peer();
|
||||
auto result = base::make_unique_q<Ui::PopupMenu>(
|
||||
parent,
|
||||
st::popupMenuWithIcons);
|
||||
|
||||
MuteMenu::FillMuteMenu(
|
||||
result.get(),
|
||||
peer->owner().history(peer),
|
||||
delegate()->peerListUiShow());
|
||||
|
||||
// First clear _menu value, so that we don't check row positions yet.
|
||||
base::take(_menu);
|
||||
|
||||
// Here unique_qptr is used like a shared pointer, where
|
||||
// not the last destroyed pointer destroys the object, but the first.
|
||||
_menu = base::unique_qptr<Ui::PopupMenu>(result.get());
|
||||
_menu->setDestroyedCallback(crl::guard(this, [=] {
|
||||
_lastClickedPeer = nullptr;
|
||||
}));
|
||||
_lastClickedPeer = peer;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto AddExceptionBoxController::createRow(not_null<History*> history)
|
||||
-> std::unique_ptr<AddExceptionBoxController::Row> {
|
||||
if (Data::DefaultNotifyType(history->peer) != _type
|
||||
|| history->peer->isSelf()
|
||||
|| history->peer->isRepliesChat()) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<Row>(history);
|
||||
}
|
||||
|
||||
ExceptionsController::ExceptionsController(
|
||||
not_null<Window::SessionController*> window,
|
||||
Notify type)
|
||||
: _window(window)
|
||||
, _type(type) {
|
||||
}
|
||||
|
||||
Main::Session &ExceptionsController::session() const {
|
||||
return _window->session();
|
||||
}
|
||||
|
||||
void ExceptionsController::prepare() {
|
||||
refreshRows();
|
||||
|
||||
session().data().notifySettings().exceptionsUpdates(
|
||||
) | rpl::filter(rpl::mappers::_1 == _type) | rpl::start_with_next([=] {
|
||||
refreshRows();
|
||||
}, lifetime());
|
||||
|
||||
session().changes().peerUpdates(
|
||||
Data::PeerUpdate::Flag::Notifications
|
||||
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
||||
const auto peer = update.peer;
|
||||
if (const auto row = delegate()->peerListFindRow(peer->id.value)) {
|
||||
if (peer->notify().muteUntil().has_value()) {
|
||||
refreshStatus(row);
|
||||
} else {
|
||||
delegate()->peerListRemoveRow(row);
|
||||
delegate()->peerListRefreshRows();
|
||||
_count = delegate()->peerListFullRowsCount();
|
||||
}
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void ExceptionsController::loadMoreRows() {
|
||||
}
|
||||
|
||||
void ExceptionsController::bringToTop(not_null<PeerData*> peer) {
|
||||
_topOrdered[peer] = ++_topOrder;
|
||||
if (delegate()->peerListFindRow(peer->id.value)) {
|
||||
sort();
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<int> ExceptionsController::countValue() const {
|
||||
return _count.value();
|
||||
}
|
||||
|
||||
void ExceptionsController::rowClicked(not_null<PeerListRow*> row) {
|
||||
delegate()->peerListShowRowMenu(row, true);
|
||||
}
|
||||
|
||||
void ExceptionsController::rowRightActionClicked(
|
||||
not_null<PeerListRow*> row) {
|
||||
session().data().notifySettings().resetToDefault(row->peer());
|
||||
}
|
||||
|
||||
void ExceptionsController::refreshRows() {
|
||||
auto seen = base::flat_set<not_null<PeerData*>>();
|
||||
const auto &list = session().data().notifySettings().exceptions(_type);
|
||||
auto removed = false, added = false;
|
||||
auto already = delegate()->peerListFullRowsCount();
|
||||
seen.reserve(std::min(int(list.size()), already));
|
||||
for (auto i = 0; i != already;) {
|
||||
const auto row = delegate()->peerListRowAt(i);
|
||||
if (list.contains(row->peer())) {
|
||||
seen.emplace(row->peer());
|
||||
++i;
|
||||
} else {
|
||||
delegate()->peerListRemoveRow(row);
|
||||
--already;
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
for (const auto &peer : list) {
|
||||
if (!seen.contains(peer)) {
|
||||
appendRow(peer);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
if (added || removed) {
|
||||
if (added) {
|
||||
sort();
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
_count = delegate()->peerListFullRowsCount();
|
||||
}
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> ExceptionsController::rowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) {
|
||||
const auto peer = row->peer();
|
||||
auto result = base::make_unique_q<Ui::PopupMenu>(
|
||||
parent,
|
||||
st::popupMenuWithIcons);
|
||||
|
||||
result->addAction(
|
||||
(peer->isUser()
|
||||
? tr::lng_context_view_profile
|
||||
: peer->isBroadcast()
|
||||
? tr::lng_context_view_channel
|
||||
: tr::lng_context_view_group)(tr::now),
|
||||
crl::guard(_window, [window = _window.get(), peer] {
|
||||
window->showPeerInfo(peer);
|
||||
}),
|
||||
(peer->isUser() ? &st::menuIconProfile : &st::menuIconInfo));
|
||||
result->addSeparator();
|
||||
|
||||
MuteMenu::FillMuteMenu(
|
||||
result.get(),
|
||||
peer->owner().history(peer),
|
||||
_window->uiShow());
|
||||
|
||||
// First clear _menu value, so that we don't check row positions yet.
|
||||
base::take(_menu);
|
||||
|
||||
// Here unique_qptr is used like a shared pointer, where
|
||||
// not the last destroyed pointer destroys the object, but the first.
|
||||
_menu = base::unique_qptr<Ui::PopupMenu>(result.get());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ExceptionsController::appendRow(not_null<PeerData*> peer) {
|
||||
delegate()->peerListAppendRow(createRow(peer));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListRow> ExceptionsController::createRow(
|
||||
not_null<PeerData*> peer) const {
|
||||
auto row = std::make_unique<PeerListRowWithLink>(peer);
|
||||
row->setActionLink(tr::lng_notification_exceptions_remove(tr::now));
|
||||
refreshStatus(row.get());
|
||||
return row;
|
||||
}
|
||||
|
||||
void ExceptionsController::refreshStatus(not_null<PeerListRow*> row) const {
|
||||
const auto peer = row->peer();
|
||||
const auto status = peer->owner().notifySettings().isMuted(peer)
|
||||
? tr::lng_notification_exceptions_muted(tr::now)
|
||||
: tr::lng_notification_exceptions_unmuted(tr::now);
|
||||
row->setCustomStatus(status);
|
||||
}
|
||||
|
||||
void ExceptionsController::sort() {
|
||||
auto keys = base::flat_map<PeerListRowId, QString>();
|
||||
keys.reserve(delegate()->peerListFullRowsCount());
|
||||
const auto length = QString::number(_topOrder).size();
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto id = row.id();
|
||||
const auto i = keys.find(id);
|
||||
if (i != end(keys)) {
|
||||
return i->second;
|
||||
}
|
||||
const auto peer = row.peer();
|
||||
const auto top = _topOrdered.find(peer);
|
||||
if (top != end(_topOrdered)) {
|
||||
const auto order = _topOrder - top->second;
|
||||
return keys.emplace(
|
||||
id,
|
||||
u"0%1"_q.arg(order, length, 10, QChar('0'))).first->second;
|
||||
}
|
||||
const auto history = peer->owner().history(peer);
|
||||
return keys.emplace(
|
||||
id,
|
||||
'1' + history->chatListNameSortKey()).first->second;
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return (key(a).compare(key(b)) < 0);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
template <Notify kType>
|
||||
[[nodiscard]] Type Id() {
|
||||
return &NotificationsTypeMetaImplementation<kType>::Meta;
|
||||
|
@ -103,7 +427,7 @@ void SetupChecks(
|
|||
: ExtractRingtoneName(session->data().document(now.id));
|
||||
};
|
||||
settings->defaultUpdates(
|
||||
Data::DefaultNotify::User
|
||||
Notify::User
|
||||
) | rpl::start_with_next([=] {
|
||||
toneLabel->fire(label());
|
||||
}, toneInner->lifetime());
|
||||
|
@ -147,9 +471,74 @@ void SetupChecks(
|
|||
}
|
||||
|
||||
void SetupExceptions(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Notify type) {
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
not_null<Window::SessionController*> window,
|
||||
Notify type) {
|
||||
const auto add = AddButton(
|
||||
container,
|
||||
tr::lng_notification_exceptions_add(),
|
||||
st::settingsButtonActive,
|
||||
{ &st::menuIconInviteSettings });
|
||||
|
||||
auto controller = std::make_unique<ExceptionsController>(window, type);
|
||||
controller->setStyleOverrides(&st::settingsBlockedList);
|
||||
const auto content = container->add(
|
||||
object_ptr<PeerListContent>(container, controller.get()));
|
||||
|
||||
struct State {
|
||||
std::unique_ptr<ExceptionsController> controller;
|
||||
std::unique_ptr<PeerListContentDelegateSimple> delegate;
|
||||
};
|
||||
const auto state = content->lifetime().make_state<State>();
|
||||
state->controller = std::move(controller);
|
||||
state->delegate = std::make_unique<PeerListContentDelegateSimple>();
|
||||
|
||||
state->delegate->setContent(content);
|
||||
state->controller->setDelegate(state->delegate.get());
|
||||
|
||||
add->setClickedCallback([=] {
|
||||
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
const auto done = [=](not_null<PeerData*> peer) {
|
||||
state->controller->bringToTop(peer);
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
};
|
||||
auto controller = std::make_unique<AddExceptionBoxController>(
|
||||
&window->session(),
|
||||
type,
|
||||
crl::guard(content, done));
|
||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->addButton(tr::lng_cancel(), [box] { box->closeBox(); });
|
||||
};
|
||||
*box = window->show(
|
||||
Box<PeerListBox>(std::move(controller), std::move(initBox)));
|
||||
});
|
||||
|
||||
const auto wrap = container->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::SettingsButton>>(
|
||||
container,
|
||||
CreateButton(
|
||||
container,
|
||||
tr::lng_notification_exceptions_clear(),
|
||||
st::settingsAttentionButtonWithIcon,
|
||||
{ &st::menuIconDeleteAttention })));
|
||||
wrap->entity()->setClickedCallback([=] {
|
||||
const auto clear = [=](Fn<void()> close) {
|
||||
window->session().data().notifySettings().clearExceptions(type);
|
||||
close();
|
||||
};
|
||||
window->show(Ui::MakeConfirmBox({
|
||||
.text = tr::lng_notification_exceptions_clear_sure(),
|
||||
.confirmed = clear,
|
||||
.confirmText = tr::lng_notification_exceptions_clear_button(),
|
||||
.confirmStyle = &st::attentionBoxButton,
|
||||
.title = tr::lng_notification_exceptions_clear(),
|
||||
}));
|
||||
});
|
||||
wrap->toggleOn(
|
||||
state->controller->countValue() | rpl::map(rpl::mappers::_1 > 1),
|
||||
anim::type::instant);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -211,7 +600,7 @@ bool NotificationsEnabledForType(
|
|||
|
||||
rpl::producer<bool> NotificationsEnabledForTypeValue(
|
||||
not_null<Main::Session*> session,
|
||||
Data::DefaultNotify type) {
|
||||
Notify type) {
|
||||
const auto settings = &session->data().notifySettings();
|
||||
return rpl::single(
|
||||
rpl::empty
|
||||
|
|
|
@ -173,6 +173,7 @@ menuIconReportAttention: icon {{ "menu/report", menuIconAttentionColor }};
|
|||
menuIconRestoreAttention: icon {{ "menu/restore", menuIconAttentionColor }};
|
||||
|
||||
menuIconBlockSettings: icon {{ "menu/block", windowBgActive }};
|
||||
menuIconInviteSettings: icon {{ "menu/invite", windowBgActive }};
|
||||
|
||||
playerSpeedSlow: icon {{ "player/speed/audiospeed_menu_0.5", menuIconColor }};
|
||||
playerSpeedSlowActive: icon {{ "player/speed/audiospeed_menu_0.5", mediaPlayerActiveFg }};
|
||||
|
|
Loading…
Add table
Reference in a new issue