From 83e55b6b56f1125026cc2ccf545d29a7b4727303 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 27 Aug 2021 15:51:50 +0300 Subject: [PATCH] Add td_api::getChatThemes. --- CMakeLists.txt | 2 + SplitSource.php | 1 + td/generate/scheme/td_api.tl | 22 +++++ td/telegram/Global.h | 9 ++ td/telegram/Td.cpp | 27 ++++++ td/telegram/Td.h | 5 + td/telegram/ThemeManager.cpp | 176 +++++++++++++++++++++++++++++++++++ td/telegram/ThemeManager.h | 75 +++++++++++++++ td/telegram/cli.cpp | 2 + 9 files changed, 319 insertions(+) create mode 100644 td/telegram/ThemeManager.cpp create mode 100644 td/telegram/ThemeManager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f4426793..7d0fd8b0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,6 +403,7 @@ set(TDLIB_SOURCE td/telegram/Td.cpp td/telegram/TdDb.cpp td/telegram/TermsOfService.cpp + td/telegram/ThemeManager.cpp td/telegram/TopDialogManager.cpp td/telegram/UpdatesManager.cpp td/telegram/Venue.cpp @@ -619,6 +620,7 @@ set(TDLIB_SOURCE td/telegram/TdDb.h td/telegram/TdParameters.h td/telegram/TermsOfService.h + td/telegram/ThemeManager.h td/telegram/TopDialogCategory.h td/telegram/TopDialogManager.h td/telegram/UniqueId.h diff --git a/SplitSource.php b/SplitSource.php index fdb492b55..c8d860e4a 100644 --- a/SplitSource.php +++ b/SplitSource.php @@ -302,6 +302,7 @@ function split_file($file, $chunks, $undo) { 'secret_chats_manager[_(-][^.]|SecretChatsManager' => 'SecretChatsManager', 'stickers_manager[_(-][^.]|StickersManager' => 'StickersManager', '[>](td_db[(][)]|get_td_db_impl[(])|TdDb[^A-Za-z]' => 'TdDb', + 'theme_manager[_(-][^.]|ThemeManager' => "ThemeManager", 'TopDialogCategory|get_top_dialog_category' => 'TopDialogCategory', 'top_dialog_manager[_(-][^.]|TopDialogManager' => 'TopDialogManager', 'updates_manager[_(-][^.]|UpdatesManager|get_difference[)]|updateSentMessage|dummyUpdate' => 'UpdatesManager', diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 658930f72..dfe664563 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2719,6 +2719,24 @@ inputBackgroundLocal background:InputFile = InputBackground; inputBackgroundRemote background_id:int64 = InputBackground; +//@description Describes theme settings +//@accent_color Theme accent color in ARGB format +//@background The background to be used in chats; may be null +//@message_fill The fill to be used as a background for outgoing messages +//@animate_message_fill If true, the freeform gradient fill needs to be animated on every sent message +themeSettings accent_color:int32 background:background message_fill:BackgroundFill animate_message_fill:Bool = ThemeSettings; + + +//@description Describes a chat theme +//@name Theme name +//@light_settings Theme settings for a light chat theme +//@dark_settings Theme settings for a dark chat theme +chatTheme name:string light_settings:themeSettings dark_settings:themeSettings = ChatTheme; + +//@description Contains a list of chat themes @chat_themes A list of chat themes +chatThemes chat_themes:vector = ChatThemes; + + //@description Contains a list of hashtags @hashtags A list of hashtags hashtags hashtags:vector = Hashtags; @@ -5232,6 +5250,10 @@ removeBackground background_id:int64 = Ok; resetBackgrounds = Ok; +//@description Returns the list of available chat themes +getChatThemes = ChatThemes; + + //@description Returns information about the current localization target. This is an offline request if only_local is true. Can be called before authorization @only_local If true, returns only locally available information without sending network requests getLocalizationTargetInfo only_local:Bool = LocalizationTargetInfo; diff --git a/td/telegram/Global.h b/td/telegram/Global.h index ee4bbf17d..b40bb6552 100644 --- a/td/telegram/Global.h +++ b/td/telegram/Global.h @@ -53,6 +53,7 @@ class StorageManager; class Td; class TdDb; class TempAuthKeyWatchdog; +class ThemeManager; class TopDialogManager; class UpdatesManager; class WebPagesManager; @@ -280,6 +281,13 @@ class Global final : public ActorContext { storage_manager_ = storage_manager; } + ActorId theme_manager() const { + return theme_manager_; + } + void set_theme_manager(ActorId theme_manager) { + theme_manager_ = theme_manager; + } + ActorId top_dialog_manager() const { return top_dialog_manager_; } @@ -410,6 +418,7 @@ class Global final : public ActorContext { ActorId secret_chats_manager_; ActorId stickers_manager_; ActorId storage_manager_; + ActorId theme_manager_; ActorId top_dialog_manager_; ActorId updates_manager_; ActorId web_pages_manager_; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index ab15aba8d..2d1cc7627 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -97,6 +97,7 @@ #include "td/telegram/StorageManager.h" #include "td/telegram/SuggestedAction.h" #include "td/telegram/TdDb.h" +#include "td/telegram/ThemeManager.h" #include "td/telegram/TopDialogCategory.h" #include "td/telegram/TopDialogManager.h" #include "td/telegram/UpdatesManager.h" @@ -2909,6 +2910,20 @@ class SetBackgroundRequest final : public RequestActor<> { } }; +class GetChatThemesRequest final : public RequestOnceActor { + void do_run(Promise &&promise) final { + td->theme_manager_->get_chat_themes(std::move(promise)); + } + + void do_send_result() final { + send_result(td->theme_manager_->get_chat_themes_object()); + } + + public: + GetChatThemesRequest(ActorShared td, uint64 request_id) : RequestOnceActor(std::move(td), request_id) { + } +}; + Td::Td(unique_ptr callback, Options options) : callback_(std::move(callback)), td_options_(std::move(options)) { CHECK(callback_ != nullptr); @@ -3730,6 +3745,8 @@ void Td::dec_actor_refcnt() { LOG(DEBUG) << "PollManager was cleared" << timer; stickers_manager_.reset(); LOG(DEBUG) << "StickersManager was cleared" << timer; + theme_manager_.reset(); + LOG(DEBUG) << "ThemeManager was cleared" << timer; updates_manager_.reset(); LOG(DEBUG) << "UpdatesManager was cleared" << timer; video_notes_manager_.reset(); @@ -3918,6 +3935,8 @@ void Td::clear() { LOG(DEBUG) << "PollManager actor was cleared" << timer; stickers_manager_actor_.reset(); LOG(DEBUG) << "StickersManager actor was cleared" << timer; + theme_manager_actor_.reset(); + LOG(DEBUG) << "ThemeManager actor was cleared" << timer; updates_manager_actor_.reset(); LOG(DEBUG) << "UpdatesManager actor was cleared" << timer; web_pages_manager_actor_.reset(); @@ -4370,6 +4389,9 @@ void Td::init_managers() { stickers_manager_ = make_unique(this, create_reference()); stickers_manager_actor_ = register_actor("StickersManager", stickers_manager_.get()); G()->set_stickers_manager(stickers_manager_actor_.get()); + theme_manager_ = make_unique(this, create_reference()); + theme_manager_actor_ = register_actor("ThemeManager", theme_manager_.get()); + G()->set_theme_manager(theme_manager_actor_.get()); updates_manager_ = make_unique(this, create_reference()); updates_manager_actor_ = register_actor("UpdatesManager", updates_manager_.get()); G()->set_updates_manager(updates_manager_actor_.get()); @@ -8069,6 +8091,11 @@ void Td::on_request(uint64 id, const td_api::resetBackgrounds &request) { background_manager_->reset_backgrounds(std::move(promise)); } +void Td::on_request(uint64 id, const td_api::getChatThemes &request) { + CHECK_IS_USER(); + CREATE_NO_ARGS_REQUEST(GetChatThemesRequest); +} + void Td::on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.referrer_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index f8a0332a9..8b8c9eb39 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -67,6 +67,7 @@ class SecureManager; class SecretChatsManager; class StickersManager; class StorageManager; +class ThemeManager; class TopDialogManager; class UpdatesManager; class VideoNotesManager; @@ -171,6 +172,8 @@ class Td final : public NetQueryCallback { ActorOwn poll_manager_actor_; unique_ptr stickers_manager_; ActorOwn stickers_manager_actor_; + unique_ptr theme_manager_; + ActorOwn theme_manager_actor_; unique_ptr updates_manager_; ActorOwn updates_manager_actor_; unique_ptr web_pages_manager_; @@ -1168,6 +1171,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::resetBackgrounds &request); + void on_request(uint64 id, const td_api::getChatThemes &request); + void on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request); void on_request(uint64 id, td_api::setBotUpdatesStatus &request); diff --git a/td/telegram/ThemeManager.cpp b/td/telegram/ThemeManager.cpp new file mode 100644 index 000000000..61fa1b578 --- /dev/null +++ b/td/telegram/ThemeManager.cpp @@ -0,0 +1,176 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// 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/ThemeManager.h" + +#include "td/telegram/BackgroundManager.h" +#include "td/telegram/Global.h" +#include "td/telegram/net/NetQueryCreator.h" +#include "td/telegram/Td.h" + +#include "td/utils/algorithm.h" +#include "td/utils/buffer.h" + +namespace td { + +class GetChatThemesQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit GetChatThemesQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(int32 hash) { + send_query(G()->net_query_creator().create(telegram_api::account_getChatThemes(hash))); + } + + void on_result(uint64 id, BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + promise_.set_value(result_ptr.move_as_ok()); + } + + void on_error(uint64 id, Status status) final { + promise_.set_error(std::move(status)); + } +}; + +ThemeManager::ThemeManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { +} + +void ThemeManager::tear_down() { + parent_.reset(); +} + +void ThemeManager::get_chat_themes(Promise &&promise) { + pending_get_chat_themes_queries_.push_back(std::move(promise)); + if (pending_get_chat_themes_queries_.size() == 1) { + auto request_promise = PromiseCreator::lambda( + [actor_id = actor_id(this)](Result> result) { + send_closure(actor_id, &ThemeManager::on_get_chat_themes, std::move(result)); + }); + + td_->create_handler(std::move(request_promise))->send(chat_themes_.hash); + } +} + +td_api::object_ptr ThemeManager::get_theme_settings_object(const ThemeSettings &settings) const { + auto fill = [colors = settings.message_colors]() mutable -> td_api::object_ptr { + if (colors.size() >= 3) { + return td_api::make_object(std::move(colors)); + } + CHECK(!colors.empty()); + if (colors.size() == 1 || colors[0] == colors[1]) { + return td_api::make_object(colors[0]); + } + return td_api::make_object(colors[1], colors[0], 0); + }(); + + // ignore settings.base_theme for now + return td_api::make_object( + settings.accent_color, + td_->background_manager_->get_background_object(settings.background_id, false, &settings.background_type), + std::move(fill), settings.animate_message_colors); +} + +td_api::object_ptr ThemeManager::get_chat_theme_object(const ChatTheme &theme) const { + return td_api::make_object(theme.emoji, get_theme_settings_object(theme.light_theme), + get_theme_settings_object(theme.dark_theme)); +} + +td_api::object_ptr ThemeManager::get_chat_themes_object() const { + return td_api::make_object( + transform(chat_themes_.themes, [this](const ChatTheme &theme) { return get_chat_theme_object(theme); })); +} + +void ThemeManager::on_get_chat_themes(Result> result) { + auto promises = std::move(pending_get_chat_themes_queries_); + CHECK(!promises.empty()); + reset_to_empty(pending_get_chat_themes_queries_); + + if (result.is_error()) { + // do not clear chat_themes_ + + auto error = result.move_as_error(); + for (auto &promise : promises) { + promise.set_error(error.clone()); + } + return; + } + + auto chat_themes_ptr = result.move_as_ok(); + LOG(DEBUG) << "Receive " << to_string(chat_themes_ptr); + if (chat_themes_ptr->get_id() == telegram_api::account_chatThemesNotModified::ID) { + for (auto &promise : promises) { + promise.set_value(Unit()); + } + return; + } + + auto chat_themes = telegram_api::move_object_as(chat_themes_ptr); + LOG(INFO) << "Receive " << to_string(chat_themes); + chat_themes_.hash = chat_themes->hash_; + chat_themes_.themes.clear(); + for (auto &chat_theme : chat_themes->themes_) { + if (chat_theme->emoticon_.empty()) { + LOG(ERROR) << "Receive " << to_string(chat_theme); + continue; + } + + ChatTheme theme; + theme.emoji = std::move(chat_theme->emoticon_); + theme.light_theme = get_chat_theme_settings(std::move(chat_theme->theme_->settings_)); + theme.dark_theme = get_chat_theme_settings(std::move(chat_theme->dark_theme_->settings_)); + chat_themes_.themes.push_back(std::move(theme)); + } + + for (auto &promise : promises) { + promise.set_value(Unit()); + } +} + +ThemeManager::BaseTheme ThemeManager::get_base_theme( + const telegram_api::object_ptr &base_theme) { + CHECK(base_theme != nullptr); + switch (base_theme->get_id()) { + case telegram_api::baseThemeClassic::ID: + return BaseTheme::Classic; + case telegram_api::baseThemeDay::ID: + return BaseTheme::Day; + case telegram_api::baseThemeNight::ID: + return BaseTheme::Night; + case telegram_api::baseThemeTinted::ID: + return BaseTheme::Tinted; + case telegram_api::baseThemeArctic::ID: + return BaseTheme::Arctic; + default: + UNREACHABLE(); + return BaseTheme::Classic; + } +} + +ThemeManager::ThemeSettings ThemeManager::get_chat_theme_settings( + telegram_api::object_ptr settings) { + ThemeSettings result; + if (settings != nullptr && 1 <= settings->message_colors_.size() && settings->message_colors_.size() <= 4) { + auto background = + td_->background_manager_->on_get_background(BackgroundId(), string(), std::move(settings->wallpaper_), false); + + result.accent_color = settings->accent_color_; + result.background_id = background.first; + result.background_type = std::move(background.second); + result.base_theme = get_base_theme(settings->base_theme_); + result.message_colors = std::move(settings->message_colors_); + result.animate_message_colors = settings->message_colors_animated_; + } + return result; +} + +} // namespace td diff --git a/td/telegram/ThemeManager.h b/td/telegram/ThemeManager.h new file mode 100644 index 000000000..b7cd0e05e --- /dev/null +++ b/td/telegram/ThemeManager.h @@ -0,0 +1,75 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// 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/BackgroundId.h" +#include "td/telegram/BackgroundType.h" +#include "td/telegram/td.h" +#include "td/telegram/telegram_api.h" + +#include "td/actor/actor.h" +#include "td/actor/PromiseFuture.h" + +#include "td/utils/common.h" +#include "td/utils/Status.h" + +namespace td { + +class Td; + +class ThemeManager final : public Actor { + public: + ThemeManager(Td *td, ActorShared<> parent); + + void get_chat_themes(Promise &&promise); + + td_api::object_ptr get_chat_themes_object() const; + + private: + enum class BaseTheme : int32 { Classic, Day, Night, Tinted, Arctic }; + + struct ThemeSettings { + int32 accent_color = 0; + BackgroundId background_id; + BackgroundType background_type; + BaseTheme base_theme; + vector message_colors; + bool animate_message_colors = false; + }; + + struct ChatTheme { + string emoji; + ThemeSettings light_theme; + ThemeSettings dark_theme; + }; + + struct ChatThemes { + int32 hash = 0; + vector themes; + }; + + void tear_down() final; + + void on_get_chat_themes(Result> result); + + td_api::object_ptr get_theme_settings_object(const ThemeSettings &settings) const; + + td_api::object_ptr get_chat_theme_object(const ChatTheme &theme) const; + + static BaseTheme get_base_theme(const telegram_api::object_ptr &base_theme); + + ThemeSettings get_chat_theme_settings(telegram_api::object_ptr settings); + + vector> pending_get_chat_themes_queries_; + + ChatThemes chat_themes_; + + Td *td_; + ActorShared<> parent_; +}; + +} // namespace td diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index f52081d5d..884723ede 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2287,6 +2287,8 @@ class CliClient final : public Actor { send_request(td_api::make_object(to_integer(args))); } else if (op == "rbgs") { send_request(td_api::make_object()); + } else if (op == "gcts") { + send_request(td_api::make_object()); } else if (op == "gcos") { send_request(td_api::make_object()); } else if (op == "gcoc") {