diff --git a/Telegram/SourceFiles/data/data_cloud_themes.cpp b/Telegram/SourceFiles/data/data_cloud_themes.cpp index 4be5d9aa76..2fe5f2ced9 100644 --- a/Telegram/SourceFiles/data/data_cloud_themes.cpp +++ b/Telegram/SourceFiles/data/data_cloud_themes.cpp @@ -7,12 +7,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_cloud_themes.h" +#include "window/themes/window_theme.h" +#include "window/themes/window_theme_preview.h" #include "data/data_session.h" #include "data/data_document.h" +#include "data/data_file_origin.h" #include "main/main_session.h" #include "apiwrap.h" namespace Data { +namespace { + +constexpr auto kFirstReloadTimeout = 60 * crl::time(1000); +constexpr auto kReloadTimeout = 3600 * crl::time(1000); + +} // namespace CloudTheme CloudTheme::Parse( not_null session, @@ -36,7 +45,103 @@ QString CloudThemes::Format() { } CloudThemes::CloudThemes(not_null session) -: _session(session) { +: _session(session) +, _reloadCurrentTimer([=] { reloadCurrent(); }) { + setupReload(); +} + +void CloudThemes::setupReload() { + using namespace Window::Theme; + + if (needReload()) { + _reloadCurrentTimer.callOnce(kFirstReloadTimeout); + } + base::ObservableViewer( + *Background() + ) | rpl::filter([](const BackgroundUpdate &update) { + return (update.type == BackgroundUpdate::Type::ApplyingTheme); + }) | rpl::map([=] { + return needReload(); + }) | rpl::start_with_next([=](bool need) { + if (need) { + scheduleReload(); + } else { + _reloadCurrentTimer.cancel(); + } + }, _lifetime); +} + +bool CloudThemes::needReload() const { + const auto &fields = Window::Theme::Background()->themeObject().cloud; + return fields.id && fields.documentId; +} + +void CloudThemes::reloadCurrent() { + if (!needReload()) { + return; + } + const auto &fields = Window::Theme::Background()->themeObject().cloud; + _session->api().request(MTPaccount_GetTheme( + MTP_string(Format()), + MTP_inputTheme(MTP_long(fields.id), MTP_long(fields.accessHash)), + MTP_long(fields.documentId) + )).done([=](const MTPTheme &result) { + applyUpdate(result); + }).fail([=](const RPCError &error) { + _reloadCurrentTimer.callOnce(kReloadTimeout); + }).send(); +} + +void CloudThemes::applyUpdate(const MTPTheme &theme) { + theme.match([&](const MTPDtheme &data) { + const auto cloud = CloudTheme::Parse(_session, data); + const auto &object = Window::Theme::Background()->themeObject(); + if ((cloud.id != object.cloud.id) + || (cloud.documentId == object.cloud.documentId)) { + return; + } + if (const auto updated = data.vdocument()) { + updateFromDocument( + cloud, + _session->data().processDocument(*updated)); + } + }, [&](const MTPDthemeDocumentNotModified &data) { + }); + scheduleReload(); +} + +void CloudThemes::updateFromDocument( + const CloudTheme &cloud, + not_null document) { + if (_updatingFrom) { + _updatingFrom->cancel(); + } else { + base::ObservableViewer( + _session->downloaderTaskFinished() + ) | rpl::filter([=] { + return _updatingFrom->loaded(); + }) | rpl::start_with_next([=] { + _updatingFromLifetime.destroy(); + auto preview = Window::Theme::PreviewFromFile( + document->data(), + document->location().name(), + cloud); + if (preview) { + Window::Theme::Apply(std::move(preview)); + } + }, _updatingFromLifetime); + } + + _updatingFrom = document; + _updatingFrom->save(Data::FileOrigin(), QString()); // #TODO themes +} + +void CloudThemes::scheduleReload() { + if (needReload()) { + _reloadCurrentTimer.callOnce(kReloadTimeout); + } else { + _reloadCurrentTimer.cancel(); + } } void CloudThemes::refresh() { diff --git a/Telegram/SourceFiles/data/data_cloud_themes.h b/Telegram/SourceFiles/data/data_cloud_themes.h index 072561ddbc..a34366d5ea 100644 --- a/Telegram/SourceFiles/data/data_cloud_themes.h +++ b/Telegram/SourceFiles/data/data_cloud_themes.h @@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/timer.h" + +class DocumentData; + namespace Main { class Session; } // namespace Main @@ -37,15 +41,31 @@ public: [[nodiscard]] const std::vector &list() const; void apply(const CloudTheme &data); + void applyUpdate(const MTPTheme &theme); + private: void parseThemes(const QVector &list); + void setupReload(); + [[nodiscard]] bool needReload() const; + void scheduleReload(); + void reloadCurrent(); + void updateFromDocument( + const CloudTheme &cloud, + not_null document); + const not_null _session; int32 _hash = 0; mtpRequestId _requestId = 0; std::vector _list; rpl::event_stream<> _updates; + base::Timer _reloadCurrentTimer; + DocumentData *_updatingFrom = nullptr; + rpl::lifetime _updatingFromLifetime; + + rpl::lifetime _lifetime; + }; } // namespace Data diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index d98001c085..83373f906d 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4612,5 +4612,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } break; + ////// Cloud themes + case mtpc_updateTheme: { + const auto &data = update.c_updateTheme(); + session().data().cloudThemes().applyUpdate(data.vtheme()); + } break; + } }