diff --git a/CMakeLists.txt b/CMakeLists.txt index 719292ea7..aef167b5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -488,6 +488,7 @@ set(TDLIB_SOURCE td/telegram/StateManager.cpp td/telegram/StickersManager.cpp td/telegram/StorageManager.cpp + td/telegram/SuggestedAction.cpp td/telegram/Td.cpp td/telegram/TdDb.cpp td/telegram/TermsOfService.cpp @@ -676,6 +677,7 @@ set(TDLIB_SOURCE td/telegram/StickerSetId.h td/telegram/StickersManager.h td/telegram/StorageManager.h + td/telegram/SuggestedAction.h td/telegram/Td.h td/telegram/TdCallback.h td/telegram/TdDb.h diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index feb454797..ff39e0872 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2860,6 +2860,15 @@ tMeUrl url:string type:TMeUrlType = TMeUrl; tMeUrls urls:vector = TMeUrls; +//@class SuggestedAction @description Describes an action suggested to the current user + +//@description Suggests the user to enable "archive_and_mute_new_chats_from_unknown_users" option +suggestedActionEnableArchiveAndMuteNewChats = SuggestedAction; + +//@description Suggests the user to check authorization phone number and change the phone number if it is inaccessible +suggestedActionCheckPhoneNumber = SuggestedAction; + + //@description Contains a counter @count Count count count:int32 = Count; @@ -3231,6 +3240,9 @@ updateDiceEmojis emojis:vector = Update; //@description The parameters of animation search through GetOption("animation_search_bot_username") bot has changed @provider Name of the animation search provider @emojis The new list of emojis suggested for searching updateAnimationSearchParameters provider:string emojis:vector = Update; +//@description The list of suggested to the user actions has changed @added_actions Added suggested actions @removed_actions Removed suggested actions +updateSuggestedActions added_actions:vector removed_actions:vector = Update; + //@description A new incoming inline query; for bots only @id Unique query identifier @sender_user_id Identifier of the user who sent the query @user_location User location; may be null //@query Text of the query @offset Offset of the first entry to return updateNewInlineQuery id:int64 sender_user_id:int32 user_location:location query:string offset:string = Update; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 34936f698..d2cafd30a 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index d43114479..680ec028c 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -55,6 +55,7 @@ #include "td/utils/tl_parsers.h" #include "td/utils/UInt.h" +#include #include #include #include @@ -1002,6 +1003,9 @@ void ConfigManager::set_archive_and_mute(bool archive_and_mute, Promise && if (G()->close_flag()) { return promise.set_error(Status::Error(500, "Request aborted")); } + if (archive_and_mute) { + do_dismiss_suggested_action(SuggestedAction::EnableArchiveAndMuteNewChats); + } last_set_archive_and_mute_ = archive_and_mute; auto &queries = set_archive_and_mute_queries_[archive_and_mute]; @@ -1044,9 +1048,24 @@ void ConfigManager::do_set_ignore_sensitive_content_restrictions(bool ignore_sen } void ConfigManager::do_set_archive_and_mute(bool archive_and_mute) { + if (archive_and_mute) { + do_dismiss_suggested_action(SuggestedAction::EnableArchiveAndMuteNewChats); + } G()->shared_config().set_option_boolean("archive_and_mute_new_chats_from_unknown_users", archive_and_mute); } +td_api::object_ptr ConfigManager::get_update_suggested_actions( + const vector &added_actions, const vector &removed_actions) { + return td_api::make_object(transform(added_actions, get_suggested_action_object), + transform(removed_actions, get_suggested_action_object)); +} + +void ConfigManager::do_dismiss_suggested_action(SuggestedAction suggested_action) { + if (td::remove(suggested_actions_, suggested_action)) { + send_closure(G()->td(), &Td::send_update, get_update_suggested_actions({}, {suggested_action})); + } +} + void ConfigManager::on_result(NetQueryPtr res) { auto token = get_link_token(); if (token == 6 || token == 7) { @@ -1388,6 +1407,9 @@ void ConfigManager::process_app_config(tl_object_ptr &c CHECK(config != nullptr); LOG(INFO) << "Receive app config " << to_string(config); + const bool archive_and_mute = + G()->shared_config().get_option_boolean("archive_and_mute_new_chats_from_unknown_users"); + vector> new_values; string ignored_restriction_reasons; vector dice_emojis; @@ -1395,6 +1417,7 @@ void ConfigManager::process_app_config(tl_object_ptr &c std::unordered_map dice_emoji_success_value; string animation_search_provider; string animation_search_emojis; + vector suggested_actions; if (config->get_id() == telegram_api::jsonObject::ID) { for (auto &key_value : static_cast(config.get())->value_) { Slice key = key_value->key_; @@ -1516,6 +1539,32 @@ void ConfigManager::process_app_config(tl_object_ptr &c } continue; } + if (key == "pending_suggestions") { + if (value->get_id() == telegram_api::jsonArray::ID) { + auto actions = std::move(static_cast(value)->value_); + for (auto &action : actions) { + CHECK(action != nullptr); + if (action->get_id() == telegram_api::jsonString::ID) { + Slice action_str = static_cast(action.get())->value_; + auto suggested_action = get_suggested_action(action_str); + if (suggested_action != SuggestedAction::Empty) { + if (archive_and_mute && suggested_action == SuggestedAction::EnableArchiveAndMuteNewChats) { + LOG(INFO) << "Skip SuggestedAction::EnableArchiveAndMuteNewChats"; + } else { + suggested_actions.push_back(suggested_action); + } + } else { + LOG(ERROR) << "Receive unsupported suggested action " << action_str; + } + } else { + LOG(ERROR) << "Receive unexpected suggested action " << to_string(action); + } + } + } else { + LOG(ERROR) << "Receive unexpected pending_suggestions " << to_string(*value); + } + continue; + } new_values.push_back(std::move(key_value)); } @@ -1566,6 +1615,37 @@ void ConfigManager::process_app_config(tl_object_ptr &c shared_config.set_option_empty("default_ton_blockchain_config"); shared_config.set_option_empty("default_ton_blockchain_name"); + + if (!is_set_content_settings_request_sent_) { // do not update suggested actions while changing content settings + std::sort(suggested_actions.begin(), suggested_actions.end()); + suggested_actions.erase(std::unique(suggested_actions.begin(), suggested_actions.end()), suggested_actions.end()); + if (suggested_actions != suggested_actions_) { + vector added_actions; + vector removed_actions; + auto old_it = suggested_actions_.begin(); + auto new_it = suggested_actions.begin(); + while (old_it != suggested_actions_.end() || new_it != suggested_actions.end()) { + if (new_it == suggested_actions.end() || std::less()(*old_it, *new_it)) { + removed_actions.push_back(*old_it++); + } else if (old_it == suggested_actions_.end() || std::less()(*new_it, *old_it)) { + added_actions.push_back(*new_it++); + } else { + old_it++; + new_it++; + } + } + CHECK(!added_actions.empty() || !removed_actions.empty()); + suggested_actions_ = std::move(suggested_actions); + send_closure(G()->td(), &Td::send_update, + get_update_suggested_actions(std::move(added_actions), std::move(removed_actions))); + } + } +} + +void ConfigManager::get_current_state(vector> &updates) const { + if (!suggested_actions_.empty()) { + updates.push_back(get_update_suggested_actions(suggested_actions_, {})); + } } } // namespace td diff --git a/td/telegram/ConfigManager.h b/td/telegram/ConfigManager.h index 08998a49e..e789da2d7 100644 --- a/td/telegram/ConfigManager.h +++ b/td/telegram/ConfigManager.h @@ -9,6 +9,7 @@ #include "td/telegram/net/DcId.h" #include "td/telegram/net/DcOptions.h" #include "td/telegram/net/NetQuery.h" +#include "td/telegram/SuggestedAction.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" @@ -96,6 +97,8 @@ class ConfigManager : public NetQueryCallback { void on_dc_options_update(DcOptions dc_options); + void get_current_state(vector> &updates) const; + private: ActorShared<> parent_; int32 config_sent_cnt_{0}; @@ -115,6 +118,8 @@ class ConfigManager : public NetQueryCallback { bool is_set_archive_and_mute_request_sent_ = false; bool last_set_archive_and_mute_ = false; + vector suggested_actions_; + void start_up() override; void hangup_shared() override; void hangup() override; @@ -132,6 +137,11 @@ class ConfigManager : public NetQueryCallback { void do_set_archive_and_mute(bool archive_and_mute); + static td_api::object_ptr get_update_suggested_actions( + const vector &added_actions, const vector &removed_actions); + + void do_dismiss_suggested_action(SuggestedAction suggested_action); + Timestamp load_config_expire_time(); void save_config_expire(Timestamp timestamp); void save_dc_options_update(DcOptions dc_options); diff --git a/td/telegram/SuggestedAction.cpp b/td/telegram/SuggestedAction.cpp new file mode 100644 index 000000000..1da461c2f --- /dev/null +++ b/td/telegram/SuggestedAction.cpp @@ -0,0 +1,56 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// +// 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/SuggestedAction.h" + +namespace td { + +SuggestedAction get_suggested_action(Slice action_str) { + if (action_str == Slice("AUTOARCHIVE_POPULAR")) { + return SuggestedAction::EnableArchiveAndMuteNewChats; + } + return SuggestedAction::Empty; +} + +string get_suggested_action_str(SuggestedAction action) { + switch (action) { + case SuggestedAction::EnableArchiveAndMuteNewChats: + return "AUTOARCHIVE_POPULAR"; + default: + return string(); + } +} + +SuggestedAction get_suggested_action(const td_api::object_ptr &action_object) { + if (action_object == nullptr) { + return SuggestedAction::Empty; + } + switch (action_object->get_id()) { + case td_api::suggestedActionEnableArchiveAndMuteNewChats::ID: + return SuggestedAction::EnableArchiveAndMuteNewChats; + case td_api::suggestedActionCheckPhoneNumber::ID: + return SuggestedAction::CheckPhoneNumber; + default: + UNREACHABLE(); + return SuggestedAction::Empty; + } +} + +td_api::object_ptr get_suggested_action_object(SuggestedAction action) { + switch (action) { + case SuggestedAction::Empty: + return nullptr; + case SuggestedAction::EnableArchiveAndMuteNewChats: + return td_api::make_object(); + case SuggestedAction::CheckPhoneNumber: + return td_api::make_object(); + default: + UNREACHABLE(); + return nullptr; + } +} + +} // namespace td diff --git a/td/telegram/SuggestedAction.h b/td/telegram/SuggestedAction.h new file mode 100644 index 000000000..99a7470f3 --- /dev/null +++ b/td/telegram/SuggestedAction.h @@ -0,0 +1,26 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// +// 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/td_api.h" + +#include "td/utils/common.h" +#include "td/utils/Slice.h" + +namespace td { + +enum class SuggestedAction : int32 { Empty, EnableArchiveAndMuteNewChats, CheckPhoneNumber }; + +SuggestedAction get_suggested_action(Slice action_str); + +string get_suggested_action_str(SuggestedAction action); + +SuggestedAction get_suggested_action(const td_api::object_ptr &action_object); + +td_api::object_ptr get_suggested_action_object(SuggestedAction action); + +} // namespace td diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 442e6fef7..25320f689 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -4831,6 +4831,8 @@ void Td::on_request(uint64 id, const td_api::getCurrentState &request) { notification_manager_->get_current_state(updates); + config_manager_->get_actor_unsafe()->get_current_state(updates); + // TODO updateFileGenerationStart generation_id:int64 original_path:string destination_path:string conversion:string = Update; // TODO updateCall call:call = Update; }