diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 0144e762..f8502489 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2112,13 +2112,16 @@ backgroundTypePattern is_moving:Bool color:int32 intensity:int32 = BackgroundTyp //@description A solid background @color A color of the background in RGB24 format backgroundTypeSolid color:int32 = BackgroundType; +//@description A gradient background @top_color A top color of the background in RGB24 format @bottom_color A bottom color of the background in RGB24 format +backgroundTypeGradient top_color:int32 bottom_color:int32 = BackgroundType; + //@description Describes a chat background //@id Unique background identifier //@is_default True, if this is one of default backgrounds //@is_dark True, if the background is dark and is recommended to be used with dark theme //@name Unique background name -//@document Document with the background; may be null. Null only for solid backgrounds +//@document Document with the background; may be null. Null only for solid and gradient backgrounds //@type Type of the background background id:int64 is_default:Bool is_dark:Bool name:string document:document type:BackgroundType = Background; @@ -3956,7 +3959,7 @@ getBackgroundUrl name:string type:BackgroundType = HttpUrl; searchBackground name:string = Background; //@description Changes the background selected by the user; adds background to the list of installed backgrounds -//@background The input background to use, null for solid backgrounds +//@background The input background to use, null for solid and gradient backgrounds //@type Background type; null for default background. The method will return error 404 if type is null //@for_dark_theme True, if the background is chosen for dark theme setBackground background:InputBackground type:BackgroundType for_dark_theme:Bool = Background; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 8801797e..a6329b14 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/BackgroundManager.cpp b/td/telegram/BackgroundManager.cpp index f834ddfa..aa049732 100644 --- a/td/telegram/BackgroundManager.cpp +++ b/td/telegram/BackgroundManager.cpp @@ -325,7 +325,8 @@ void BackgroundManager::start_up() { log_event_parse(logevent, logevent_string).ensure(); CHECK(logevent.background_.id.is_valid()); - bool needs_file_id = (logevent.background_.type.type != BackgroundType::Type::Solid); + bool needs_file_id = (logevent.background_.type.type != BackgroundType::Type::Solid && + logevent.background_.type.type != BackgroundType::Type::Gradient); if (logevent.background_.file_id.is_valid() != needs_file_id) { LOG(ERROR) << "Failed to load " << logevent.background_.id << " of " << logevent.background_.type; G()->td_db()->get_binlog_pmc()->erase(get_background_database_key(for_dark_theme)); @@ -393,6 +394,9 @@ Result BackgroundManager::get_background_url(const string &name, case BackgroundType::Type::Solid: url += type.get_color_hex_string(); return url; + case BackgroundType::Type::Gradient: + url += type.get_color_hex_string() + '-' + BackgroundType::get_color_hex_string(type.intensity); + return url; default: UNREACHABLE(); return url; @@ -427,15 +431,29 @@ BackgroundId BackgroundManager::search_background(const string &name, Promise 6 || i + 7 < name.size()) { + promise.set_error(Status::Error(400, "WALLPAPER_INVALID")); + return BackgroundId(); + } + have_hyphen = true; + hyphen_pos = i; } } - int32 color = static_cast(hex_to_integer(name)); - auto background_id = add_solid_background(color); + BackgroundId background_id; + if (have_hyphen) { + int32 top_color = static_cast(hex_to_integer(name.substr(0, hyphen_pos))); + int32 bottom_color = static_cast(hex_to_integer(name.substr(hyphen_pos + 1))); + background_id = add_gradient_background(top_color, bottom_color); + } else { + int32 color = static_cast(hex_to_integer(name)); + background_id = add_solid_background(color); + } promise.set_value(Unit()); return background_id; } @@ -468,14 +486,15 @@ void BackgroundManager::on_load_background_from_database(string name, string val loaded_from_database_backgrounds_.insert(name); - CHECK(name.size() > 6); + CHECK(name.size() > 13); if (name_to_background_id_.count(name) == 0 && !value.empty()) { LOG(INFO) << "Successfully loaded background " << name << " of size " << value.size() << " from database"; Background background; auto status = log_event_parse(background, value); - if (status.is_error() || background.type.type == BackgroundType::Type::Solid || !background.file_id.is_valid() || + if (status.is_error() || background.type.type == BackgroundType::Type::Solid || + background.type.type == BackgroundType::Type::Gradient || !background.file_id.is_valid() || !background.id.is_valid()) { - LOG(ERROR) << "Can't load bacground " << name << ": " << status << ' ' << format::as_hex_dump<4>(Slice(value)); + LOG(ERROR) << "Can't load background " << name << ": " << status << ' ' << format::as_hex_dump<4>(Slice(value)); } else { if (background.name != name) { LOG(ERROR) << "Expected background " << name << ", but received " << background.name; @@ -533,6 +552,24 @@ BackgroundId BackgroundManager::add_solid_background(int32 color) { return background_id; } +BackgroundId BackgroundManager::add_gradient_background(int32 top_color, int32 bottom_color) { + CHECK(0 <= top_color && top_color < 0x1000000); + CHECK(0 <= bottom_color && bottom_color < 0x1000000); + BackgroundId background_id((static_cast(top_color) << 24) + bottom_color + 1); + + Background background; + background.id = background_id; + background.is_creator = true; + background.is_default = false; + background.is_dark = (top_color & 0x808080) == 0 && (bottom_color & 0x808080) == 0; + background.type = BackgroundType(top_color, bottom_color); + background.name = + BackgroundType::get_color_hex_string(top_color) + "-" + BackgroundType::get_color_hex_string(bottom_color); + add_background(background); + + return background_id; +} + BackgroundId BackgroundManager::set_background(const td_api::InputBackground *input_background, const td_api::BackgroundType *background_type, bool for_dark_theme, Promise &&promise) { @@ -557,6 +594,14 @@ BackgroundId BackgroundManager::set_background(const td_api::InputBackground *in promise.set_value(Unit()); return background_id; } + if (type.type == BackgroundType::Type::Gradient) { + auto background_id = add_gradient_background(type.color, type.intensity); + if (set_background_id_[for_dark_theme] != background_id) { + set_background_id(background_id, type, for_dark_theme); + } + promise.set_value(Unit()); + return background_id; + } if (input_background == nullptr) { promise.set_error(Status::Error(400, "Input background must be non-empty")); @@ -753,7 +798,7 @@ void BackgroundManager::remove_background(BackgroundId background_id, Promisetype.type == BackgroundType::Type::Solid) { + if (background->type.type == BackgroundType::Type::Solid || background->type.type == BackgroundType::Type::Gradient) { return query_promise.set_value(Unit()); } @@ -828,7 +873,7 @@ void BackgroundManager::add_background(const Background &background) { result->name = background.name; - if (result->name.size() > 6) { + if (result->name.size() > 13) { name_to_background_id_.emplace(result->name, result->id); loaded_from_database_backgrounds_.erase(result->name); // don't needed anymore } @@ -863,7 +908,7 @@ void BackgroundManager::add_background(const Background &background) { file_id_to_background_id_.emplace(result->file_id, result->id); } else { // if file_source_id is valid, then this is a new background with result->file_id == FileId() - // then background.file_id == FileId(), then this is a solid background, which can't have file_source_id + // then background.file_id == FileId(), then this is a solid or a gradient background, which can't have file_source_id CHECK(!file_source_id.is_valid()); } } @@ -903,7 +948,7 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou if (expected_background_id.is_valid() && id != expected_background_id) { LOG(ERROR) << "Expected " << expected_background_id << ", but receive " << to_string(wallpaper); } - if (wallpaper->slug_.size() <= 6 || (0 < wallpaper->id_ && wallpaper->id_ <= 0x1000000)) { + if (wallpaper->slug_.size() <= 13 || (0 < wallpaper->id_ && wallpaper->id_ <= 0x1000000000000)) { LOG(ERROR) << "Receive " << to_string(wallpaper); return BackgroundId(); } @@ -943,7 +988,7 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou name_to_background_id_.emplace(expected_background_name, id); } - if (G()->parameters().use_file_db && background.name.size() > 6) { + if (G()->parameters().use_file_db && background.name.size() > 13) { LOG(INFO) << "Save " << id << " to database with name " << background.name; G()->td_db()->get_sqlite_pmc()->set(get_background_name_database_key(background.name), log_event_store(background).as_slice().str(), Auto()); diff --git a/td/telegram/BackgroundManager.h b/td/telegram/BackgroundManager.h index 0ce5cacc..b3bd1d30 100644 --- a/td/telegram/BackgroundManager.h +++ b/td/telegram/BackgroundManager.h @@ -106,6 +106,8 @@ class BackgroundManager : public Actor { BackgroundId add_solid_background(int32 color); + BackgroundId add_gradient_background(int32 top_color, int32 bottom_color); + void add_background(const Background &background); Background *get_background_ref(BackgroundId background_id); diff --git a/td/telegram/BackgroundType.cpp b/td/telegram/BackgroundType.cpp index 408ecc11..3051573c 100644 --- a/td/telegram/BackgroundType.cpp +++ b/td/telegram/BackgroundType.cpp @@ -10,7 +10,7 @@ namespace td { -string BackgroundType::get_color_hex_string() const { +string BackgroundType::get_color_hex_string(int32 color) { string result; for (int i = 20; i >= 0; i -= 4) { result += "0123456789abcdef"[(color >> i) & 0xf]; @@ -18,6 +18,10 @@ string BackgroundType::get_color_hex_string() const { return result; } +string BackgroundType::get_color_hex_string() const { + return get_color_hex_string(color); +} + bool operator==(const BackgroundType &lhs, const BackgroundType &rhs) { return lhs.type == rhs.type && lhs.is_blurred == rhs.is_blurred && lhs.is_moving == rhs.is_moving && lhs.color == rhs.color && lhs.intensity == rhs.intensity; @@ -33,6 +37,9 @@ StringBuilder &operator<<(StringBuilder &string_builder, const BackgroundType &t << ' ' << type.intensity << ']'; case BackgroundType::Type::Solid: return string_builder << "type Solid[" << type.get_color_hex_string() << ']'; + case BackgroundType::Type::Gradient: + return string_builder << "type Gradient[" << type.get_color_hex_string() << '-' + << type.get_color_hex_string(type.intensity) << ']'; default: UNREACHABLE(); return string_builder; @@ -61,11 +68,22 @@ Result get_background_type(const td_api::BackgroundType *type) { result = BackgroundType(solid->color_); break; } + case td_api::backgroundTypeGradient::ID: { + auto gradient = static_cast(type); + result = BackgroundType(gradient->top_color_, gradient->bottom_color_); + break; + } default: UNREACHABLE(); } - if (result.intensity < 0 || result.intensity > 100) { - return Status::Error(400, "Wrong intensity value"); + if (result.type == BackgroundType::Type::Gradient) { + if (result.intensity < 0 || result.intensity > 0xFFFFFF) { + return Status::Error(400, "Wrong bottom color value"); + } + } else { + if (result.intensity < 0 || result.intensity > 100) { + return Status::Error(400, "Wrong intensity value"); + } } if (result.color < 0 || result.color > 0xFFFFFF) { return Status::Error(400, "Wrong color value"); @@ -113,6 +131,8 @@ td_api::object_ptr get_background_type_object(const Back return td_api::make_object(type.is_moving, type.color, type.intensity); case BackgroundType::Type::Solid: return td_api::make_object(type.color); + case BackgroundType::Type::Gradient: + return td_api::make_object(type.color, type.intensity); default: UNREACHABLE(); return nullptr; @@ -139,6 +159,7 @@ telegram_api::object_ptr get_input_wallpaper_se return telegram_api::make_object(flags, false /*ignored*/, false /*ignored*/, type.color, type.intensity); case BackgroundType::Type::Solid: + case BackgroundType::Type::Gradient: default: UNREACHABLE(); return nullptr; diff --git a/td/telegram/BackgroundType.h b/td/telegram/BackgroundType.h index a2ed240c..6b8af84b 100644 --- a/td/telegram/BackgroundType.h +++ b/td/telegram/BackgroundType.h @@ -16,7 +16,7 @@ namespace td { struct BackgroundType { - enum class Type : int32 { Wallpaper, Pattern, Solid }; + enum class Type : int32 { Wallpaper, Pattern, Solid, Gradient }; Type type = Type::Solid; bool is_blurred = false; bool is_moving = false; @@ -32,8 +32,13 @@ struct BackgroundType { } explicit BackgroundType(int32 color) : type(Type::Solid), color(color) { } + BackgroundType(int32 top_color, int32 bottom_color) + : type(Type::Gradient), color(top_color), intensity(bottom_color) { + } string get_color_hex_string() const; + + static string get_color_hex_string(int32 color); }; bool operator==(const BackgroundType &lhs, const BackgroundType &rhs); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 8c0ad6f2..56af732f 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2102,6 +2102,9 @@ class CliClient final : public Actor { send_get_background_url(td_api::make_object(-1)); send_get_background_url(td_api::make_object(0xABCDEF)); send_get_background_url(td_api::make_object(0x1000000)); + send_get_background_url(td_api::make_object(0xABCDEF, 0xFEDCBA)); + send_get_background_url(td_api::make_object(0, 0)); + send_get_background_url(td_api::make_object(-1, -1)); } else if (op == "sbg") { send_request(td_api::make_object(args)); } else if (op == "sbgd") { @@ -2117,6 +2120,13 @@ class CliClient final : public Actor { } else if (op == "sbgs" || op == "sbgsd") { send_request(td_api::make_object( nullptr, td_api::make_object(to_integer(args)), op == "sbgsd")); + } else if (op == "sbgg" || op == "sbggd") { + string top_color; + string bottom_color; + std::tie(top_color, bottom_color) = split(args); + auto background_type = td_api::make_object(to_integer(top_color), + to_integer(bottom_color)); + send_request(td_api::make_object(nullptr, std::move(background_type), op == "sbggd")); } else if (op == "sbgwid" || op == "sbgwidd") { send_request(td_api::make_object( td_api::make_object(to_integer(args)),