From 7a2b3abe18d431add7187ea79c5d22a9e19c8669 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 11 Apr 2022 20:01:44 +0300 Subject: [PATCH] Support new NotificationSound. --- CMakeLists.txt | 3 + td/generate/scheme/td_api.tl | 10 +- td/telegram/MessagesManager.cpp | 37 ++- td/telegram/MessagesManager.h | 2 +- td/telegram/NotificationSettings.cpp | 66 ++--- td/telegram/NotificationSettings.h | 11 +- td/telegram/NotificationSettings.hpp | 34 ++- td/telegram/NotificationSettingsManager.cpp | 58 ++-- td/telegram/NotificationSettingsManager.h | 2 +- td/telegram/NotificationSound.cpp | 299 ++++++++++++++++++++ td/telegram/NotificationSound.h | 68 +++++ td/telegram/NotificationSoundType.h | 15 + td/telegram/cli.cpp | 8 +- 13 files changed, 515 insertions(+), 98 deletions(-) create mode 100644 td/telegram/NotificationSound.cpp create mode 100644 td/telegram/NotificationSound.h create mode 100644 td/telegram/NotificationSoundType.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b2a7df246..bc0871b16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -393,6 +393,7 @@ set(TDLIB_SOURCE td/telegram/NotificationManager.cpp td/telegram/NotificationSettings.cpp td/telegram/NotificationSettingsManager.cpp + td/telegram/NotificationSound.cpp td/telegram/NotificationType.cpp td/telegram/OptionManager.cpp td/telegram/Payments.cpp @@ -620,6 +621,8 @@ set(TDLIB_SOURCE td/telegram/NotificationManager.h td/telegram/NotificationSettings.h td/telegram/NotificationSettingsManager.h + td/telegram/NotificationSound.h + td/telegram/NotificationSoundType.h td/telegram/NotificationType.h td/telegram/OptionManager.h td/telegram/PasswordManager.h diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 6da09c7fa..152803031 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -925,19 +925,19 @@ notificationSettingsScopeChannelChats = NotificationSettingsScope; //@description Contains information about notification settings for a chat //@use_default_mute_for If true, mute_for is ignored and the value for the relevant type of chat is used instead @mute_for Time left before notifications will be unmuted, in seconds -//@use_default_sound If true, sound is ignored and the value for the relevant type of chat is used instead @sound The name of an audio file to be used for notification sounds; only applies to iOS applications +//@use_default_sound If true, the value for the relevant type of chat is used instead of ringtone_id @ringtone_id Identifier of the ringtone to be played for notifications; 0 if sound is disabled //@use_default_show_preview If true, show_preview is ignored and the value for the relevant type of chat is used instead @show_preview True, if message content must be displayed in notifications //@use_default_disable_pinned_message_notifications If true, disable_pinned_message_notifications is ignored and the value for the relevant type of chat is used instead @disable_pinned_message_notifications If true, notifications for incoming pinned messages will be created as for an ordinary unread message //@use_default_disable_mention_notifications If true, disable_mention_notifications is ignored and the value for the relevant type of chat is used instead @disable_mention_notifications If true, notifications for messages with mentions will be created as for an ordinary unread message -chatNotificationSettings use_default_mute_for:Bool mute_for:int32 use_default_sound:Bool sound:string use_default_show_preview:Bool show_preview:Bool use_default_disable_pinned_message_notifications:Bool disable_pinned_message_notifications:Bool use_default_disable_mention_notifications:Bool disable_mention_notifications:Bool = ChatNotificationSettings; +chatNotificationSettings use_default_mute_for:Bool mute_for:int32 use_default_sound:Bool ringtone_id:int64 use_default_show_preview:Bool show_preview:Bool use_default_disable_pinned_message_notifications:Bool disable_pinned_message_notifications:Bool use_default_disable_mention_notifications:Bool disable_mention_notifications:Bool = ChatNotificationSettings; //@description Contains information about notification settings for several chats //@mute_for Time left before notifications will be unmuted, in seconds -//@sound The name of an audio file to be used for notification sounds; only applies to iOS applications +//@ringtone_id Identifier of the ringtone to be played for notifications; 0 if sound is disabled //@show_preview True, if message content must be displayed in notifications //@disable_pinned_message_notifications True, if notifications for incoming pinned messages will be created as for an ordinary unread message //@disable_mention_notifications True, if notifications for messages with mentions will be created as for an ordinary unread message -scopeNotificationSettings mute_for:int32 sound:string show_preview:Bool disable_pinned_message_notifications:Bool disable_mention_notifications:Bool = ScopeNotificationSettings; +scopeNotificationSettings mute_for:int32 ringtone_id:int64 show_preview:Bool disable_pinned_message_notifications:Bool disable_mention_notifications:Bool = ScopeNotificationSettings; //@description Contains information about a message draft @@ -5174,7 +5174,7 @@ getScopeNotificationSettings scope:NotificationSettingsScope = ScopeNotification //@description Changes notification settings for chats of a given type @scope Types of chats for which to change the notification settings @notification_settings The new notification settings for the given scope setScopeNotificationSettings scope:NotificationSettingsScope notification_settings:scopeNotificationSettings = Ok; -//@description Resets all notification settings to their default values. By default, all chats are unmuted, the sound is set to "default" and message previews are shown +//@description Resets all notification settings to their default values. By default, all chats are unmuted and message previews are shown resetAllNotificationSettings = Ok; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 04a74944b..ea98044b1 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -48,6 +48,7 @@ #include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationSettings.hpp" #include "td/telegram/NotificationSettingsManager.h" +#include "td/telegram/NotificationSound.h" #include "td/telegram/NotificationType.h" #include "td/telegram/PublicDialogType.h" #include "td/telegram/ReplyMarkup.h" @@ -7825,17 +7826,16 @@ void MessagesManager::on_message_edited(FullMessageId full_message_id, int32 pts bool MessagesManager::update_dialog_notification_settings(DialogId dialog_id, DialogNotificationSettings *current_settings, - const DialogNotificationSettings &new_settings) { + DialogNotificationSettings &&new_settings) { if (td_->auth_manager_->is_bot()) { // just in case return false; } bool need_update_server = current_settings->mute_until != new_settings.mute_until || - current_settings->sound != new_settings.sound || + !are_equivalent_notification_sounds(current_settings->sound, new_settings.sound) || current_settings->show_preview != new_settings.show_preview || current_settings->use_default_mute_until != new_settings.use_default_mute_until || - current_settings->use_default_sound != new_settings.use_default_sound || current_settings->use_default_show_preview != new_settings.use_default_show_preview; bool need_update_local = current_settings->use_default_disable_pinned_message_notifications != @@ -7847,7 +7847,8 @@ bool MessagesManager::update_dialog_notification_settings(DialogId dialog_id, bool is_changed = need_update_server || need_update_local || current_settings->is_synchronized != new_settings.is_synchronized || - current_settings->is_use_default_fixed != new_settings.is_use_default_fixed; + current_settings->is_use_default_fixed != new_settings.is_use_default_fixed || + are_different_equivalent_notification_sounds(current_settings->sound, new_settings.sound); if (is_changed) { Dialog *d = get_dialog(dialog_id); @@ -7860,7 +7861,7 @@ bool MessagesManager::update_dialog_notification_settings(DialogId dialog_id, update_dialog_unmute_timeout(d, current_settings->use_default_mute_until, current_settings->mute_until, new_settings.use_default_mute_until, new_settings.mute_until); - *current_settings = new_settings; + *current_settings = std::move(new_settings); on_dialog_updated(dialog_id, "update_dialog_notification_settings"); if (is_dialog_muted(d)) { @@ -8063,7 +8064,7 @@ void MessagesManager::on_update_dialog_notify_settings( return; } - const DialogNotificationSettings notification_settings = ::td::get_dialog_notification_settings( + DialogNotificationSettings notification_settings = ::td::get_dialog_notification_settings( std::move(peer_notify_settings), current_settings->use_default_disable_pinned_message_notifications, current_settings->disable_pinned_message_notifications, current_settings->use_default_disable_mention_notifications, current_settings->disable_mention_notifications); @@ -8071,7 +8072,7 @@ void MessagesManager::on_update_dialog_notify_settings( return; } - update_dialog_notification_settings(dialog_id, current_settings, notification_settings); + update_dialog_notification_settings(dialog_id, current_settings, std::move(notification_settings)); } void MessagesManager::on_update_dialog_available_reactions(DialogId dialog_id, vector &&available_reactions) { @@ -21270,7 +21271,10 @@ Status MessagesManager::set_dialog_notification_settings( TRY_RESULT(new_settings, ::td::get_dialog_notification_settings(std::move(notification_settings), current_settings->silent_send_message)); - if (update_dialog_notification_settings(dialog_id, current_settings, new_settings)) { + if (is_notification_sound_default(current_settings->sound) && is_notification_sound_default(new_settings.sound)) { + new_settings.sound = dup_notification_sound(current_settings->sound); + } + if (update_dialog_notification_settings(dialog_id, current_settings, std::move(new_settings))) { update_dialog_notification_settings_on_server(dialog_id, false); } return Status::OK(); @@ -21279,11 +21283,11 @@ Status MessagesManager::set_dialog_notification_settings( void MessagesManager::reset_all_notification_settings() { CHECK(!td_->auth_manager_->is_bot()); - DialogNotificationSettings new_dialog_settings; - new_dialog_settings.is_synchronized = true; for (auto &dialog : dialogs_) { + DialogNotificationSettings new_dialog_settings; + new_dialog_settings.is_synchronized = true; Dialog *d = dialog.second.get(); - update_dialog_notification_settings(d->dialog_id, &d->notification_settings, new_dialog_settings); + update_dialog_notification_settings(d->dialog_id, &d->notification_settings, std::move(new_dialog_settings)); } td_->notification_settings_manager_->reset_scope_notification_settings(); @@ -35721,11 +35725,14 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source Dialog *user_d = get_dialog_force(DialogId(user_id), source); if (user_d != nullptr && user_d->notification_settings.is_synchronized) { VLOG(notifications) << "Copy notification settings from " << user_d->dialog_id << " to " << dialog_id; - auto new_notification_settings = user_d->notification_settings; - new_notification_settings.use_default_show_preview = true; - new_notification_settings.show_preview = false; + auto user_settings = &user_d->notification_settings; + auto new_notification_settings = DialogNotificationSettings( + user_settings->use_default_mute_until, user_settings->mute_until, + dup_notification_sound(user_settings->sound), true /*use_default_show_preview*/, false /*show_preview*/, + user_settings->silent_send_message, true, false, true, false); new_notification_settings.is_secret_chat_show_preview_fixed = true; - update_dialog_notification_settings(dialog_id, &d->notification_settings, new_notification_settings); + update_dialog_notification_settings(dialog_id, &d->notification_settings, + std::move(new_notification_settings)); } else { d->notification_settings.is_synchronized = true; } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index a6791f6f7..58f780ce6 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2604,7 +2604,7 @@ class MessagesManager final : public Actor { NotificationId last_notification_id, const char *source); bool update_dialog_notification_settings(DialogId dialog_id, DialogNotificationSettings *current_settings, - const DialogNotificationSettings &new_settings); + DialogNotificationSettings &&new_settings); void schedule_dialog_unmute(DialogId dialog_id, bool use_default, int32 mute_until); diff --git a/td/telegram/NotificationSettings.cpp b/td/telegram/NotificationSettings.cpp index 55066bdde..d67395044 100644 --- a/td/telegram/NotificationSettings.cpp +++ b/td/telegram/NotificationSettings.cpp @@ -7,7 +7,6 @@ #include "td/telegram/NotificationSettings.h" #include "td/telegram/Global.h" -#include "td/telegram/misc.h" #include "td/utils/common.h" @@ -21,7 +20,6 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DialogNotificatio << ", " << notification_settings.disable_pinned_message_notifications << ", " << notification_settings.disable_mention_notifications << ", " << notification_settings.use_default_mute_until << ", " - << notification_settings.use_default_sound << ", " << notification_settings.use_default_show_preview << ", " << notification_settings.use_default_disable_pinned_message_notifications << ", " << notification_settings.use_default_disable_mention_notifications << ", " @@ -69,9 +67,9 @@ td_api::object_ptr get_chat_notification_setti CHECK(notification_settings != nullptr); return td_api::make_object( notification_settings->use_default_mute_until, max(0, notification_settings->mute_until - G()->unix_time()), - notification_settings->use_default_sound, notification_settings->sound, - notification_settings->use_default_show_preview, notification_settings->show_preview, - notification_settings->use_default_disable_pinned_message_notifications, + is_notification_sound_default(notification_settings->sound), + get_notification_sound_ringtone_id(notification_settings->sound), notification_settings->use_default_show_preview, + notification_settings->show_preview, notification_settings->use_default_disable_pinned_message_notifications, notification_settings->disable_pinned_message_notifications, notification_settings->use_default_disable_mention_notifications, notification_settings->disable_mention_notifications); @@ -81,8 +79,9 @@ td_api::object_ptr get_scope_notification_set const ScopeNotificationSettings *notification_settings) { CHECK(notification_settings != nullptr); return td_api::make_object( - max(0, notification_settings->mute_until - G()->unix_time()), notification_settings->sound, - notification_settings->show_preview, notification_settings->disable_pinned_message_notifications, + max(0, notification_settings->mute_until - G()->unix_time()), + get_notification_sound_ringtone_id(notification_settings->sound), notification_settings->show_preview, + notification_settings->disable_pinned_message_notifications, notification_settings->disable_mention_notifications); } @@ -133,23 +132,17 @@ Result get_dialog_notification_settings( if (notification_settings == nullptr) { return Status::Error(400, "New notification settings must be non-empty"); } - if (!clean_input_string(notification_settings->sound_)) { - return Status::Error(400, "Notification settings sound must be encoded in UTF-8"); - } - if (notification_settings->sound_.empty()) { - notification_settings->sound_ = "default"; - } int32 mute_until = notification_settings->use_default_mute_for_ ? 0 : get_mute_until(notification_settings->mute_for_); - return DialogNotificationSettings(notification_settings->use_default_mute_for_, mute_until, - notification_settings->use_default_sound_, std::move(notification_settings->sound_), - notification_settings->use_default_show_preview_, - notification_settings->show_preview_, old_silent_send_message, - notification_settings->use_default_disable_pinned_message_notifications_, - notification_settings->disable_pinned_message_notifications_, - notification_settings->use_default_disable_mention_notifications_, - notification_settings->disable_mention_notifications_); + return DialogNotificationSettings( + notification_settings->use_default_mute_for_, mute_until, + get_notification_sound(notification_settings->use_default_sound_, notification_settings->ringtone_id_), + notification_settings->use_default_show_preview_, notification_settings->show_preview_, old_silent_send_message, + notification_settings->use_default_disable_pinned_message_notifications_, + notification_settings->disable_pinned_message_notifications_, + notification_settings->use_default_disable_mention_notifications_, + notification_settings->disable_mention_notifications_); } Result get_scope_notification_settings( @@ -157,20 +150,27 @@ Result get_scope_notification_settings( if (notification_settings == nullptr) { return Status::Error(400, "New notification settings must be non-empty"); } - if (!clean_input_string(notification_settings->sound_)) { - return Status::Error(400, "Notification settings sound must be encoded in UTF-8"); - } - if (notification_settings->sound_.empty()) { - notification_settings->sound_ = "default"; - } auto mute_until = get_mute_until(notification_settings->mute_for_); - return ScopeNotificationSettings(mute_until, std::move(notification_settings->sound_), + return ScopeNotificationSettings(mute_until, get_notification_sound(false, notification_settings->ringtone_id_), notification_settings->show_preview_, notification_settings->disable_pinned_message_notifications_, notification_settings->disable_mention_notifications_); } +static unique_ptr get_peer_notification_sound( + tl_object_ptr &settings) { + telegram_api::NotificationSound *sound = +#if TD_ANDROID + settings->android_sound_.get(); +#elif TD_DARWIN_IOS || TD_DARWIN_TV_OS || TD_DARWIN_WATCH_OS + settings->ios_sound_.get(); +#else + settings->other_sound_.get(); +#endif + return get_notification_sound(sound); +} + DialogNotificationSettings get_dialog_notification_settings(tl_object_ptr &&settings, bool old_use_default_disable_pinned_message_notifications, bool old_disable_pinned_message_notifications, @@ -180,16 +180,13 @@ DialogNotificationSettings get_dialog_notification_settings(tl_object_ptrflags_ & telegram_api::peerNotifySettings::MUTE_UNTIL_MASK) == 0; - bool use_default_sound = settings->other_sound_ == nullptr; bool use_default_show_preview = (settings->flags_ & telegram_api::peerNotifySettings::SHOW_PREVIEWS_MASK) == 0; auto mute_until = use_default_mute_until || settings->mute_until_ <= G()->unix_time() ? 0 : settings->mute_until_; - string sound = "default"; bool silent_send_message = (settings->flags_ & telegram_api::peerNotifySettings::SILENT_MASK) == 0 ? false : settings->silent_; return {use_default_mute_until, mute_until, - use_default_sound, - std::move(sound), + get_peer_notification_sound(settings), use_default_show_preview, settings->show_previews_, silent_send_message, @@ -209,15 +206,14 @@ ScopeNotificationSettings get_scope_notification_settings(tl_object_ptrmute_until_ <= G()->unix_time() ? 0 : settings->mute_until_; - string sound = "default"; auto show_preview = (settings->flags_ & telegram_api::peerNotifySettings::SHOW_PREVIEWS_MASK) == 0 ? false : settings->show_previews_; - return {mute_until, std::move(sound), show_preview, old_disable_pinned_message_notifications, + return {mute_until, get_peer_notification_sound(settings), show_preview, old_disable_pinned_message_notifications, old_disable_mention_notifications}; } bool are_default_dialog_notification_settings(const DialogNotificationSettings &settings, bool compare_sound) { - return settings.use_default_mute_until && (!compare_sound || settings.use_default_sound) && + return settings.use_default_mute_until && (!compare_sound || is_notification_sound_default(settings.sound)) && settings.use_default_show_preview && settings.use_default_disable_pinned_message_notifications && settings.use_default_disable_mention_notifications; } diff --git a/td/telegram/NotificationSettings.h b/td/telegram/NotificationSettings.h index 01cd22623..0fc0d6170 100644 --- a/td/telegram/NotificationSettings.h +++ b/td/telegram/NotificationSettings.h @@ -6,6 +6,7 @@ // #pragma once +#include "td/telegram/NotificationSound.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" @@ -18,11 +19,10 @@ namespace td { class DialogNotificationSettings { public: int32 mute_until = 0; - string sound = "default"; + unique_ptr sound; bool show_preview = true; bool silent_send_message = false; bool use_default_mute_until = true; - bool use_default_sound = true; bool use_default_show_preview = true; bool is_use_default_fixed = true; bool is_secret_chat_show_preview_fixed = false; @@ -36,7 +36,7 @@ class DialogNotificationSettings { DialogNotificationSettings() = default; - DialogNotificationSettings(bool use_default_mute_until, int32 mute_until, bool use_default_sound, string sound, + DialogNotificationSettings(bool use_default_mute_until, int32 mute_until, unique_ptr &&sound, bool use_default_show_preview, bool show_preview, bool silent_send_message, bool use_default_disable_pinned_message_notifications, bool disable_pinned_message_notifications, bool use_default_disable_mention_notifications, @@ -46,7 +46,6 @@ class DialogNotificationSettings { , show_preview(show_preview) , silent_send_message(silent_send_message) , use_default_mute_until(use_default_mute_until) - , use_default_sound(use_default_sound) , use_default_show_preview(use_default_show_preview) , is_synchronized(true) , use_default_disable_pinned_message_notifications(use_default_disable_pinned_message_notifications) @@ -61,7 +60,7 @@ enum class NotificationSettingsScope : int32 { Private, Group, Channel }; class ScopeNotificationSettings { public: int32 mute_until = 0; - string sound = "default"; + unique_ptr sound; bool show_preview = true; bool is_synchronized = false; @@ -71,7 +70,7 @@ class ScopeNotificationSettings { ScopeNotificationSettings() = default; - ScopeNotificationSettings(int32 mute_until, string sound, bool show_preview, + ScopeNotificationSettings(int32 mute_until, unique_ptr &&sound, bool show_preview, bool disable_pinned_message_notifications, bool disable_mention_notifications) : mute_until(mute_until) , sound(std::move(sound)) diff --git a/td/telegram/NotificationSettings.hpp b/td/telegram/NotificationSettings.hpp index 288af3c71..2b66bf1dc 100644 --- a/td/telegram/NotificationSettings.hpp +++ b/td/telegram/NotificationSettings.hpp @@ -8,6 +8,7 @@ #include "td/telegram/Global.h" #include "td/telegram/NotificationSettings.h" +#include "td/telegram/NotificationSound.h" #include "td/utils/tl_helpers.h" @@ -17,7 +18,8 @@ template void store(const DialogNotificationSettings ¬ification_settings, StorerT &storer) { bool is_muted = !notification_settings.use_default_mute_until && notification_settings.mute_until != 0 && notification_settings.mute_until > G()->unix_time(); - bool has_sound = !notification_settings.use_default_sound && notification_settings.sound != "default"; + bool has_sound = notification_settings.sound != nullptr; + bool has_ringtone_support = true; BEGIN_STORE_FLAGS(); STORE_FLAG(is_muted); STORE_FLAG(has_sound); @@ -25,7 +27,7 @@ void store(const DialogNotificationSettings ¬ification_settings, StorerT &sto STORE_FLAG(notification_settings.silent_send_message); STORE_FLAG(notification_settings.is_synchronized); STORE_FLAG(notification_settings.use_default_mute_until); - STORE_FLAG(notification_settings.use_default_sound); + STORE_FLAG(false); // use_default_sound STORE_FLAG(notification_settings.use_default_show_preview); STORE_FLAG(notification_settings.is_use_default_fixed); STORE_FLAG(!notification_settings.use_default_disable_pinned_message_notifications); @@ -33,6 +35,7 @@ void store(const DialogNotificationSettings ¬ification_settings, StorerT &sto STORE_FLAG(!notification_settings.use_default_disable_mention_notifications); STORE_FLAG(notification_settings.disable_mention_notifications); STORE_FLAG(notification_settings.is_secret_chat_show_preview_fixed); + STORE_FLAG(has_ringtone_support); END_STORE_FLAGS(); if (is_muted) { store(notification_settings.mute_until, storer); @@ -46,8 +49,10 @@ template void parse(DialogNotificationSettings ¬ification_settings, ParserT &parser) { bool is_muted; bool has_sound; + bool use_default_sound; bool use_disable_pinned_message_notifications; bool use_disable_mention_notifications; + bool has_ringtone_support; BEGIN_PARSE_FLAGS(); PARSE_FLAG(is_muted); PARSE_FLAG(has_sound); @@ -55,7 +60,7 @@ void parse(DialogNotificationSettings ¬ification_settings, ParserT &parser) { PARSE_FLAG(notification_settings.silent_send_message); PARSE_FLAG(notification_settings.is_synchronized); PARSE_FLAG(notification_settings.use_default_mute_until); - PARSE_FLAG(notification_settings.use_default_sound); + PARSE_FLAG(use_default_sound); PARSE_FLAG(notification_settings.use_default_show_preview); PARSE_FLAG(notification_settings.is_use_default_fixed); PARSE_FLAG(use_disable_pinned_message_notifications); @@ -63,6 +68,7 @@ void parse(DialogNotificationSettings ¬ification_settings, ParserT &parser) { PARSE_FLAG(use_disable_mention_notifications); PARSE_FLAG(notification_settings.disable_mention_notifications); PARSE_FLAG(notification_settings.is_secret_chat_show_preview_fixed); + PARSE_FLAG(has_ringtone_support); END_PARSE_FLAGS(); notification_settings.use_default_disable_pinned_message_notifications = !use_disable_pinned_message_notifications; notification_settings.use_default_disable_mention_notifications = !use_disable_mention_notifications; @@ -70,14 +76,21 @@ void parse(DialogNotificationSettings ¬ification_settings, ParserT &parser) { parse(notification_settings.mute_until, parser); } if (has_sound) { - parse(notification_settings.sound, parser); + if (has_ringtone_support) { + parse_notification_sound(notification_settings.sound, parser); + } else { + string sound; + parse(sound, parser); + notification_settings.sound = use_default_sound ? nullptr : get_legacy_notification_sound(sound); + } } } template void store(const ScopeNotificationSettings ¬ification_settings, StorerT &storer) { bool is_muted = notification_settings.mute_until != 0 && notification_settings.mute_until > G()->unix_time(); - bool has_sound = notification_settings.sound != "default"; + bool has_sound = notification_settings.sound != nullptr; + bool has_ringtone_support = true; BEGIN_STORE_FLAGS(); STORE_FLAG(is_muted); STORE_FLAG(has_sound); @@ -86,6 +99,7 @@ void store(const ScopeNotificationSettings ¬ification_settings, StorerT &stor STORE_FLAG(notification_settings.is_synchronized); STORE_FLAG(notification_settings.disable_pinned_message_notifications); STORE_FLAG(notification_settings.disable_mention_notifications); + STORE_FLAG(has_ringtone_support); END_STORE_FLAGS(); if (is_muted) { store(notification_settings.mute_until, storer); @@ -100,6 +114,7 @@ void parse(ScopeNotificationSettings ¬ification_settings, ParserT &parser) { bool is_muted; bool has_sound; bool silent_send_message_ignored; + bool has_ringtone_support; BEGIN_PARSE_FLAGS(); PARSE_FLAG(is_muted); PARSE_FLAG(has_sound); @@ -108,13 +123,20 @@ void parse(ScopeNotificationSettings ¬ification_settings, ParserT &parser) { PARSE_FLAG(notification_settings.is_synchronized); PARSE_FLAG(notification_settings.disable_pinned_message_notifications); PARSE_FLAG(notification_settings.disable_mention_notifications); + PARSE_FLAG(has_ringtone_support); END_PARSE_FLAGS(); (void)silent_send_message_ignored; if (is_muted) { parse(notification_settings.mute_until, parser); } if (has_sound) { - parse(notification_settings.sound, parser); + if (has_ringtone_support) { + parse_notification_sound(notification_settings.sound, parser); + } else { + string sound; + parse(sound, parser); + notification_settings.sound = get_legacy_notification_sound(sound); + } } } diff --git a/td/telegram/NotificationSettingsManager.cpp b/td/telegram/NotificationSettingsManager.cpp index 4c4baac64..4f6e5e3f3 100644 --- a/td/telegram/NotificationSettingsManager.cpp +++ b/td/telegram/NotificationSettingsManager.cpp @@ -15,6 +15,7 @@ #include "td/telegram/MessagesManager.h" #include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationSettings.hpp" +#include "td/telegram/NotificationSound.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" @@ -174,7 +175,7 @@ class UpdateDialogNotifySettingsQuery final : public Td::ResultHandler { if (!new_settings.use_default_mute_until) { flags |= telegram_api::inputPeerNotifySettings::MUTE_UNTIL_MASK; } - if (!new_settings.use_default_sound) { + if (new_settings.sound != nullptr) { flags |= telegram_api::inputPeerNotifySettings::SOUND_MASK; } if (!new_settings.use_default_show_preview) { @@ -184,10 +185,9 @@ class UpdateDialogNotifySettingsQuery final : public Td::ResultHandler { flags |= telegram_api::inputPeerNotifySettings::SILENT_MASK; } send_query(G()->net_query_creator().create(telegram_api::account_updateNotifySettings( - std::move(input_notify_peer), - make_tl_object( - flags, new_settings.show_preview, new_settings.silent_send_message, new_settings.mute_until, - make_tl_object())))); + std::move(input_notify_peer), make_tl_object( + flags, new_settings.show_preview, new_settings.silent_send_message, + new_settings.mute_until, get_input_notification_sound(new_settings.sound))))); } void on_result(BufferSlice packet) final { @@ -231,12 +231,14 @@ class UpdateScopeNotifySettingsQuery final : public Td::ResultHandler { auto input_notify_peer = get_input_notify_peer(scope); CHECK(input_notify_peer != nullptr); int32 flags = telegram_api::inputPeerNotifySettings::MUTE_UNTIL_MASK | - telegram_api::inputPeerNotifySettings::SOUND_MASK | telegram_api::inputPeerNotifySettings::SHOW_PREVIEWS_MASK; + if (new_settings.sound != nullptr) { + flags |= telegram_api::inputPeerNotifySettings::SOUND_MASK; + } send_query(G()->net_query_creator().create(telegram_api::account_updateNotifySettings( std::move(input_notify_peer), make_tl_object( flags, new_settings.show_preview, false, new_settings.mute_until, - make_tl_object())))); + get_input_notification_sound(new_settings.sound))))); scope_ = scope; } @@ -341,9 +343,9 @@ void NotificationSettingsManager::init() { } } if (!channels_notification_settings_.is_synchronized && is_authorized) { - channels_notification_settings_ = chats_notification_settings_; - channels_notification_settings_.disable_pinned_message_notifications = false; - channels_notification_settings_.disable_mention_notifications = false; + channels_notification_settings_ = ScopeNotificationSettings( + chats_notification_settings_.mute_until, dup_notification_sound(chats_notification_settings_.sound), + chats_notification_settings_.show_preview, false, false); channels_notification_settings_.is_synchronized = false; send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, Promise<>()); } @@ -483,26 +485,26 @@ void NotificationSettingsManager::on_update_scope_notify_settings( auto old_notification_settings = get_scope_notification_settings(scope); CHECK(old_notification_settings != nullptr); - const ScopeNotificationSettings notification_settings = ::td::get_scope_notification_settings( + ScopeNotificationSettings notification_settings = ::td::get_scope_notification_settings( std::move(peer_notify_settings), old_notification_settings->disable_pinned_message_notifications, old_notification_settings->disable_mention_notifications); if (!notification_settings.is_synchronized) { return; } - update_scope_notification_settings(scope, old_notification_settings, notification_settings); + update_scope_notification_settings(scope, old_notification_settings, std::move(notification_settings)); } bool NotificationSettingsManager::update_scope_notification_settings(NotificationSettingsScope scope, ScopeNotificationSettings *current_settings, - const ScopeNotificationSettings &new_settings) { + ScopeNotificationSettings &&new_settings) { if (td_->auth_manager_->is_bot()) { // just in case return false; } bool need_update_server = current_settings->mute_until != new_settings.mute_until || - current_settings->sound != new_settings.sound || + !are_equivalent_notification_sounds(current_settings->sound, new_settings.sound) || current_settings->show_preview != new_settings.show_preview; bool need_update_local = current_settings->disable_pinned_message_notifications != new_settings.disable_pinned_message_notifications || @@ -512,7 +514,8 @@ bool NotificationSettingsManager::update_scope_notification_settings(Notificatio if (was_inited && !is_inited) { return false; // just in case } - bool is_changed = need_update_server || need_update_local || was_inited != is_inited; + bool is_changed = need_update_server || need_update_local || was_inited != is_inited || + are_different_equivalent_notification_sounds(current_settings->sound, new_settings.sound); if (is_changed) { save_scope_notification_settings(scope, new_settings); @@ -528,7 +531,7 @@ bool NotificationSettingsManager::update_scope_notification_settings(Notificatio td_->messages_manager_->on_update_scope_mention_notifications(scope, new_settings.disable_mention_notifications); } - *current_settings = new_settings; + *current_settings = std::move(new_settings); send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope)); } @@ -571,15 +574,15 @@ void NotificationSettingsManager::update_scope_unmute_timeout(NotificationSettin void NotificationSettingsManager::reset_scope_notification_settings() { CHECK(!td_->auth_manager_->is_bot()); - ScopeNotificationSettings new_scope_settings; - new_scope_settings.is_synchronized = true; - update_scope_notification_settings(NotificationSettingsScope::Private, &users_notification_settings_, - new_scope_settings); - update_scope_notification_settings(NotificationSettingsScope::Group, &chats_notification_settings_, - new_scope_settings); - update_scope_notification_settings(NotificationSettingsScope::Channel, &channels_notification_settings_, - new_scope_settings); + for (auto scope : + {NotificationSettingsScope::Private, NotificationSettingsScope::Group, NotificationSettingsScope::Channel}) { + auto current_settings = get_scope_notification_settings(scope); + CHECK(current_settings != nullptr); + ScopeNotificationSettings new_scope_settings; + new_scope_settings.is_synchronized = true; + update_scope_notification_settings(scope, current_settings, std::move(new_scope_settings)); + } } void NotificationSettingsManager::send_get_dialog_notification_settings_query(DialogId dialog_id, @@ -653,8 +656,13 @@ void NotificationSettingsManager::update_dialog_notify_settings(DialogId dialog_ Status NotificationSettingsManager::set_scope_notification_settings( NotificationSettingsScope scope, td_api::object_ptr &¬ification_settings) { CHECK(!td_->auth_manager_->is_bot()); + auto *current_settings = get_scope_notification_settings(scope); + CHECK(current_settings != nullptr); TRY_RESULT(new_settings, ::td::get_scope_notification_settings(std::move(notification_settings))); - if (update_scope_notification_settings(scope, get_scope_notification_settings(scope), new_settings)) { + if (is_notification_sound_default(current_settings->sound) && is_notification_sound_default(new_settings.sound)) { + new_settings.sound = dup_notification_sound(current_settings->sound); + } + if (update_scope_notification_settings(scope, current_settings, std::move(new_settings))) { update_scope_notification_settings_on_server(scope, 0); } return Status::OK(); diff --git a/td/telegram/NotificationSettingsManager.h b/td/telegram/NotificationSettingsManager.h index 95e6e0ead..ab720210d 100644 --- a/td/telegram/NotificationSettingsManager.h +++ b/td/telegram/NotificationSettingsManager.h @@ -99,7 +99,7 @@ class NotificationSettingsManager final : public Actor { const ScopeNotificationSettings &new_settings); bool update_scope_notification_settings(NotificationSettingsScope scope, ScopeNotificationSettings *current_settings, - const ScopeNotificationSettings &new_settings); + ScopeNotificationSettings &&new_settings); static uint64 save_update_scope_notification_settings_on_server_log_event(NotificationSettingsScope scope); diff --git a/td/telegram/NotificationSound.cpp b/td/telegram/NotificationSound.cpp new file mode 100644 index 000000000..1ddf05250 --- /dev/null +++ b/td/telegram/NotificationSound.cpp @@ -0,0 +1,299 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/NotificationSound.h" + +#include "td/utils/tl_helpers.h" + +namespace td { + +class NotificationSoundNone final : public NotificationSound { + public: + NotificationSoundNone() = default; + + NotificationSoundType get_type() const final { + return NotificationSoundType::None; + } +}; + +class NotificationSoundLocal final : public NotificationSound { + public: + string title_; + string data_; + + NotificationSoundLocal() = default; + NotificationSoundLocal(string title, string data) : title_(std::move(title)), data_(std::move(data)) { + } + + NotificationSoundType get_type() const final { + return NotificationSoundType::Local; + } +}; + +class NotificationSoundRingtone final : public NotificationSound { + public: + int64 ringtone_id_; + + NotificationSoundRingtone() = default; + explicit NotificationSoundRingtone(int64 ringtone_id) : ringtone_id_(ringtone_id) { + } + + NotificationSoundType get_type() const final { + return NotificationSoundType::Ringtone; + } +}; + +template +static void store(const NotificationSound *notification_sound, StorerT &storer) { + CHECK(notification_sound != nullptr); + + auto sound_type = notification_sound->get_type(); + store(sound_type, storer); + + switch (sound_type) { + case NotificationSoundType::None: + break; + case NotificationSoundType::Local: { + const auto *sound = static_cast(notification_sound); + store(sound->title_, storer); + store(sound->data_, storer); + break; + } + case NotificationSoundType::Ringtone: { + const auto *sound = static_cast(notification_sound); + store(sound->ringtone_id_, storer); + break; + } + default: + UNREACHABLE(); + } +} + +template +static void parse(unique_ptr ¬ification_sound, ParserT &parser) { + NotificationSoundType sound_type; + parse(sound_type, parser); + + switch (sound_type) { + case NotificationSoundType::None: + notification_sound = make_unique(); + break; + case NotificationSoundType::Local: { + auto sound = make_unique(); + parse(sound->title_, parser); + parse(sound->data_, parser); + notification_sound = std::move(sound); + break; + } + case NotificationSoundType::Ringtone: { + auto sound = make_unique(); + parse(sound->ringtone_id_, parser); + notification_sound = std::move(sound); + break; + } + default: + LOG(FATAL) << "Have unknown notification sound type " << static_cast(sound_type); + } +} + +void store_notification_sound(const NotificationSound *notification_sound, LogEventStorerCalcLength &storer) { + store(notification_sound, storer); +} + +void store_notification_sound(const NotificationSound *notification_sound, LogEventStorerUnsafe &storer) { + store(notification_sound, storer); +} + +void parse_notification_sound(unique_ptr ¬ification_sound, LogEventParser &parser) { + parse(notification_sound, parser); +} + +StringBuilder &operator<<(StringBuilder &string_builder, const unique_ptr ¬ification_sound) { + if (notification_sound == nullptr) { + return string_builder << "DefaultSound"; + } + switch (notification_sound->get_type()) { + case NotificationSoundType::None: + return string_builder << "NoSound"; + case NotificationSoundType::Local: { + const auto *sound = static_cast(notification_sound.get()); + return string_builder << "LocalSound[" << sound->title_ << '|' << sound->data_ << ']'; + } + case NotificationSoundType::Ringtone: { + const auto *sound = static_cast(notification_sound.get()); + return string_builder << "Ringtone[" << sound->ringtone_id_ << ']'; + } + default: + UNREACHABLE(); + return string_builder; + } +} + +bool is_notification_sound_default(const unique_ptr ¬ification_sound) { + if (notification_sound == nullptr) { + return true; + } + return notification_sound->get_type() == NotificationSoundType::Local; +} + +bool are_equivalent_notification_sounds(const unique_ptr &lhs, + const unique_ptr &rhs) { + if (is_notification_sound_default(lhs)) { + return is_notification_sound_default(rhs); + } + if (is_notification_sound_default(rhs)) { + return false; + } + + auto sound_type = lhs->get_type(); + if (sound_type != rhs->get_type()) { + return false; + } + + switch (sound_type) { + case NotificationSoundType::None: + return true; + case NotificationSoundType::Ringtone: + return static_cast(lhs.get())->ringtone_id_ == + static_cast(rhs.get())->ringtone_id_; + case NotificationSoundType::Local: + default: + UNREACHABLE(); + break; + } + return false; +} + +bool are_different_equivalent_notification_sounds(const unique_ptr &lhs, + const unique_ptr &rhs) { + if (lhs == nullptr) { + return rhs != nullptr && rhs->get_type() == NotificationSoundType::Local; + } + if (rhs == nullptr) { + return lhs->get_type() == NotificationSoundType::Local; + } + if (lhs->get_type() != NotificationSoundType::Local || rhs->get_type() != NotificationSoundType::Local) { + return false; + } + + const auto *lhs_local = static_cast(lhs.get()); + const auto *rhs_local = static_cast(rhs.get()); + return lhs_local->title_ != rhs_local->title_ || lhs_local->data_ != rhs_local->data_; +} + +int64 get_notification_sound_ringtone_id(const unique_ptr ¬ification_sound) { + if (notification_sound == nullptr) { + return -1; + } + switch (notification_sound->get_type()) { + case NotificationSoundType::None: + return 0; + case NotificationSoundType::Local: + return -1; + case NotificationSoundType::Ringtone: { + return static_cast(notification_sound.get())->ringtone_id_; + default: + UNREACHABLE(); + return -1; + } + } +} + +unique_ptr get_legacy_notification_sound(const string &sound) { + if (sound == "default") { + return nullptr; + } + if (sound.empty()) { + return make_unique(); + } + return td::make_unique(sound, sound); +} + +unique_ptr get_notification_sound(bool use_default_sound, int64 ringtone_id) { + if (use_default_sound || ringtone_id == -1) { + return nullptr; + } + if (ringtone_id == 0) { + return make_unique(); + } + return td::make_unique(ringtone_id); +} + +unique_ptr get_notification_sound(telegram_api::NotificationSound *notification_sound) { + if (notification_sound == nullptr) { + return nullptr; + } + + switch (notification_sound->get_id()) { + case telegram_api::notificationSoundDefault::ID: + return nullptr; + case telegram_api::notificationSoundNone::ID: + return make_unique(); + case telegram_api::notificationSoundLocal::ID: { + const auto *sound = static_cast(notification_sound); + return td::make_unique(std::move(sound->title_), std::move(sound->data_)); + } + case telegram_api::notificationSoundRingtone::ID: { + const auto *sound = static_cast(notification_sound); + if (sound->id_ == 0 || sound->id_ == -1) { + LOG(ERROR) << "Receive ringtone with id = " << sound->id_; + return make_unique(); + } + return td::make_unique(sound->id_); + } + default: + UNREACHABLE(); + return nullptr; + } +} + +telegram_api::object_ptr get_input_notification_sound( + const unique_ptr ¬ification_sound) { + if (notification_sound == nullptr) { + return nullptr; + } + + // must not return nullptr if notification_sound != nullptr + switch (notification_sound->get_type()) { + case NotificationSoundType::None: + return telegram_api::make_object(); + case NotificationSoundType::Local: { + const auto *sound = static_cast(notification_sound.get()); + return telegram_api::make_object(sound->title_, sound->data_); + } + case NotificationSoundType::Ringtone: { + const auto *sound = static_cast(notification_sound.get()); + return telegram_api::make_object(sound->ringtone_id_); + } + default: + UNREACHABLE(); + return nullptr; + } +} + +unique_ptr dup_notification_sound(const unique_ptr ¬ification_sound) { + if (notification_sound == nullptr) { + return nullptr; + } + + switch (notification_sound->get_type()) { + case NotificationSoundType::None: + return make_unique(); + case NotificationSoundType::Local: { + const auto *sound = static_cast(notification_sound.get()); + return td::make_unique(sound->title_, sound->data_); + } + case NotificationSoundType::Ringtone: { + const auto *sound = static_cast(notification_sound.get()); + return td::make_unique(sound->ringtone_id_); + } + default: + UNREACHABLE(); + return nullptr; + } +} + +} // namespace td diff --git a/td/telegram/NotificationSound.h b/td/telegram/NotificationSound.h new file mode 100644 index 000000000..0a91662e2 --- /dev/null +++ b/td/telegram/NotificationSound.h @@ -0,0 +1,68 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/logevent/LogEvent.h" +#include "td/telegram/NotificationSoundType.h" +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" + +#include "td/utils/common.h" +#include "td/utils/StringBuilder.h" + +namespace td { + +class NotificationSound { + public: + NotificationSound() = default; + NotificationSound(const NotificationSound &) = delete; + NotificationSound &operator=(const NotificationSound &) = delete; + NotificationSound(NotificationSound &&) = delete; + NotificationSound &operator=(NotificationSound &&) = delete; + + virtual NotificationSoundType get_type() const = 0; + virtual ~NotificationSound() = default; + + template + void store(StorerT &storer) const; +}; + +StringBuilder &operator<<(StringBuilder &string_builder, const unique_ptr ¬ification_sound); + +void store_notification_sound(const NotificationSound *notification_sound, LogEventStorerCalcLength &storer); + +void store_notification_sound(const NotificationSound *notification_sound, LogEventStorerUnsafe &storer); + +template +void NotificationSound::store(StorerT &storer) const { + store_notification_sound(this, storer); +} + +void parse_notification_sound(unique_ptr ¬ification_sound, LogEventParser &parser); + +bool is_notification_sound_default(const unique_ptr ¬ification_sound); + +bool are_equivalent_notification_sounds(const unique_ptr &lhs, + const unique_ptr &rhs); + +bool are_different_equivalent_notification_sounds(const unique_ptr &lhs, + const unique_ptr &rhs); + +int64 get_notification_sound_ringtone_id(const unique_ptr ¬ification_sound); + +unique_ptr get_legacy_notification_sound(const string &sound); + +unique_ptr get_notification_sound(bool use_default_sound, int64 ringtone_id); + +unique_ptr get_notification_sound(telegram_api::NotificationSound *notification_sound); + +telegram_api::object_ptr get_input_notification_sound( + const unique_ptr ¬ification_sound); + +unique_ptr dup_notification_sound(const unique_ptr ¬ification_sound); + +} // namespace td diff --git a/td/telegram/NotificationSoundType.h b/td/telegram/NotificationSoundType.h new file mode 100644 index 000000000..374139eea --- /dev/null +++ b/td/telegram/NotificationSoundType.h @@ -0,0 +1,15 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/utils/common.h" + +namespace td { + +enum class NotificationSoundType : int32 { None, Local, Ringtone }; + +} // namespace td diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index e77c0e47a..d6a3df3d4 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -4498,17 +4498,17 @@ class CliClient final : public Actor { } else if (op == "scns" || op == "ssns") { string chat_id_or_scope; string mute_for; - string sound; + int64 ringtone_id; string show_preview; string disable_pinned_message_notifications; string disable_mention_notifications; - get_args(args, chat_id_or_scope, mute_for, sound, show_preview, disable_pinned_message_notifications, + get_args(args, chat_id_or_scope, mute_for, ringtone_id, show_preview, disable_pinned_message_notifications, disable_mention_notifications); if (op == "scns") { send_request(td_api::make_object( as_chat_id(chat_id_or_scope), td_api::make_object( - mute_for.empty(), to_integer(mute_for), sound.empty(), sound, show_preview.empty(), + mute_for.empty(), to_integer(mute_for), ringtone_id == -1, ringtone_id, show_preview.empty(), as_bool(show_preview), disable_pinned_message_notifications.empty(), as_bool(disable_pinned_message_notifications), disable_mention_notifications.empty(), as_bool(disable_mention_notifications)))); @@ -4516,7 +4516,7 @@ class CliClient final : public Actor { send_request(td_api::make_object( get_notification_settings_scope(chat_id_or_scope), td_api::make_object( - to_integer(mute_for), sound, as_bool(show_preview), + to_integer(mute_for), ringtone_id, as_bool(show_preview), as_bool(disable_pinned_message_notifications), as_bool(disable_mention_notifications)))); } } else if (op == "rans") {