diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index d85a5e306..8745365c1 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -130,6 +130,8 @@ PRIVATE api/api_messages_search.h api/api_messages_search_merged.cpp api/api_messages_search_merged.h + api/api_peer_colors.cpp + api/api_peer_colors.h api/api_peer_photo.cpp api/api_peer_photo.h api/api_polls.cpp diff --git a/Telegram/SourceFiles/api/api_peer_colors.cpp b/Telegram/SourceFiles/api/api_peer_colors.cpp new file mode 100644 index 000000000..85d60d814 --- /dev/null +++ b/Telegram/SourceFiles/api/api_peer_colors.cpp @@ -0,0 +1,126 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "api/api_peer_colors.h" + +#include "apiwrap.h" +#include "ui/chat/chat_style.h" + +namespace Api { +namespace { + +constexpr auto kRequestEach = 3600 * crl::time(1000); + +} // namespace + +PeerColors::PeerColors(not_null api) +: _api(&api->instance()) +, _timer([=] { request(); }) { + request(); + _timer.callEach(kRequestEach); +} + +PeerColors::~PeerColors() = default; + +void PeerColors::request() { + if (_requestId) { + return; + } + _requestId = _api.request(MTPhelp_GetPeerColors( + MTP_int(_hash) + )).done([=](const MTPhelp_PeerColors &result) { + _requestId = 0; + result.match([&](const MTPDhelp_peerColors &data) { + _hash = data.vhash().v; + apply(data); + }, [](const MTPDhelp_peerColorsNotModified &) { + }); + }).fail([=] { + _requestId = 0; + }).send(); +} + +std::vector PeerColors::suggested() const { + return _suggested.current(); +} + +rpl::producer> PeerColors::suggestedValue() const { + return _suggested.value(); +} + +auto PeerColors::indicesValue() const +-> rpl::producer { + return rpl::single(_colorIndicesCurrent + ? *_colorIndicesCurrent + : Ui::ColorIndicesCompressed() + ) | rpl::then(_colorIndicesChanged.events() | rpl::map([=] { + return *_colorIndicesCurrent; + })); +} + +void PeerColors::apply(const MTPDhelp_peerColors &data) { + auto suggested = std::vector(); + auto colors = std::make_shared< + std::array>(); + + using ParsedColor = std::array; + const auto parseColors = [](const MTPhelp_PeerColorSet &set) { + return set.match([&](const MTPDhelp_peerColorSet &data) { + auto result = ParsedColor(); + const auto &list = data.vcolors().v; + if (list.empty() || list.size() > Ui::kColorPatternsCount) { + LOG(("API Error: Bad count for PeerColorSet.colors: %1" + ).arg(list.size())); + return ParsedColor(); + } + auto fill = result.data(); + for (const auto &color : list) { + *fill++ = (uint32(1) << 24) | uint32(color.v); + } + return result; + }, [](const MTPDhelp_peerColorProfileSet &) { + LOG(("API Error: peerColorProfileSet in colors result!")); + return ParsedColor(); + }); + }; + + const auto &list = data.vcolors().v; + suggested.reserve(list.size()); + for (const auto &color : list) { + const auto &data = color.data(); + const auto colorIndexBare = data.vcolor_id().v; + if (colorIndexBare < 0 || colorIndexBare >= Ui::kColorIndexCount) { + LOG(("API Error: Bad color index: %1").arg(colorIndexBare)); + continue; + } + const auto colorIndex = uint8(colorIndexBare); + if (!data.is_hidden()) { + suggested.push_back(colorIndex); + } + if (const auto light = data.vcolors()) { + auto &fields = (*colors)[colorIndex]; + fields.light = parseColors(*light); + if (const auto dark = data.vdark_colors()) { + fields.dark = parseColors(*dark); + } else { + fields.dark = fields.light; + } + } + } + + if (!_colorIndicesCurrent) { + _colorIndicesCurrent = std::make_unique( + Ui::ColorIndicesCompressed{ std::move(colors) }); + _colorIndicesChanged.fire({}); + } else if (*_colorIndicesCurrent->colors != *colors) { + _colorIndicesCurrent->colors = std::move(colors); + _colorIndicesChanged.fire({}); + } + _suggested = std::move(suggested); +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_peer_colors.h b/Telegram/SourceFiles/api/api_peer_colors.h new file mode 100644 index 000000000..de06d4221 --- /dev/null +++ b/Telegram/SourceFiles/api/api_peer_colors.h @@ -0,0 +1,46 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "base/timer.h" +#include "mtproto/sender.h" + +class ApiWrap; + +namespace Ui { +struct ColorIndicesCompressed; +} // namespace Ui + +namespace Api { + +class PeerColors final { +public: + explicit PeerColors(not_null api); + ~PeerColors(); + + [[nodiscard]] std::vector suggested() const; + [[nodiscard]] rpl::producer> suggestedValue() const; + [[nodiscard]] auto indicesValue() const + -> rpl::producer; + +private: + void request(); + void apply(const MTPDhelp_peerColors &data); + + MTP::Sender _api; + int32 _hash = 0; + + mtpRequestId _requestId = 0; + base::Timer _timer; + rpl::variable> _suggested; + rpl::event_stream<> _colorIndicesChanged; + std::unique_ptr _colorIndicesCurrent; + +}; + +} // namespace Api diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index ec26f166b..f2405f2e3 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_hash.h" #include "api/api_invite_links.h" #include "api/api_media.h" +#include "api/api_peer_colors.h" #include "api/api_peer_photo.h" #include "api/api_polls.h" #include "api/api_sending.h" @@ -180,7 +181,8 @@ ApiWrap::ApiWrap(not_null session) , _transcribes(std::make_unique(this)) , _premium(std::make_unique(this)) , _usernames(std::make_unique(this)) -, _websites(std::make_unique(this)) { +, _websites(std::make_unique(this)) +, _peerColors(std::make_unique(this)) { crl::on_main(session, [=] { // You can't use _session->lifetime() in the constructor, // only queued, because it is not constructed yet. @@ -4402,3 +4404,7 @@ Api::Usernames &ApiWrap::usernames() { Api::Websites &ApiWrap::websites() { return *_websites; } + +Api::PeerColors &ApiWrap::peerColors() { + return *_peerColors; +} diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index ecb0f968a..bdfc8561f 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -73,6 +73,7 @@ class InviteLinks; class ViewsManager; class ConfirmPhone; class PeerPhoto; +class PeerColors; class Polls; class ChatParticipants; class UnreadThings; @@ -392,6 +393,7 @@ public: [[nodiscard]] Api::Premium &premium(); [[nodiscard]] Api::Usernames &usernames(); [[nodiscard]] Api::Websites &websites(); + [[nodiscard]] Api::PeerColors &peerColors(); void updatePrivacyLastSeens(); @@ -711,6 +713,7 @@ private: const std::unique_ptr _premium; const std::unique_ptr _usernames; const std::unique_ptr _websites; + const std::unique_ptr _peerColors; mtpRequestId _wallPaperRequestId = 0; QString _wallPaperSlug; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp index 5b5f80bf4..fd3458c1d 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_peer_color_box.h" #include "apiwrap.h" +#include "api/api_peer_colors.h" #include "base/unixtime.h" #include "boxes/peers/replace_boost_box.h" #include "chat_helpers/compose/compose_show.h" @@ -787,19 +788,7 @@ void EditPeerColorBox( state->emojiId.value() ), {}); - const auto appConfig = &peer->session().account().appConfig(); - auto indices = rpl::single( - rpl::empty - ) | rpl::then( - appConfig->refreshed() - ) | rpl::map([=] { - const auto list = appConfig->get>( - "peer_colors_available", - { 0, 1, 2, 3, 4, 5, 6 }); - return list | ranges::views::transform([](int i) { - return uint8(i); - }) | ranges::to_vector; - }); + auto indices = peer->session().api().peerColors().suggestedValue(); const auto margin = st::settingsColorRadioMargin; const auto skip = st::settingsColorRadioSkip; box->addRow( diff --git a/Telegram/SourceFiles/main/main_app_config.cpp b/Telegram/SourceFiles/main/main_app_config.cpp index fdc98ac39..a973979b7 100644 --- a/Telegram/SourceFiles/main/main_app_config.cpp +++ b/Telegram/SourceFiles/main/main_app_config.cpp @@ -61,7 +61,6 @@ void AppConfig::refresh() { _data.emplace_or_assign(qs(data.vkey()), data.vvalue()); }); } - parseColorIndices(); DEBUG_LOG(("getAppConfig result handled.")); _refreshed.fire({}); }, [](const MTPDhelp_appConfigNotModified &) {}); @@ -224,121 +223,4 @@ void AppConfig::dismissSuggestion(const QString &key) { )).send(); } -void AppConfig::parseColorIndices() { - constexpr auto parseColor = [](const MTPJSONValue &color) { - if (color.type() != mtpc_jsonString) { - LOG(("API Error: Bad type for color element.")); - return uint32(); - } - const auto value = color.c_jsonString().vvalue().v; - if (value.size() != 6) { - LOG(("API Error: Bad length for color element: %1" - ).arg(qs(value))); - return uint32(); - } - const auto hex = [](char ch) { - return (ch >= 'a' && ch <= 'f') - ? (ch - 'a' + 10) - : (ch >= 'A' && ch <= 'F') - ? (ch - 'A' + 10) - : (ch >= '0' && ch <= '9') - ? (ch - '0') - : 0; - }; - auto result = (uint32(1) << 24); - for (auto i = 0; i != 6; ++i) { - result |= (uint32(hex(value[i])) << ((5 - i) * 4)); - } - return result; - }; - - struct ParsedColor { - uint8 colorIndex = Ui::kColorIndexCount; - std::array colors; - - explicit operator bool() const { - return colorIndex < Ui::kColorIndexCount; - } - }; - const auto parseColors = [&](const MTPJSONObjectValue &element) { - const auto &data = element.data(); - if (data.vvalue().type() != mtpc_jsonArray) { - LOG(("API Error: Bad value for peer_colors element.")); - return ParsedColor(); - } - const auto &list = data.vvalue().c_jsonArray().vvalue().v; - if (list.empty() || list.size() > Ui::kColorPatternsCount) { - LOG(("API Error: Bad count for peer_colors element: %1" - ).arg(list.size())); - return ParsedColor(); - } - const auto index = data.vkey().v.toInt(); - if (index < Ui::kSimpleColorIndexCount - || index >= Ui::kColorIndexCount) { - LOG(("API Error: Bad index for peer_colors element: %1" - ).arg(qs(data.vkey().v))); - return ParsedColor(); - } - auto result = ParsedColor{ .colorIndex = uint8(index) }; - auto fill = result.colors.data(); - for (const auto &color : list) { - *fill++ = parseColor(color); - } - return result; - }; - const auto checkColorsObjectType = [&](const MTPJSONValue &value) { - if (value.type() != mtpc_jsonObject) { - if (value.type() != mtpc_jsonArray - || !value.c_jsonArray().vvalue().v.empty()) { - LOG(("API Error: Bad value for [dark_]peer_colors.")); - } - return false; - } - return true; - }; - - auto colors = std::make_shared< - std::array>(); - getValue(u"peer_colors"_q, [&](const MTPJSONValue &value) { - if (!checkColorsObjectType(value)) { - return; - } - for (const auto &element : value.c_jsonObject().vvalue().v) { - if (const auto parsed = parseColors(element)) { - auto &fields = (*colors)[parsed.colorIndex]; - fields.dark = fields.light = parsed.colors; - } - } - }); - getValue(u"dark_peer_colors"_q, [&](const MTPJSONValue &value) { - if (!checkColorsObjectType(value)) { - return; - } - for (const auto &element : value.c_jsonObject().vvalue().v) { - if (const auto parsed = parseColors(element)) { - (*colors)[parsed.colorIndex].dark = parsed.colors; - } - } - }); - - if (!_colorIndicesCurrent) { - _colorIndicesCurrent = std::make_unique( - Ui::ColorIndicesCompressed{ std::move(colors) }); - _colorIndicesChanged.fire({}); - } else if (*_colorIndicesCurrent->colors != *colors) { - _colorIndicesCurrent->colors = std::move(colors); - _colorIndicesChanged.fire({}); - } -} - -auto AppConfig::colorIndicesValue() const --> rpl::producer { - return rpl::single(_colorIndicesCurrent - ? *_colorIndicesCurrent - : Ui::ColorIndicesCompressed() - ) | rpl::then(_colorIndicesChanged.events() | rpl::map([=] { - return *_colorIndicesCurrent; - })); -} - } // namespace Main diff --git a/Telegram/SourceFiles/main/main_app_config.h b/Telegram/SourceFiles/main/main_app_config.h index 04c00dcfe..541b9f24c 100644 --- a/Telegram/SourceFiles/main/main_app_config.h +++ b/Telegram/SourceFiles/main/main_app_config.h @@ -54,14 +54,10 @@ public: const QString &key) const; void dismissSuggestion(const QString &key); - [[nodiscard]] auto colorIndicesValue() const - -> rpl::producer; - void refresh(); private: void refreshDelayed(); - void parseColorIndices(); template [[nodiscard]] auto getValue( @@ -95,9 +91,6 @@ private: rpl::event_stream<> _refreshed; base::flat_set _dismissedSuggestions; - rpl::event_stream<> _colorIndicesChanged; - std::unique_ptr _colorIndicesCurrent; - rpl::lifetime _lifetime; }; diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 84f48106a..72b791fa1 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "apiwrap.h" +#include "api/api_peer_colors.h" #include "api/api_updates.h" #include "api/api_send_progress.h" #include "api/api_user_privacy.h" @@ -476,9 +477,9 @@ Window::SessionController *Session::tryResolveWindow() const { return _windows.front(); } -auto Session::colorIndicesValue() const +auto Session::colorIndicesValue() -> rpl::producer { - return _account->appConfig().colorIndicesValue(); + return api().peerColors().indicesValue(); } } // namespace Main diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 342c7ced6..2dd967722 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -191,12 +191,14 @@ public: [[nodiscard]] Support::Helper &supportHelper() const; [[nodiscard]] Support::Templates &supportTemplates() const; - [[nodiscard]] auto colorIndicesValue() const + [[nodiscard]] auto colorIndicesValue() -> rpl::producer; private: static constexpr auto kDefaultSaveDelay = crl::time(1000); + void parseColorIndices(const MTPDhelp_peerColors &data); + const not_null _account; const std::unique_ptr _settings; @@ -234,8 +236,6 @@ private: QByteArray _tmpPassword; TimeId _tmpPasswordValidUntil = 0; - rpl::event_stream _colorIndicesChanges; - rpl::lifetime _lifetime; };