2021-08-27 14:51:50 +02:00
|
|
|
//
|
|
|
|
// 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"
|
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
#include "td/telegram/AuthManager.h"
|
2021-08-27 14:51:50 +02:00
|
|
|
#include "td/telegram/BackgroundManager.h"
|
2021-09-24 16:17:32 +02:00
|
|
|
#include "td/telegram/BackgroundType.hpp"
|
2021-08-27 14:51:50 +02:00
|
|
|
#include "td/telegram/Global.h"
|
|
|
|
#include "td/telegram/net/NetQueryCreator.h"
|
|
|
|
#include "td/telegram/Td.h"
|
2021-09-24 16:17:32 +02:00
|
|
|
#include "td/telegram/TdDb.h"
|
2021-08-27 14:51:50 +02:00
|
|
|
|
|
|
|
#include "td/utils/algorithm.h"
|
|
|
|
#include "td/utils/buffer.h"
|
2021-09-01 19:31:39 +02:00
|
|
|
#include "td/utils/logging.h"
|
2021-09-13 14:55:01 +02:00
|
|
|
#include "td/utils/Random.h"
|
2021-09-08 15:50:03 +02:00
|
|
|
#include "td/utils/Time.h"
|
2021-08-27 14:51:50 +02:00
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
|
|
|
class GetChatThemesQuery final : public Td::ResultHandler {
|
|
|
|
Promise<telegram_api::object_ptr<telegram_api::account_ChatThemes>> promise_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit GetChatThemesQuery(Promise<telegram_api::object_ptr<telegram_api::account_ChatThemes>> &&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<telegram_api::account_getChatThemes>(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));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-09-12 21:39:52 +02:00
|
|
|
bool operator==(const ThemeManager::ThemeSettings &lhs, const ThemeManager::ThemeSettings &rhs) {
|
2021-09-07 21:04:44 +02:00
|
|
|
return lhs.accent_color == rhs.accent_color && lhs.message_accent_color == rhs.message_accent_color &&
|
|
|
|
lhs.background_id == rhs.background_id && lhs.background_type == rhs.background_type &&
|
|
|
|
lhs.base_theme == rhs.base_theme && lhs.message_colors == rhs.message_colors &&
|
|
|
|
lhs.animate_message_colors == rhs.animate_message_colors;
|
2021-09-12 21:39:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const ThemeManager::ThemeSettings &lhs, const ThemeManager::ThemeSettings &rhs) {
|
|
|
|
return !(lhs == rhs);
|
|
|
|
}
|
|
|
|
|
2021-09-24 16:17:32 +02:00
|
|
|
template <class StorerT>
|
|
|
|
void ThemeManager::ThemeSettings::store(StorerT &storer) const {
|
|
|
|
using td::store;
|
|
|
|
bool has_message_accent_color = message_accent_color != accent_color;
|
|
|
|
bool has_background = background_id.is_valid();
|
|
|
|
BEGIN_STORE_FLAGS();
|
|
|
|
STORE_FLAG(animate_message_colors);
|
|
|
|
STORE_FLAG(has_message_accent_color);
|
|
|
|
STORE_FLAG(has_background);
|
|
|
|
END_STORE_FLAGS();
|
|
|
|
store(accent_color, storer);
|
|
|
|
if (has_message_accent_color) {
|
|
|
|
store(message_accent_color, storer);
|
|
|
|
}
|
|
|
|
if (has_background) {
|
|
|
|
storer.context()->td().get_actor_unsafe()->background_manager_->store_background(background_id, storer);
|
|
|
|
store(background_type, storer);
|
|
|
|
}
|
|
|
|
store(base_theme, storer);
|
|
|
|
store(message_colors, storer);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ParserT>
|
|
|
|
void ThemeManager::ThemeSettings::parse(ParserT &parser) {
|
|
|
|
using td::parse;
|
|
|
|
bool has_message_accent_color;
|
|
|
|
bool has_background;
|
|
|
|
BEGIN_PARSE_FLAGS();
|
|
|
|
PARSE_FLAG(animate_message_colors);
|
|
|
|
PARSE_FLAG(has_message_accent_color);
|
|
|
|
PARSE_FLAG(has_background);
|
|
|
|
END_PARSE_FLAGS();
|
|
|
|
parse(accent_color, parser);
|
|
|
|
if (has_message_accent_color) {
|
|
|
|
parse(message_accent_color, parser);
|
|
|
|
} else {
|
|
|
|
message_accent_color = accent_color;
|
|
|
|
}
|
|
|
|
if (has_background) {
|
|
|
|
parser.context()->td().get_actor_unsafe()->background_manager_->parse_background(background_id, parser);
|
|
|
|
parse(background_type, parser);
|
|
|
|
}
|
|
|
|
parse(base_theme, parser);
|
|
|
|
parse(message_colors, parser);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class StorerT>
|
|
|
|
void ThemeManager::ChatTheme::store(StorerT &storer) const {
|
|
|
|
BEGIN_STORE_FLAGS();
|
|
|
|
END_STORE_FLAGS();
|
|
|
|
td::store(emoji, storer);
|
|
|
|
td::store(light_id, storer);
|
|
|
|
td::store(dark_id, storer);
|
|
|
|
td::store(light_theme, storer);
|
|
|
|
td::store(dark_theme, storer);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ParserT>
|
|
|
|
void ThemeManager::ChatTheme::parse(ParserT &parser) {
|
|
|
|
BEGIN_PARSE_FLAGS();
|
|
|
|
END_PARSE_FLAGS();
|
|
|
|
td::parse(emoji, parser);
|
|
|
|
td::parse(light_id, parser);
|
|
|
|
td::parse(dark_id, parser);
|
|
|
|
td::parse(light_theme, parser);
|
|
|
|
td::parse(dark_theme, parser);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class StorerT>
|
|
|
|
void ThemeManager::ChatThemes::store(StorerT &storer) const {
|
|
|
|
td::store(hash, storer);
|
|
|
|
td::store(themes, storer);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ParserT>
|
|
|
|
void ThemeManager::ChatThemes::parse(ParserT &parser) {
|
|
|
|
td::parse(hash, parser);
|
|
|
|
td::parse(themes, parser);
|
|
|
|
}
|
|
|
|
|
2021-08-27 14:51:50 +02:00
|
|
|
ThemeManager::ThemeManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
2021-09-13 14:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeManager::start_up() {
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeManager::init() {
|
|
|
|
if (!td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-24 16:17:32 +02:00
|
|
|
auto log_event_string = G()->td_db()->get_binlog_pmc()->get(get_chat_themes_database_key());
|
|
|
|
if (!log_event_string.empty()) {
|
|
|
|
auto status = log_event_parse(chat_themes_, log_event_string);
|
|
|
|
if (status.is_ok()) {
|
|
|
|
send_update_chat_themes();
|
|
|
|
} else {
|
|
|
|
LOG(ERROR) << "Failed to parse chat themes from binlog: " << status;
|
|
|
|
chat_themes_ = ChatThemes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
chat_themes_.next_reload_time = Time::now();
|
2021-09-13 14:55:01 +02:00
|
|
|
loop();
|
2021-08-27 14:51:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeManager::tear_down() {
|
|
|
|
parent_.reset();
|
|
|
|
}
|
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
void ThemeManager::loop() {
|
|
|
|
if (!td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot()) {
|
|
|
|
return;
|
2021-09-07 12:30:51 +02:00
|
|
|
}
|
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
if (Time::now() < chat_themes_.next_reload_time) {
|
|
|
|
return set_timeout_at(chat_themes_.next_reload_time);
|
2021-09-07 12:30:51 +02:00
|
|
|
}
|
2021-08-27 14:51:50 +02:00
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
auto request_promise = PromiseCreator::lambda(
|
|
|
|
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
|
|
|
|
send_closure(actor_id, &ThemeManager::on_get_chat_themes, std::move(result));
|
|
|
|
});
|
|
|
|
|
|
|
|
td_->create_handler<GetChatThemesQuery>(std::move(request_promise))->send(chat_themes_.hash);
|
2021-08-27 14:51:50 +02:00
|
|
|
}
|
|
|
|
|
2021-09-12 21:29:40 +02:00
|
|
|
void ThemeManager::on_update_theme(telegram_api::object_ptr<telegram_api::theme> &&theme, Promise<Unit> &&promise) {
|
|
|
|
CHECK(theme != nullptr);
|
2021-09-13 14:55:01 +02:00
|
|
|
bool is_changed = false;
|
2021-09-12 21:29:40 +02:00
|
|
|
for (auto &chat_theme : chat_themes_.themes) {
|
|
|
|
if (chat_theme.light_id == theme->id_ || chat_theme.dark_id == theme->id_) {
|
|
|
|
auto theme_settings = get_chat_theme_settings(std::move(theme->settings_));
|
2021-09-07 21:04:44 +02:00
|
|
|
if (theme_settings.message_colors.empty()) {
|
|
|
|
break;
|
|
|
|
}
|
2021-09-12 21:39:52 +02:00
|
|
|
if (chat_theme.light_id == theme->id_ && chat_theme.light_theme != theme_settings) {
|
2021-09-12 21:29:40 +02:00
|
|
|
chat_theme.light_theme = theme_settings;
|
2021-09-13 14:55:01 +02:00
|
|
|
is_changed = true;
|
2021-09-12 21:29:40 +02:00
|
|
|
}
|
2021-09-12 21:39:52 +02:00
|
|
|
if (chat_theme.dark_id == theme->id_ && chat_theme.dark_theme != theme_settings) {
|
2021-09-12 21:29:40 +02:00
|
|
|
chat_theme.dark_theme = theme_settings;
|
2021-09-13 14:55:01 +02:00
|
|
|
is_changed = true;
|
2021-09-12 21:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-13 14:55:01 +02:00
|
|
|
if (is_changed) {
|
2021-09-24 16:17:32 +02:00
|
|
|
save_chat_themes();
|
2021-09-13 14:55:01 +02:00
|
|
|
send_update_chat_themes();
|
|
|
|
}
|
2021-09-12 21:29:40 +02:00
|
|
|
promise.set_value(Unit());
|
|
|
|
}
|
|
|
|
|
2021-08-27 14:51:50 +02:00
|
|
|
td_api::object_ptr<td_api::themeSettings> ThemeManager::get_theme_settings_object(const ThemeSettings &settings) const {
|
|
|
|
auto fill = [colors = settings.message_colors]() mutable -> td_api::object_ptr<td_api::BackgroundFill> {
|
|
|
|
if (colors.size() >= 3) {
|
|
|
|
return td_api::make_object<td_api::backgroundFillFreeformGradient>(std::move(colors));
|
|
|
|
}
|
|
|
|
CHECK(!colors.empty());
|
|
|
|
if (colors.size() == 1 || colors[0] == colors[1]) {
|
|
|
|
return td_api::make_object<td_api::backgroundFillSolid>(colors[0]);
|
|
|
|
}
|
|
|
|
return td_api::make_object<td_api::backgroundFillGradient>(colors[1], colors[0], 0);
|
|
|
|
}();
|
|
|
|
|
|
|
|
// ignore settings.base_theme for now
|
|
|
|
return td_api::make_object<td_api::themeSettings>(
|
|
|
|
settings.accent_color,
|
|
|
|
td_->background_manager_->get_background_object(settings.background_id, false, &settings.background_type),
|
2021-09-07 21:04:44 +02:00
|
|
|
std::move(fill), settings.animate_message_colors, settings.message_accent_color);
|
2021-08-27 14:51:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
td_api::object_ptr<td_api::chatTheme> ThemeManager::get_chat_theme_object(const ChatTheme &theme) const {
|
|
|
|
return td_api::make_object<td_api::chatTheme>(theme.emoji, get_theme_settings_object(theme.light_theme),
|
|
|
|
get_theme_settings_object(theme.dark_theme));
|
|
|
|
}
|
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
td_api::object_ptr<td_api::updateChatThemes> ThemeManager::get_update_chat_themes_object() const {
|
|
|
|
return td_api::make_object<td_api::updateChatThemes>(
|
2021-08-27 14:51:50 +02:00
|
|
|
transform(chat_themes_.themes, [this](const ChatTheme &theme) { return get_chat_theme_object(theme); }));
|
|
|
|
}
|
|
|
|
|
2021-09-24 16:17:32 +02:00
|
|
|
string ThemeManager::get_chat_themes_database_key() {
|
|
|
|
return "chat_themes";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeManager::save_chat_themes() {
|
|
|
|
G()->td_db()->get_binlog_pmc()->set(get_chat_themes_database_key(), log_event_store(chat_themes_).as_slice().str());
|
|
|
|
}
|
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
void ThemeManager::send_update_chat_themes() const {
|
|
|
|
send_closure(G()->td(), &Td::send_update, get_update_chat_themes_object());
|
|
|
|
}
|
2021-08-27 14:51:50 +02:00
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
void ThemeManager::on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
|
2021-08-27 14:51:50 +02:00
|
|
|
if (result.is_error()) {
|
2021-09-13 14:55:01 +02:00
|
|
|
set_timeout_in(Random::fast(40, 60));
|
2021-08-27 14:51:50 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-07 12:30:51 +02:00
|
|
|
chat_themes_.next_reload_time = Time::now() + THEME_CACHE_TIME;
|
2021-09-13 14:55:01 +02:00
|
|
|
set_timeout_at(chat_themes_.next_reload_time);
|
2021-09-07 12:30:51 +02:00
|
|
|
|
2021-08-27 14:51:50 +02:00
|
|
|
auto chat_themes_ptr = result.move_as_ok();
|
|
|
|
LOG(DEBUG) << "Receive " << to_string(chat_themes_ptr);
|
2021-09-13 14:55:01 +02:00
|
|
|
if (chat_themes_ptr->get_id() == telegram_api::account_chatThemesNotModified::ID) {
|
|
|
|
return;
|
2021-08-27 14:51:50 +02:00
|
|
|
}
|
2021-09-13 14:55:01 +02:00
|
|
|
CHECK(chat_themes_ptr->get_id() == telegram_api::account_chatThemes::ID);
|
|
|
|
auto chat_themes = telegram_api::move_object_as<telegram_api::account_chatThemes>(chat_themes_ptr);
|
|
|
|
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;
|
|
|
|
}
|
2021-08-27 14:51:50 +02:00
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
ChatTheme theme;
|
|
|
|
theme.emoji = std::move(chat_theme->emoticon_);
|
|
|
|
theme.light_id = chat_theme->theme_->id_;
|
|
|
|
theme.dark_id = chat_theme->dark_theme_->id_;
|
|
|
|
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_));
|
|
|
|
if (theme.light_theme.message_colors.empty() || theme.dark_theme.message_colors.empty()) {
|
|
|
|
continue;
|
2021-09-07 12:30:51 +02:00
|
|
|
}
|
2021-09-13 14:55:01 +02:00
|
|
|
chat_themes_.themes.push_back(std::move(theme));
|
2021-08-27 14:51:50 +02:00
|
|
|
}
|
2021-09-13 14:55:01 +02:00
|
|
|
|
2021-09-24 16:17:32 +02:00
|
|
|
save_chat_themes();
|
2021-09-13 14:55:01 +02:00
|
|
|
send_update_chat_themes();
|
2021-08-27 14:51:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ThemeManager::BaseTheme ThemeManager::get_base_theme(
|
|
|
|
const telegram_api::object_ptr<telegram_api::BaseTheme> &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<telegram_api::themeSettings> settings) {
|
|
|
|
ThemeSettings result;
|
2021-09-01 19:31:39 +02:00
|
|
|
if (settings != nullptr && !settings->message_colors_.empty() && settings->message_colors_.size() <= 4) {
|
2021-08-27 14:51:50 +02:00
|
|
|
auto background =
|
|
|
|
td_->background_manager_->on_get_background(BackgroundId(), string(), std::move(settings->wallpaper_), false);
|
|
|
|
|
|
|
|
result.accent_color = settings->accent_color_;
|
2021-09-07 21:04:44 +02:00
|
|
|
bool has_outbox_accent_color = (settings->flags_ & telegram_api::themeSettings::OUTBOX_ACCENT_COLOR_MASK) != 0;
|
|
|
|
result.message_accent_color = (has_outbox_accent_color ? settings->outbox_accent_color_ : result.accent_color);
|
2021-08-27 14:51:50 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-09-13 14:55:01 +02:00
|
|
|
void ThemeManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
|
|
|
|
if (!td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot() || chat_themes_.themes.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
updates.push_back(get_update_chat_themes_object());
|
|
|
|
}
|
|
|
|
|
2021-08-27 14:51:50 +02:00
|
|
|
} // namespace td
|