Open theme editor for existing themes.

This commit is contained in:
John Preston 2019-09-05 08:18:21 +03:00
parent dd74f57a66
commit 03bdd80b2f
11 changed files with 111 additions and 91 deletions

View File

@ -337,8 +337,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_bg_use_default" = "Use default color theme"; "lng_settings_bg_use_default" = "Use default color theme";
"lng_settings_bg_from_gallery" = "Choose from gallery"; "lng_settings_bg_from_gallery" = "Choose from gallery";
"lng_settings_bg_from_file" = "Choose from file"; "lng_settings_bg_from_file" = "Choose from file";
"lng_settings_bg_edit_theme" = "Launch theme editor"; "lng_settings_bg_theme_edit" = "Edit theme";
"lng_settings_bg_create_theme" = "Create new theme"; "lng_settings_bg_theme_create" = "Create new theme";
"lng_settings_bg_cloud_themes" = "Custom themes"; "lng_settings_bg_cloud_themes" = "Custom themes";
"lng_settings_bg_show_all" = "Show all themes"; "lng_settings_bg_show_all" = "Show all themes";
"lng_settings_bg_tile" = "Tile background"; "lng_settings_bg_tile" = "Tile background";

View File

@ -1084,8 +1084,7 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
base::ObservableViewer( base::ObservableViewer(
*Window::Theme::Background() *Window::Theme::Background()
) | rpl::filter([](const Update &update) { ) | rpl::filter([](const Update &update) {
return (update.type == Update::Type::ApplyingTheme return (update.type == Update::Type::ApplyingTheme);
|| update.type == Update::Type::New);
}) | rpl::map([=] { }) | rpl::map([=] {
return chosen(); return chosen();
}) | rpl::start_with_next([=](Type type) { }) | rpl::start_with_next([=](Type type) {
@ -1149,6 +1148,8 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
void SetupThemeOptions( void SetupThemeOptions(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container) { not_null<Ui::VerticalLayout*> container) {
using namespace Window::Theme;
AddSkip(container, st::settingsPrivacySkip); AddSkip(container, st::settingsPrivacySkip);
AddSubsectionTitle(container, tr::lng_settings_themes()); AddSubsectionTitle(container, tr::lng_settings_themes());
@ -1156,20 +1157,38 @@ void SetupThemeOptions(
AddSkip(container, st::settingsThemesTopSkip); AddSkip(container, st::settingsThemesTopSkip);
SetupDefaultThemes(container); SetupDefaultThemes(container);
AddSkip(container, st::settingsThemesBottomSkip); AddSkip(container, st::settingsThemesBottomSkip);
auto canEdit = rpl::single(false);
const auto canEditCurrent = [=] {
const auto userId = controller->session().userId();
return (Background()->themeObject().cloud.createdBy == userId);
};
auto canEdit = rpl::single(BackgroundUpdate(
BackgroundUpdate::Type::ApplyingTheme,
Background()->tile()
)) | rpl::then(base::ObservableViewer(
*Background()
)) | rpl::filter([](const BackgroundUpdate &update) {
return (update.type == BackgroundUpdate::Type::ApplyingTheme);
}) | rpl::map([=] {
return canEditCurrent();
});
AddButton( AddButton(
container, container,
rpl::conditional( rpl::conditional(
std::move(canEdit), std::move(canEdit),
tr::lng_settings_bg_edit_theme(), tr::lng_settings_bg_theme_edit(),
tr::lng_settings_bg_create_theme()), tr::lng_settings_bg_theme_create()),
st::settingsChatButton, st::settingsChatButton,
&st::settingsIconThemes, &st::settingsIconThemes,
st::settingsChatIconLeft st::settingsChatIconLeft
)->addClickHandler([=] { )->addClickHandler([=] {
controller->window().show(Box( if (canEditCurrent()) {
Window::Theme::CreateBox, StartEditor(
&controller->window())); &controller->window(),
Background()->themeObject().cloud);
} else {
controller->window().show(Box(CreateBox, &controller->window()));
}
}); });
AddSkip(container); AddSkip(container);

View File

@ -4201,21 +4201,17 @@ Window::Theme::Saved readThemeUsingKey(FileKey key) {
auto &cache = result.cache; auto &cache = result.cache;
theme.stream >> object.content; theme.stream >> object.content;
theme.stream >> tag >> object.pathAbsolute; theme.stream >> tag >> object.pathAbsolute;
const auto isCloud = (object.pathAbsolute == kThemePathAbsoluteCloud);
if (tag == kThemeNewPathRelativeTag) { if (tag == kThemeNewPathRelativeTag) {
if (isCloud) { auto creator = qint32();
auto creator = qint32(); theme.stream
theme.stream >> object.pathRelative
>> object.cloud.id >> object.cloud.id
>> object.cloud.accessHash >> object.cloud.accessHash
>> object.cloud.slug >> object.cloud.slug
>> object.cloud.title >> object.cloud.title
>> object.cloud.documentId >> object.cloud.documentId
>> creator; >> creator;
object.cloud.createdBy = creator; object.cloud.createdBy = creator;
} else {
theme.stream >> object.pathRelative;
}
} else { } else {
object.pathRelative = tag; object.pathRelative = tag;
} }
@ -4224,7 +4220,7 @@ Window::Theme::Saved readThemeUsingKey(FileKey key) {
} }
auto ignoreCache = false; auto ignoreCache = false;
if (!isCloud) { if (!object.cloud.id) {
QFile file(object.pathRelative); QFile file(object.pathRelative);
if (object.pathRelative.isEmpty() || !file.exists()) { if (object.pathRelative.isEmpty() || !file.exists()) {
file.setFileName(object.pathAbsolute); file.setFileName(object.pathAbsolute);
@ -4299,33 +4295,30 @@ void writeTheme(const Window::Theme::Saved &saved) {
const auto &object = saved.object; const auto &object = saved.object;
const auto &cache = saved.cache; const auto &cache = saved.cache;
const auto tag = QString(kThemeNewPathRelativeTag); const auto tag = QString(kThemeNewPathRelativeTag);
const auto isCloud = (saved.object.pathAbsolute == kThemePathAbsoluteCloud); quint32 size = Serialize::bytearraySize(object.content)
quint32 size = Serialize::bytearraySize(object.content); + Serialize::stringSize(tag)
size += Serialize::stringSize(tag) + Serialize::stringSize(object.pathAbsolute); + Serialize::stringSize(object.pathAbsolute)
if (isCloud) { + Serialize::stringSize(object.pathRelative)
size += sizeof(uint64) * 3 + sizeof(uint64) * 3
+ Serialize::stringSize(object.cloud.slug) + Serialize::stringSize(object.cloud.slug)
+ Serialize::stringSize(object.cloud.title) + Serialize::stringSize(object.cloud.title)
+ sizeof(qint32); + sizeof(qint32)
} else { + sizeof(qint32) * 2
size += Serialize::stringSize(object.pathRelative); + Serialize::bytearraySize(cache.colors)
} + Serialize::bytearraySize(cache.background)
size += sizeof(int32) * 2 + Serialize::bytearraySize(cache.colors) + Serialize::bytearraySize(cache.background) + sizeof(quint32); + sizeof(quint32);
EncryptedDescriptor data(size); EncryptedDescriptor data(size);
data.stream << object.content;
data.stream << tag << object.pathAbsolute;
if (isCloud) {
data.stream
<< object.cloud.id
<< object.cloud.accessHash
<< object.cloud.slug
<< object.cloud.title
<< object.cloud.documentId
<< qint32(object.cloud.createdBy);
} else {
data.stream << object.pathRelative;
}
data.stream data.stream
<< object.content
<< tag
<< object.pathAbsolute
<< object.pathRelative
<< object.cloud.id
<< object.cloud.accessHash
<< object.cloud.slug
<< object.cloud.title
<< object.cloud.documentId
<< qint32(object.cloud.createdBy)
<< cache.paletteChecksum << cache.paletteChecksum
<< cache.contentChecksum << cache.contentChecksum
<< cache.colors << cache.colors

View File

@ -413,7 +413,7 @@ Checkbox::Checkbox(
text, text,
_checkboxOptions, _checkboxOptions,
countTextMinWidth()) { countTextMinWidth()) {
_check->setUpdateCallback([=] { updateCheck(); }); _check->setUpdateCallback([=] { update(); });
resizeToText(); resizeToText();
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
} }

View File

@ -590,8 +590,8 @@ void MainWindow::reActivateWindow() {
} }
void MainWindow::showRightColumn(object_ptr<TWidget> widget) { void MainWindow::showRightColumn(object_ptr<TWidget> widget) {
auto wasWidth = width(); const auto wasWidth = width();
auto wasRightWidth = _rightColumn ? _rightColumn->width() : 0; const auto wasRightWidth = _rightColumn ? _rightColumn->width() : 0;
_rightColumn = std::move(widget); _rightColumn = std::move(widget);
if (_rightColumn) { if (_rightColumn) {
_rightColumn->setParent(this); _rightColumn->setParent(this);
@ -600,13 +600,14 @@ void MainWindow::showRightColumn(object_ptr<TWidget> widget) {
} else if (App::wnd()) { } else if (App::wnd()) {
App::wnd()->setInnerFocus(); App::wnd()->setInnerFocus();
} }
auto nowRightWidth = _rightColumn ? _rightColumn->width() : 0; const auto nowRightWidth = _rightColumn ? _rightColumn->width() : 0;
setMinimumWidth(st::windowMinWidth + nowRightWidth); const auto wasMaximized = isMaximized();
if (!isMaximized()) { if (!isMaximized()) {
tryToExtendWidthBy(wasWidth + nowRightWidth - wasRightWidth - width()); tryToExtendWidthBy(wasWidth + nowRightWidth - wasRightWidth - width());
} else { } else {
updateControlsGeometry(); updateControlsGeometry();
} }
setMinimumWidth(st::windowMinWidth + nowRightWidth);
} }
int MainWindow::maximalExtendBy() const { int MainWindow::maximalExtendBy() const {

View File

@ -1065,8 +1065,10 @@ void Unload() {
GlobalApplying = Applying(); GlobalApplying = Applying();
} }
bool Apply(const QString &filepath) { bool Apply(
if (auto preview = PreviewFromFile(filepath, {}, {})) { const QString &filepath,
const Data::CloudTheme &cloud) {
if (auto preview = PreviewFromFile(filepath, {}, cloud)) {
return Apply(std::move(preview)); return Apply(std::move(preview));
} }
return false; return false;

View File

@ -18,7 +18,6 @@ namespace Window {
namespace Theme { namespace Theme {
inline constexpr auto kThemeSchemeSizeLimit = 1024 * 1024; inline constexpr auto kThemeSchemeSizeLimit = 1024 * 1024;
inline const auto kThemePathAbsoluteCloud = qstr("special://cloud");
struct Object { struct Object {
QString pathRelative; QString pathRelative;
@ -53,7 +52,9 @@ struct Preview {
QImage preview; QImage preview;
}; };
bool Apply(const QString &filepath); bool Apply(
const QString &filepath,
const Data::CloudTheme &cloud = Data::CloudTheme());
bool Apply(std::unique_ptr<Preview> preview); bool Apply(std::unique_ptr<Preview> preview);
void ApplyDefaultWithPath(const QString &themePath); void ApplyDefaultWithPath(const QString &themePath);
bool ApplyEditedPalette(const QString &path, const QByteArray &content); bool ApplyEditedPalette(const QString &path, const QByteArray &content);

View File

@ -262,21 +262,6 @@ void WriteDefaultPalette(const QString &path) {
} }
} }
void StartEditor(
not_null<Window::Controller*> window,
const QString &title) {
const auto path = EditingPalettePath();
if (!Local::copyThemeColorsToPalette(path)) {
WriteDefaultPalette(path);
}
if (!Apply(path)) {
window->show(Box<InformBox>(tr::lng_theme_editor_error(tr::now)));
return;
}
KeepApplied();
window->showRightColumn(Box<Editor>(window));
}
[[nodiscard]] QString GenerateSlug() { [[nodiscard]] QString GenerateSlug() {
const auto letters = uint8('Z' + 1 - 'A'); const auto letters = uint8('Z' + 1 - 'A');
const auto digits = uint8('9' + 1 - '0'); const auto digits = uint8('9' + 1 - '0');
@ -500,6 +485,21 @@ Fn<void()> SaveTheme(
} // namespace } // namespace
void StartEditor(
not_null<Window::Controller*> window,
const Data::CloudTheme &cloud) {
const auto path = EditingPalettePath();
if (!Local::copyThemeColorsToPalette(path)) {
WriteDefaultPalette(path);
}
if (!Apply(path, cloud)) {
window->show(Box<InformBox>(tr::lng_theme_editor_error(tr::now)));
return;
}
KeepApplied();
window->showRightColumn(Box<Editor>(window));
}
void CreateBox( void CreateBox(
not_null<GenericBox*> box, not_null<GenericBox*> box,
not_null<Window::Controller*> window) { not_null<Window::Controller*> window) {
@ -542,7 +542,9 @@ void CreateBox(
return; return;
} }
box->closeBox(); box->closeBox();
StartEditor(window, title); auto cloud = Data::CloudTheme();
cloud.title = title;
StartEditor(window, cloud);
}; };
Ui::Connect(name, &Ui::InputField::submitted, done); Ui::Connect(name, &Ui::InputField::submitted, done);
box->addButton(tr::lng_box_done(), done); box->addButton(tr::lng_box_done(), done);

View File

@ -9,12 +9,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/generic_box.h" #include "boxes/generic_box.h"
namespace Data {
struct CloudTheme;
} // namespace Data
namespace Window { namespace Window {
class Controller; class Controller;
namespace Theme { namespace Theme {
void StartEditor(
not_null<Window::Controller*> window,
const Data::CloudTheme &cloud);
void CreateBox( void CreateBox(
not_null<GenericBox*> box, not_null<GenericBox*> box,
not_null<Window::Controller*> window); not_null<Window::Controller*> window);

View File

@ -915,17 +915,12 @@ std::unique_ptr<Preview> PreviewFromFile(
auto result = std::make_unique<Preview>(); auto result = std::make_unique<Preview>();
auto &object = result->object; auto &object = result->object;
object.cloud = cloud; object.cloud = cloud;
if (cloud.documentId || filepath.isEmpty()) { object.pathRelative = filepath.isEmpty()
object.pathRelative = QString(); ? QString()
object.pathAbsolute = QString(kThemePathAbsoluteCloud); : QDir().relativeFilePath(filepath);
} else { object.pathAbsolute = filepath.isEmpty()
object.pathRelative = filepath.isEmpty() ? QString()
? QString() : QFileInfo(filepath).absoluteFilePath();
: QDir().relativeFilePath(filepath);
object.pathAbsolute = filepath.isEmpty()
? QString()
: QFileInfo(filepath).absoluteFilePath();
}
if (bytes.isEmpty()) { if (bytes.isEmpty()) {
if (!LoadFromFile(filepath, &result->instance, &object.content)) { if (!LoadFromFile(filepath, &result->instance, &object.content)) {
return nullptr; return nullptr;

View File

@ -154,13 +154,13 @@ void CloudList::setup() {
_window->session().data().cloudThemes().updated() _window->session().data().cloudThemes().updated()
); );
auto themeChanges = rpl::single( auto themeChanges = rpl::single(BackgroundUpdate(
BackgroundUpdate(BackgroundUpdate::Type::New, Background()->tile()) BackgroundUpdate::Type::ApplyingTheme,
) | rpl::then(base::ObservableViewer( Background()->tile()
)) | rpl::then(base::ObservableViewer(
*Background() *Background()
)) | rpl::filter([](const BackgroundUpdate &update) { )) | rpl::filter([](const BackgroundUpdate &update) {
return (update.type == BackgroundUpdate::Type::ApplyingTheme) return (update.type == BackgroundUpdate::Type::ApplyingTheme);
|| (update.type == BackgroundUpdate::Type::New);
}); });
rpl::combine( rpl::combine(