tdesktop/Telegram/SourceFiles/data/data_cloud_themes.cpp

336 lines
8.9 KiB
C++
Raw Normal View History

2019-09-03 15:24:51 +00:00
/*
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 "data/data_cloud_themes.h"
2019-09-06 13:35:26 +00:00
#include "window/themes/window_theme.h"
#include "window/themes/window_theme_preview.h"
2019-09-06 14:24:22 +00:00
#include "window/themes/window_theme_editor_box.h"
#include "window/window_controller.h"
2019-09-03 15:24:51 +00:00
#include "data/data_session.h"
2019-09-03 18:04:38 +00:00
#include "data/data_document.h"
2019-09-06 13:35:26 +00:00
#include "data/data_file_origin.h"
#include "data/data_document_media.h"
2019-09-03 15:24:51 +00:00
#include "main/main_session.h"
2019-09-06 14:24:22 +00:00
#include "boxes/confirm_box.h"
2021-06-15 20:30:08 +00:00
#include "media/view/media_view_open_common.h"
2019-09-06 14:24:22 +00:00
#include "lang/lang_keys.h"
2019-09-03 15:24:51 +00:00
#include "apiwrap.h"
namespace Data {
2019-09-06 13:35:26 +00:00
namespace {
constexpr auto kFirstReloadTimeout = 10 * crl::time(1000);
2019-09-06 13:35:26 +00:00
constexpr auto kReloadTimeout = 3600 * crl::time(1000);
} // namespace
2019-09-03 15:24:51 +00:00
2019-09-03 18:04:38 +00:00
CloudTheme CloudTheme::Parse(
not_null<Main::Session*> session,
const MTPDtheme &data) {
const auto document = data.vdocument();
return {
data.vid().v,
data.vaccess_hash().v,
qs(data.vslug()),
qs(data.vtitle()),
(document
? session->data().processDocument(*document)->id
: DocumentId(0)),
data.is_creator() ? session->userId() : UserId(0),
data.vinstalls_count().v
2019-09-03 18:04:38 +00:00
};
}
2019-09-03 15:24:51 +00:00
QString CloudThemes::Format() {
static const auto kResult = QString::fromLatin1("tdesktop");
return kResult;
}
CloudThemes::CloudThemes(not_null<Main::Session*> session)
2019-09-06 13:35:26 +00:00
: _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) {
2019-09-06 13:52:16 +00:00
install();
2019-09-06 13:35:26 +00:00
if (need) {
scheduleReload();
} else {
_reloadCurrentTimer.cancel();
}
}, _lifetime);
}
bool CloudThemes::needReload() const {
const auto &fields = Window::Theme::Background()->themeObject().cloud;
return fields.id && fields.documentId;
}
2019-09-06 13:52:16 +00:00
void CloudThemes::install() {
using namespace Window::Theme;
const auto &fields = Background()->themeObject().cloud;
auto &themeId = IsNightMode()
? _installedNightThemeId
: _installedDayThemeId;
const auto cloudId = fields.documentId ? fields.id : uint64(0);
if (themeId == cloudId) {
return;
}
themeId = cloudId;
using Flag = MTPaccount_InstallTheme::Flag;
const auto flags = (IsNightMode() ? Flag::f_dark : Flag(0))
| Flag::f_format
| (themeId ? Flag::f_theme : Flag(0));
_session->api().request(MTPaccount_InstallTheme(
MTP_flags(flags),
MTP_string(Format()),
MTP_inputTheme(MTP_long(cloudId), MTP_long(fields.accessHash))
)).send();
}
2019-09-06 13:35:26 +00:00
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);
2021-03-12 12:48:00 +00:00
}).fail([=](const MTP::Error &error) {
2019-09-06 13:35:26 +00:00
_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)
2019-09-06 14:24:22 +00:00
|| (cloud.documentId == object.cloud.documentId)
|| !cloud.documentId) {
2019-09-06 13:35:26 +00:00
return;
}
applyFromDocument(cloud);
2019-09-06 13:35:26 +00:00
});
scheduleReload();
}
2019-09-06 14:24:22 +00:00
void CloudThemes::resolve(
2021-06-15 20:30:08 +00:00
not_null<Window::Controller*> controller,
2019-09-06 14:24:22 +00:00
const QString &slug,
const FullMsgId &clickFromMessageId) {
_session->api().request(_resolveRequestId).cancel();
_resolveRequestId = _session->api().request(MTPaccount_GetTheme(
MTP_string(Format()),
MTP_inputThemeSlug(MTP_string(slug)),
MTP_long(0)
)).done([=](const MTPTheme &result) {
2021-06-15 20:30:08 +00:00
showPreview(controller, result);
2021-03-12 12:48:00 +00:00
}).fail([=](const MTP::Error &error) {
2019-09-06 14:24:22 +00:00
if (error.type() == qstr("THEME_FORMAT_INVALID")) {
2021-06-15 20:30:08 +00:00
controller->show(Box<InformBox>(
2019-09-06 14:24:22 +00:00
tr::lng_theme_no_desktop(tr::now)));
}
}).send();
}
2021-06-15 20:30:08 +00:00
void CloudThemes::showPreview(
not_null<Window::Controller*> controller,
const MTPTheme &data) {
2019-09-06 15:31:01 +00:00
data.match([&](const MTPDtheme &data) {
2021-06-15 20:30:08 +00:00
showPreview(controller, CloudTheme::Parse(_session, data));
2019-09-06 15:31:01 +00:00
});
}
2021-06-15 20:30:08 +00:00
void CloudThemes::showPreview(
not_null<Window::Controller*> controller,
const CloudTheme &cloud) {
2019-09-06 15:31:01 +00:00
if (const auto documentId = cloud.documentId) {
2021-06-15 20:30:08 +00:00
previewFromDocument(controller, cloud);
2019-09-06 15:31:01 +00:00
} else if (cloud.createdBy == _session->userId()) {
2021-06-15 20:30:08 +00:00
controller->show(Box(
2019-09-06 15:31:01 +00:00
Window::Theme::CreateForExistingBox,
2021-06-15 20:30:08 +00:00
controller,
2019-09-06 15:31:01 +00:00
cloud));
} else {
2021-06-15 20:30:08 +00:00
controller->show(Box<InformBox>(
2019-09-06 15:31:01 +00:00
tr::lng_theme_no_desktop(tr::now)));
}
}
void CloudThemes::applyFromDocument(const CloudTheme &cloud) {
const auto document = _session->data().document(cloud.documentId);
loadDocumentAndInvoke(_updatingFrom, cloud, document, [=](
std::shared_ptr<Data::DocumentMedia> media) {
const auto document = media->owner();
2019-09-06 15:31:01 +00:00
auto preview = Window::Theme::PreviewFromFile(
media->bytes(),
2019-09-06 15:31:01 +00:00
document->location().name(),
cloud);
if (preview) {
Window::Theme::Apply(std::move(preview));
Window::Theme::KeepApplied();
2019-09-06 15:31:01 +00:00
}
});
}
2021-06-15 20:30:08 +00:00
void CloudThemes::previewFromDocument(
not_null<Window::Controller*> controller,
const CloudTheme &cloud) {
const auto sessionController = controller->sessionController();
if (!sessionController) {
return;
}
const auto document = _session->data().document(cloud.documentId);
loadDocumentAndInvoke(_previewFrom, cloud, document, [=](
std::shared_ptr<Data::DocumentMedia> media) {
const auto document = media->owner();
2021-06-15 20:30:08 +00:00
using Open = Media::View::OpenRequest;
controller->openInMediaView(Open(sessionController, document, cloud));
2019-09-06 15:31:01 +00:00
});
}
void CloudThemes::loadDocumentAndInvoke(
LoadingDocument &value,
2019-09-09 08:51:07 +00:00
const CloudTheme &cloud,
2019-09-06 15:31:01 +00:00
not_null<DocumentData*> document,
Fn<void(std::shared_ptr<Data::DocumentMedia>)> callback) {
2019-09-06 15:31:01 +00:00
const auto alreadyWaiting = (value.document != nullptr);
if (alreadyWaiting) {
value.document->cancel();
}
value.document = document;
value.documentMedia = document->createMediaView();
2019-09-09 08:51:07 +00:00
value.document->save(
Data::FileOriginTheme(cloud.id, cloud.accessHash),
QString());
2019-09-06 15:31:01 +00:00
value.callback = std::move(callback);
if (value.documentMedia->loaded()) {
2019-09-06 15:31:01 +00:00
invokeForLoaded(value);
return;
}
if (!alreadyWaiting) {
_session->downloaderTaskFinished(
) | rpl::filter([=, &value] {
return value.documentMedia->loaded();
2019-09-06 15:31:01 +00:00
}) | rpl::start_with_next([=, &value] {
invokeForLoaded(value);
}, value.subscription);
2019-09-06 13:35:26 +00:00
}
2019-09-06 15:31:01 +00:00
}
2019-09-06 13:35:26 +00:00
2019-09-06 15:31:01 +00:00
void CloudThemes::invokeForLoaded(LoadingDocument &value) {
const auto onstack = std::move(value.callback);
auto media = std::move(value.documentMedia);
2019-09-06 15:31:01 +00:00
value = LoadingDocument();
onstack(std::move(media));
2019-09-06 13:35:26 +00:00
}
void CloudThemes::scheduleReload() {
if (needReload()) {
_reloadCurrentTimer.callOnce(kReloadTimeout);
} else {
_reloadCurrentTimer.cancel();
}
2019-09-03 15:24:51 +00:00
}
void CloudThemes::refresh() {
2019-09-06 14:24:22 +00:00
if (_refreshRquestId) {
2019-09-03 15:24:51 +00:00
return;
}
2019-09-06 14:24:22 +00:00
_refreshRquestId = _session->api().request(MTPaccount_GetThemes(
2019-09-03 15:24:51 +00:00
MTP_string(Format()),
MTP_int(_hash)
)).done([=](const MTPaccount_Themes &result) {
2019-09-06 14:24:22 +00:00
_refreshRquestId = 0;
2019-09-03 15:24:51 +00:00
result.match([&](const MTPDaccount_themes &data) {
_hash = data.vhash().v;
parseThemes(data.vthemes().v);
_updates.fire({});
}, [](const MTPDaccount_themesNotModified &) {
});
2021-03-12 12:48:00 +00:00
}).fail([=](const MTP::Error &error) {
2019-09-06 14:24:22 +00:00
_refreshRquestId = 0;
2019-09-03 15:24:51 +00:00
}).send();
}
void CloudThemes::parseThemes(const QVector<MTPTheme> &list) {
_list.clear();
_list.reserve(list.size());
for (const auto &theme : list) {
theme.match([&](const MTPDtheme &data) {
2019-09-03 18:04:38 +00:00
_list.push_back(CloudTheme::Parse(_session, data));
2019-09-03 15:24:51 +00:00
});
}
checkCurrentTheme();
}
void CloudThemes::checkCurrentTheme() {
const auto &object = Window::Theme::Background()->themeObject();
if (!object.cloud.id || !object.cloud.documentId) {
return;
}
const auto i = ranges::find(_list, object.cloud.id, &CloudTheme::id);
if (i == end(_list)) {
install();
}
2019-09-03 15:24:51 +00:00
}
rpl::producer<> CloudThemes::updated() const {
return _updates.events();
}
const std::vector<CloudTheme> &CloudThemes::list() const {
return _list;
}
2019-09-08 18:01:45 +00:00
void CloudThemes::savedFromEditor(const CloudTheme &theme) {
const auto i = ranges::find(_list, theme.id, &CloudTheme::id);
if (i != end(_list)) {
*i = theme;
_updates.fire({});
2019-09-08 18:01:45 +00:00
} else {
_list.insert(begin(_list), theme);
_updates.fire({});
}
}
2019-09-08 17:05:26 +00:00
void CloudThemes::remove(uint64 cloudThemeId) {
const auto i = ranges::find(_list, cloudThemeId, &CloudTheme::id);
if (i == end(_list)) {
return;
}
_session->api().request(MTPaccount_SaveTheme(
MTP_inputTheme(
MTP_long(i->id),
MTP_long(i->accessHash)),
MTP_bool(true)
)).send();
_list.erase(i);
_updates.fire({});
}
2019-09-03 15:24:51 +00:00
} // namespace Data