mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-11 01:10:13 +00:00
Open theme editor for existing themes.
This commit is contained in:
parent
dd74f57a66
commit
03bdd80b2f
@ -337,8 +337,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_settings_bg_use_default" = "Use default color theme";
|
||||
"lng_settings_bg_from_gallery" = "Choose from gallery";
|
||||
"lng_settings_bg_from_file" = "Choose from file";
|
||||
"lng_settings_bg_edit_theme" = "Launch theme editor";
|
||||
"lng_settings_bg_create_theme" = "Create new theme";
|
||||
"lng_settings_bg_theme_edit" = "Edit theme";
|
||||
"lng_settings_bg_theme_create" = "Create new theme";
|
||||
"lng_settings_bg_cloud_themes" = "Custom themes";
|
||||
"lng_settings_bg_show_all" = "Show all themes";
|
||||
"lng_settings_bg_tile" = "Tile background";
|
||||
|
@ -1084,8 +1084,7 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
|
||||
base::ObservableViewer(
|
||||
*Window::Theme::Background()
|
||||
) | rpl::filter([](const Update &update) {
|
||||
return (update.type == Update::Type::ApplyingTheme
|
||||
|| update.type == Update::Type::New);
|
||||
return (update.type == Update::Type::ApplyingTheme);
|
||||
}) | rpl::map([=] {
|
||||
return chosen();
|
||||
}) | rpl::start_with_next([=](Type type) {
|
||||
@ -1149,6 +1148,8 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
|
||||
void SetupThemeOptions(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::VerticalLayout*> container) {
|
||||
using namespace Window::Theme;
|
||||
|
||||
AddSkip(container, st::settingsPrivacySkip);
|
||||
|
||||
AddSubsectionTitle(container, tr::lng_settings_themes());
|
||||
@ -1156,20 +1157,38 @@ void SetupThemeOptions(
|
||||
AddSkip(container, st::settingsThemesTopSkip);
|
||||
SetupDefaultThemes(container);
|
||||
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(
|
||||
container,
|
||||
rpl::conditional(
|
||||
std::move(canEdit),
|
||||
tr::lng_settings_bg_edit_theme(),
|
||||
tr::lng_settings_bg_create_theme()),
|
||||
tr::lng_settings_bg_theme_edit(),
|
||||
tr::lng_settings_bg_theme_create()),
|
||||
st::settingsChatButton,
|
||||
&st::settingsIconThemes,
|
||||
st::settingsChatIconLeft
|
||||
)->addClickHandler([=] {
|
||||
controller->window().show(Box(
|
||||
Window::Theme::CreateBox,
|
||||
&controller->window()));
|
||||
if (canEditCurrent()) {
|
||||
StartEditor(
|
||||
&controller->window(),
|
||||
Background()->themeObject().cloud);
|
||||
} else {
|
||||
controller->window().show(Box(CreateBox, &controller->window()));
|
||||
}
|
||||
});
|
||||
|
||||
AddSkip(container);
|
||||
|
@ -4201,21 +4201,17 @@ Window::Theme::Saved readThemeUsingKey(FileKey key) {
|
||||
auto &cache = result.cache;
|
||||
theme.stream >> object.content;
|
||||
theme.stream >> tag >> object.pathAbsolute;
|
||||
const auto isCloud = (object.pathAbsolute == kThemePathAbsoluteCloud);
|
||||
if (tag == kThemeNewPathRelativeTag) {
|
||||
if (isCloud) {
|
||||
auto creator = qint32();
|
||||
theme.stream
|
||||
>> object.cloud.id
|
||||
>> object.cloud.accessHash
|
||||
>> object.cloud.slug
|
||||
>> object.cloud.title
|
||||
>> object.cloud.documentId
|
||||
>> creator;
|
||||
object.cloud.createdBy = creator;
|
||||
} else {
|
||||
theme.stream >> object.pathRelative;
|
||||
}
|
||||
auto creator = qint32();
|
||||
theme.stream
|
||||
>> object.pathRelative
|
||||
>> object.cloud.id
|
||||
>> object.cloud.accessHash
|
||||
>> object.cloud.slug
|
||||
>> object.cloud.title
|
||||
>> object.cloud.documentId
|
||||
>> creator;
|
||||
object.cloud.createdBy = creator;
|
||||
} else {
|
||||
object.pathRelative = tag;
|
||||
}
|
||||
@ -4224,7 +4220,7 @@ Window::Theme::Saved readThemeUsingKey(FileKey key) {
|
||||
}
|
||||
|
||||
auto ignoreCache = false;
|
||||
if (!isCloud) {
|
||||
if (!object.cloud.id) {
|
||||
QFile file(object.pathRelative);
|
||||
if (object.pathRelative.isEmpty() || !file.exists()) {
|
||||
file.setFileName(object.pathAbsolute);
|
||||
@ -4299,33 +4295,30 @@ void writeTheme(const Window::Theme::Saved &saved) {
|
||||
const auto &object = saved.object;
|
||||
const auto &cache = saved.cache;
|
||||
const auto tag = QString(kThemeNewPathRelativeTag);
|
||||
const auto isCloud = (saved.object.pathAbsolute == kThemePathAbsoluteCloud);
|
||||
quint32 size = Serialize::bytearraySize(object.content);
|
||||
size += Serialize::stringSize(tag) + Serialize::stringSize(object.pathAbsolute);
|
||||
if (isCloud) {
|
||||
size += sizeof(uint64) * 3
|
||||
+ Serialize::stringSize(object.cloud.slug)
|
||||
+ Serialize::stringSize(object.cloud.title)
|
||||
+ sizeof(qint32);
|
||||
} else {
|
||||
size += Serialize::stringSize(object.pathRelative);
|
||||
}
|
||||
size += sizeof(int32) * 2 + Serialize::bytearraySize(cache.colors) + Serialize::bytearraySize(cache.background) + sizeof(quint32);
|
||||
quint32 size = Serialize::bytearraySize(object.content)
|
||||
+ Serialize::stringSize(tag)
|
||||
+ Serialize::stringSize(object.pathAbsolute)
|
||||
+ Serialize::stringSize(object.pathRelative)
|
||||
+ sizeof(uint64) * 3
|
||||
+ Serialize::stringSize(object.cloud.slug)
|
||||
+ Serialize::stringSize(object.cloud.title)
|
||||
+ sizeof(qint32)
|
||||
+ sizeof(qint32) * 2
|
||||
+ Serialize::bytearraySize(cache.colors)
|
||||
+ Serialize::bytearraySize(cache.background)
|
||||
+ sizeof(quint32);
|
||||
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
|
||||
<< 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.contentChecksum
|
||||
<< cache.colors
|
||||
|
@ -413,7 +413,7 @@ Checkbox::Checkbox(
|
||||
text,
|
||||
_checkboxOptions,
|
||||
countTextMinWidth()) {
|
||||
_check->setUpdateCallback([=] { updateCheck(); });
|
||||
_check->setUpdateCallback([=] { update(); });
|
||||
resizeToText();
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
@ -590,8 +590,8 @@ void MainWindow::reActivateWindow() {
|
||||
}
|
||||
|
||||
void MainWindow::showRightColumn(object_ptr<TWidget> widget) {
|
||||
auto wasWidth = width();
|
||||
auto wasRightWidth = _rightColumn ? _rightColumn->width() : 0;
|
||||
const auto wasWidth = width();
|
||||
const auto wasRightWidth = _rightColumn ? _rightColumn->width() : 0;
|
||||
_rightColumn = std::move(widget);
|
||||
if (_rightColumn) {
|
||||
_rightColumn->setParent(this);
|
||||
@ -600,13 +600,14 @@ void MainWindow::showRightColumn(object_ptr<TWidget> widget) {
|
||||
} else if (App::wnd()) {
|
||||
App::wnd()->setInnerFocus();
|
||||
}
|
||||
auto nowRightWidth = _rightColumn ? _rightColumn->width() : 0;
|
||||
setMinimumWidth(st::windowMinWidth + nowRightWidth);
|
||||
const auto nowRightWidth = _rightColumn ? _rightColumn->width() : 0;
|
||||
const auto wasMaximized = isMaximized();
|
||||
if (!isMaximized()) {
|
||||
tryToExtendWidthBy(wasWidth + nowRightWidth - wasRightWidth - width());
|
||||
} else {
|
||||
updateControlsGeometry();
|
||||
}
|
||||
setMinimumWidth(st::windowMinWidth + nowRightWidth);
|
||||
}
|
||||
|
||||
int MainWindow::maximalExtendBy() const {
|
||||
|
@ -1065,8 +1065,10 @@ void Unload() {
|
||||
GlobalApplying = Applying();
|
||||
}
|
||||
|
||||
bool Apply(const QString &filepath) {
|
||||
if (auto preview = PreviewFromFile(filepath, {}, {})) {
|
||||
bool Apply(
|
||||
const QString &filepath,
|
||||
const Data::CloudTheme &cloud) {
|
||||
if (auto preview = PreviewFromFile(filepath, {}, cloud)) {
|
||||
return Apply(std::move(preview));
|
||||
}
|
||||
return false;
|
||||
|
@ -18,7 +18,6 @@ namespace Window {
|
||||
namespace Theme {
|
||||
|
||||
inline constexpr auto kThemeSchemeSizeLimit = 1024 * 1024;
|
||||
inline const auto kThemePathAbsoluteCloud = qstr("special://cloud");
|
||||
|
||||
struct Object {
|
||||
QString pathRelative;
|
||||
@ -53,7 +52,9 @@ struct 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);
|
||||
void ApplyDefaultWithPath(const QString &themePath);
|
||||
bool ApplyEditedPalette(const QString &path, const QByteArray &content);
|
||||
|
@ -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() {
|
||||
const auto letters = uint8('Z' + 1 - 'A');
|
||||
const auto digits = uint8('9' + 1 - '0');
|
||||
@ -500,6 +485,21 @@ Fn<void()> SaveTheme(
|
||||
|
||||
} // 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(
|
||||
not_null<GenericBox*> box,
|
||||
not_null<Window::Controller*> window) {
|
||||
@ -542,7 +542,9 @@ void CreateBox(
|
||||
return;
|
||||
}
|
||||
box->closeBox();
|
||||
StartEditor(window, title);
|
||||
auto cloud = Data::CloudTheme();
|
||||
cloud.title = title;
|
||||
StartEditor(window, cloud);
|
||||
};
|
||||
Ui::Connect(name, &Ui::InputField::submitted, done);
|
||||
box->addButton(tr::lng_box_done(), done);
|
||||
|
@ -9,12 +9,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/generic_box.h"
|
||||
|
||||
namespace Data {
|
||||
struct CloudTheme;
|
||||
} // namespace Data
|
||||
|
||||
namespace Window {
|
||||
|
||||
class Controller;
|
||||
|
||||
namespace Theme {
|
||||
|
||||
void StartEditor(
|
||||
not_null<Window::Controller*> window,
|
||||
const Data::CloudTheme &cloud);
|
||||
void CreateBox(
|
||||
not_null<GenericBox*> box,
|
||||
not_null<Window::Controller*> window);
|
||||
|
@ -915,17 +915,12 @@ std::unique_ptr<Preview> PreviewFromFile(
|
||||
auto result = std::make_unique<Preview>();
|
||||
auto &object = result->object;
|
||||
object.cloud = cloud;
|
||||
if (cloud.documentId || filepath.isEmpty()) {
|
||||
object.pathRelative = QString();
|
||||
object.pathAbsolute = QString(kThemePathAbsoluteCloud);
|
||||
} else {
|
||||
object.pathRelative = filepath.isEmpty()
|
||||
? QString()
|
||||
: QDir().relativeFilePath(filepath);
|
||||
object.pathAbsolute = filepath.isEmpty()
|
||||
? QString()
|
||||
: QFileInfo(filepath).absoluteFilePath();
|
||||
}
|
||||
object.pathRelative = filepath.isEmpty()
|
||||
? QString()
|
||||
: QDir().relativeFilePath(filepath);
|
||||
object.pathAbsolute = filepath.isEmpty()
|
||||
? QString()
|
||||
: QFileInfo(filepath).absoluteFilePath();
|
||||
if (bytes.isEmpty()) {
|
||||
if (!LoadFromFile(filepath, &result->instance, &object.content)) {
|
||||
return nullptr;
|
||||
|
@ -154,13 +154,13 @@ void CloudList::setup() {
|
||||
_window->session().data().cloudThemes().updated()
|
||||
);
|
||||
|
||||
auto themeChanges = rpl::single(
|
||||
BackgroundUpdate(BackgroundUpdate::Type::New, Background()->tile())
|
||||
) | rpl::then(base::ObservableViewer(
|
||||
auto themeChanges = rpl::single(BackgroundUpdate(
|
||||
BackgroundUpdate::Type::ApplyingTheme,
|
||||
Background()->tile()
|
||||
)) | rpl::then(base::ObservableViewer(
|
||||
*Background()
|
||||
)) | rpl::filter([](const BackgroundUpdate &update) {
|
||||
return (update.type == BackgroundUpdate::Type::ApplyingTheme)
|
||||
|| (update.type == BackgroundUpdate::Type::New);
|
||||
return (update.type == BackgroundUpdate::Type::ApplyingTheme);
|
||||
});
|
||||
|
||||
rpl::combine(
|
||||
|
Loading…
Reference in New Issue
Block a user