From 4951eeac98dec612cbb679a99327230f59a299f4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 5 Sep 2019 13:51:36 +0300 Subject: [PATCH] Allow creating desktop part of multi-theme. --- Telegram/Resources/langs/lang.strings | 4 + .../SourceFiles/boxes/create_poll_box.cpp | 6 +- .../SourceFiles/boxes/edit_caption_box.cpp | 11 +- Telegram/SourceFiles/boxes/edit_caption_box.h | 2 +- Telegram/SourceFiles/boxes/send_files_box.cpp | 11 +- Telegram/SourceFiles/boxes/send_files_box.h | 2 +- .../chat_helpers/emoji_suggestions_widget.cpp | 20 +- .../chat_helpers/message_field.cpp | 4 +- Telegram/SourceFiles/core/event_filter.cpp | 8 +- Telegram/SourceFiles/core/event_filter.h | 13 +- .../SourceFiles/dialogs/dialogs_widget.cpp | 8 +- .../SourceFiles/history/history_widget.cpp | 2 +- .../view/history_view_compose_controls.cpp | 2 +- .../view/history_view_scheduled_section.cpp | 8 +- Telegram/SourceFiles/settings/settings.style | 3 + .../SourceFiles/settings/settings_chat.cpp | 4 +- .../window/themes/window_theme.cpp | 10 +- .../window/themes/window_theme_editor.cpp | 10 +- .../window/themes/window_theme_editor.h | 11 +- .../window/themes/window_theme_editor_box.cpp | 73 +++-- .../window/themes/window_theme_editor_box.h | 5 + .../themes/window_themes_cloud_list.cpp | 309 +++++++++--------- .../window/themes/window_themes_cloud_list.h | 1 + .../SourceFiles/window/window_controller.cpp | 6 +- 24 files changed, 300 insertions(+), 233 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 9ef676421..7899830b9 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1603,14 +1603,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_theme_editor_choose_name" = "Save theme file"; "lng_theme_editor_error" = "The editor encountered an error :( See 'log.txt' for details."; "lng_theme_editor_sure_close" = "Are you sure you want to close the editor? Your changes won't be saved."; +"lng_theme_editor_need_auth" = "You need to log in to save your theme."; "lng_theme_editor_done" = "Theme exported successfully!"; "lng_theme_editor_title" = "Edit color palette"; "lng_theme_editor_export_button" = "Export theme"; "lng_theme_editor_save_button" = "Save theme"; "lng_theme_editor_create_title" = "Create theme"; +"lng_theme_editor_attach_title" = "Attach desktop theme"; +"lng_theme_editor_create" = "Create"; "lng_theme_editor_name" = "Theme name"; "lng_theme_editor_create_description" = "New theme will be based on your currently selected colors and wallpaper. Alternatively, you can import existing theme or color palette from file."; +"lng_theme_editor_attach_description" = "You can create desktop part of your theme based on your currently selected colors and wallpaper. Alternatively, you can import existing theme or color palette from file."; "lng_theme_editor_import_existing" = "Import existing theme"; "lng_theme_editor_save_title" = "Save theme"; "lng_theme_editor_link_about" = "Your theme will be updated for all users each time you change it. Anyone can install it using this link.\n\nTheme links must be longer than 5 characters and use a-z, 0-9 and underscores."; diff --git a/Telegram/SourceFiles/boxes/create_poll_box.cpp b/Telegram/SourceFiles/boxes/create_poll_box.cpp index c433314c6..c93fe3321 100644 --- a/Telegram/SourceFiles/boxes/create_poll_box.cpp +++ b/Telegram/SourceFiles/boxes/create_poll_box.cpp @@ -523,11 +523,11 @@ void Options::addEmptyOption() { Core::InstallEventFilter(field, [=](not_null event) { if (event->type() != QEvent::KeyPress || !field->getLastText().isEmpty()) { - return false; + return Core::EventFilter::Result::Continue; } const auto key = static_cast(event.get())->key(); if (key != Qt::Key_Backspace) { - return false; + return Core::EventFilter::Result::Continue; } const auto index = findField(field); @@ -536,7 +536,7 @@ void Options::addEmptyOption() { } else { _backspaceInFront.fire({}); } - return true; + return Core::EventFilter::Result::Cancel; }); _list.back().removeClicks( diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index 240e332cc..ca66c3af9 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -279,14 +279,13 @@ EditCaptionBox::EditCaptionBox( }, _wayWrap->lifetime()); } -bool EditCaptionBox::emojiFilter(not_null event) { +void EditCaptionBox::emojiFilterForGeometry(not_null event) { const auto type = event->type(); if (type == QEvent::Move || type == QEvent::Resize) { // updateEmojiPanelGeometry uses not only container geometry, but // also container children geometries that will be updated later. crl::on_main(this, [=] { updateEmojiPanelGeometry(); }); } - return false; } void EditCaptionBox::updateEmojiPanelGeometry() { @@ -718,9 +717,11 @@ void EditCaptionBox::setupEmojiPanel() { Ui::InsertEmojiAtCursor(_field->textCursor(), emoji); }, lifetime()); - _emojiFilter.reset(Core::InstallEventFilter( - container, - [=](not_null event) { return emojiFilter(event); })); + const auto filterCallback = [=](not_null event) { + emojiFilterForGeometry(event); + return Core::EventFilter::Result::Continue; + }; + _emojiFilter.reset(Core::InstallEventFilter(container, filterCallback)); _emojiToggle.create(this, st::boxAttachEmoji); _emojiToggle->installEventFilter(_emojiPanel); diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.h b/Telegram/SourceFiles/boxes/edit_caption_box.h index efdc463c1..e7b310b67 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.h +++ b/Telegram/SourceFiles/boxes/edit_caption_box.h @@ -57,7 +57,7 @@ private: void setupEmojiPanel(); void updateEmojiPanelGeometry(); - bool emojiFilter(not_null event); + void emojiFilterForGeometry(not_null event); void save(); void captionResized(); diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 1e240f110..8776c6100 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -1701,9 +1701,11 @@ void SendFilesBox::setupEmojiPanel() { Ui::InsertEmojiAtCursor(_caption->textCursor(), emoji); }, lifetime()); - _emojiFilter.reset(Core::InstallEventFilter( - container, - [=](not_null event) { return emojiFilter(event); })); + const auto filterCallback = [=](not_null event) { + emojiFilterForGeometry(event); + return Core::EventFilter::Result::Continue; + }; + _emojiFilter.reset(Core::InstallEventFilter(container, filterCallback)); _emojiToggle.create(this, st::boxAttachEmoji); _emojiToggle->setVisible(!_caption->isHidden()); @@ -1713,14 +1715,13 @@ void SendFilesBox::setupEmojiPanel() { }); } -bool SendFilesBox::emojiFilter(not_null event) { +void SendFilesBox::emojiFilterForGeometry(not_null event) { const auto type = event->type(); if (type == QEvent::Move || type == QEvent::Resize) { // updateEmojiPanelGeometry uses not only container geometry, but // also container children geometries that will be updated later. crl::on_main(this, [=] { updateEmojiPanelGeometry(); }); } - return false; } void SendFilesBox::updateEmojiPanelGeometry() { diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index 401a37306..a3e6beda2 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -102,7 +102,7 @@ private: void setupEmojiPanel(); void updateEmojiPanelGeometry(); - bool emojiFilter(not_null event); + void emojiFilterForGeometry(not_null event); void refreshAlbumMediaCount(); void preparePreview(); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp index 1cfa6ba0b..bfa911513 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp @@ -521,12 +521,20 @@ SuggestionsController::SuggestionsController( setReplaceCallback(nullptr); - _fieldFilter.reset(Core::InstallEventFilter( - _field, - [=](not_null event) { return fieldFilter(event); })); - _outerFilter.reset(Core::InstallEventFilter( - outer, - [=](not_null event) { return outerFilter(event); })); + const auto fieldCallback = [=](not_null event) { + return fieldFilter(event) + ? Core::EventFilter::Result::Cancel + : Core::EventFilter::Result::Continue; + }; + _fieldFilter.reset(Core::InstallEventFilter(_field, fieldCallback)); + + const auto outerCallback = [=](not_null event) { + return outerFilter(event) + ? Core::EventFilter::Result::Cancel + : Core::EventFilter::Result::Continue; + }; + _outerFilter.reset(Core::InstallEventFilter(outer, outerCallback)); + QObject::connect( _field, &QTextEdit::textChanged, diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index f5b149123..c8ff1d161 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -822,8 +822,8 @@ void SetupSendMenu( }; Core::InstallEventFilter(button, [=](not_null e) { if (e->type() == QEvent::ContextMenu && showMenu()) { - return true; + return Core::EventFilter::Result::Cancel; } - return false; + return Core::EventFilter::Result::Continue; }); } diff --git a/Telegram/SourceFiles/core/event_filter.cpp b/Telegram/SourceFiles/core/event_filter.cpp index 63422f26c..37e3e7cf3 100644 --- a/Telegram/SourceFiles/core/event_filter.cpp +++ b/Telegram/SourceFiles/core/event_filter.cpp @@ -12,26 +12,26 @@ namespace Core { EventFilter::EventFilter( not_null parent, not_null object, - Fn)> filter) + Fn)> filter) : QObject(parent) , _filter(std::move(filter)) { object->installEventFilter(this); } bool EventFilter::eventFilter(QObject *watched, QEvent *event) { - return _filter(event); + return (_filter(event) == Result::Cancel); } not_null InstallEventFilter( not_null object, - Fn)> filter) { + Fn)> filter) { return InstallEventFilter(object, object, std::move(filter)); } not_null InstallEventFilter( not_null context, not_null object, - Fn)> filter) { + Fn)> filter) { return new EventFilter(context, object, std::move(filter)); } diff --git a/Telegram/SourceFiles/core/event_filter.h b/Telegram/SourceFiles/core/event_filter.h index c7d573f46..d6c847af2 100644 --- a/Telegram/SourceFiles/core/event_filter.h +++ b/Telegram/SourceFiles/core/event_filter.h @@ -11,26 +11,31 @@ namespace Core { class EventFilter : public QObject { public: + enum Result { + Continue, + Cancel, + }; + EventFilter( not_null parent, not_null object, - Fn)> filter); + Fn)> filter); protected: bool eventFilter(QObject *watched, QEvent *event); private: - Fn)> _filter; + Fn)> _filter; }; not_null InstallEventFilter( not_null object, - Fn)> filter); + Fn)> filter); not_null InstallEventFilter( not_null context, not_null object, - Fn)> filter); + Fn)> filter); } // namespace Core diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 0fdf61c5a..ef158c034 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -313,10 +313,12 @@ void Widget::setupScrollUpButton() { scrollToTop(); }); Core::InstallEventFilter(_scrollToTop, [=](not_null event) { - if (event->type() == QEvent::Wheel) { - return _scroll->viewportEvent(event); + if (event->type() != QEvent::Wheel) { + return Core::EventFilter::Result::Continue; } - return false; + return _scroll->viewportEvent(event) + ? Core::EventFilter::Result::Cancel + : Core::EventFilter::Result::Continue; }); updateScrollUpVisibility(); } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 40c4d3101..13c2f2575 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -679,7 +679,7 @@ void HistoryWidget::initTabbedSelector() { if (_tabbedPanel && e->type() == QEvent::ParentChange) { setTabbedPanel(nullptr); } - return false; + return Core::EventFilter::Result::Continue; }); selector->emojiChosen( diff --git a/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp index 8ff11742e..08344c352 100644 --- a/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp @@ -230,7 +230,7 @@ void ComposeControls::initTabbedSelector() { if (_tabbedPanel && e->type() == QEvent::ParentChange) { setTabbedPanel(nullptr); } - return false; + return Core::EventFilter::Result::Continue; }); selector->emojiChosen( diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index d4da0b589..0938a5a2d 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -549,10 +549,12 @@ void ScheduledWidget::setupScrollDownButton() { scrollDownClicked(); }); Core::InstallEventFilter(_scrollDown, [=](not_null event) { - if (event->type() == QEvent::Wheel) { - return _scroll->viewportEvent(event); + if (event->type() != QEvent::Wheel) { + return Core::EventFilter::Result::Continue; } - return false; + return _scroll->viewportEvent(event) + ? Core::EventFilter::Result::Cancel + : Core::EventFilter::Result::Continue; }); updateScrollDownVisibility(); } diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 6d891ded8..fc9e71d41 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -190,6 +190,9 @@ settingsThemeBubbleSkip: 6px; settingsThemeRadioBottom: 12px; settingsThemeMinSkip: 4px; +settingsThemeNotSupportedBg: windowBgOver; +settingsThemeNotSupportedIcon: icon {{ "theme_preview", menuIconFg }}; + autoDownloadLimitButton: InfoProfileButton(settingsButton) { padding: margins(22px, 10px, 22px, 0px); } diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index 2d1a0ff5f..25c1d7abd 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -1078,7 +1078,9 @@ void SetupDefaultThemes(not_null container) { } } }; - + group->setChangedCallback([=](Type type) { + group->setValue(chosen()); + }); for (const auto &scheme : kSchemesList) { refreshColorizer(scheme.type); } diff --git a/Telegram/SourceFiles/window/themes/window_theme.cpp b/Telegram/SourceFiles/window/themes/window_theme.cpp index 5a081d8c5..11a030635 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme.cpp @@ -277,7 +277,7 @@ bool loadTheme( zlib::FileToRead file(content); const auto emptyColorizer = Colorizer(); - const auto &applyColorizer = editedPalette ? emptyColorizer : colorizer; + const auto &paletteColorizer = editedPalette ? emptyColorizer : colorizer; unz_global_info globalInfo = { 0 }; file.getGlobalInfo(&globalInfo); @@ -294,7 +294,7 @@ bool loadTheme( LOG(("Theme Error: could not read 'colors.tdesktop-theme' or 'colors.tdesktop-palette' in the theme file.")); return false; } - if (!loadColorScheme(schemeContent, applyColorizer, out)) { + if (!loadColorScheme(schemeContent, paletteColorizer, out)) { return false; } Background()->saveAdjustableColors(); @@ -333,7 +333,7 @@ bool loadTheme( } } else { // Looks like it is not a .zip theme. - if (!loadColorScheme(editedPalette.value_or(content), applyColorizer, out)) { + if (!loadColorScheme(editedPalette.value_or(content), paletteColorizer, out)) { return false; } Background()->saveAdjustableColors(); @@ -403,9 +403,7 @@ bool InitializeFromSaved(Saved &&saved) { return true; } - const auto colorizer = editing - ? Colorizer() - : ColorizerForTheme(saved.object.pathAbsolute); + const auto colorizer = ColorizerForTheme(saved.object.pathAbsolute); if (!loadTheme(saved.object.content, editing, saved.cache, colorizer)) { return false; } diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor.cpp b/Telegram/SourceFiles/window/themes/window_theme_editor.cpp index bd8aa0483..675f54058 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_editor.cpp @@ -620,8 +620,12 @@ void Editor::Inner::applyEditing(const QString &name, const QString ©Of, QCo // }); //} -Editor::Editor(QWidget*, not_null window) +Editor::Editor( + QWidget*, + not_null window, + const Data::CloudTheme &cloud) : _window(window) +, _cloud(cloud) , _scroll(this, st::themesScroll) , _close(this, st::contactsMultiSelect.fieldCancel) , _select(this, st::contactsMultiSelect, tr::lng_country_ph()) @@ -678,10 +682,10 @@ Editor::Editor(QWidget*, not_null window) void Editor::save() { if (!_window->account().sessionExists()) { - //_window->show(Box()) + Ui::Toast::Show(tr::lng_theme_editor_need_auth(tr::now)); return; } - Ui::show(Box(SaveThemeBox, _window, _inner->paletteContent())); + Ui::show(Box(SaveThemeBox, _window, _cloud, _inner->paletteContent())); } void Editor::resizeEvent(QResizeEvent *e) { diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor.h b/Telegram/SourceFiles/window/themes/window_theme_editor.h index ae1c6cee7..84ec3ef5b 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor.h +++ b/Telegram/SourceFiles/window/themes/window_theme_editor.h @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "data/data_cloud_themes.h" + namespace Ui { class FlatButton; class ScrollArea; @@ -28,7 +30,10 @@ bool CopyColorsToPalette( class Editor : public TWidget { public: - Editor(QWidget*, not_null window); + Editor( + QWidget*, + not_null window, + const Data::CloudTheme &cloud); protected: void paintEvent(QPaintEvent *e) override; @@ -41,7 +46,9 @@ private: void save(); void closeEditor(); - not_null _window; + const not_null _window; + const Data::CloudTheme _cloud; + object_ptr _scroll; class Inner; QPointer _inner; diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp index 0a050e53e..4aa85fa3b 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp @@ -23,11 +23,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/localstorage.h" #include "core/file_utilities.h" #include "core/application.h" +#include "core/event_filter.h" #include "lang/lang_keys.h" #include "base/zlib_help.h" #include "base/unixtime.h" #include "data/data_session.h" #include "data/data_document.h" +#include "data/data_cloud_themes.h" #include "storage/file_upload.h" #include "mainwindow.h" #include "layout.h" @@ -498,63 +500,71 @@ void StartEditor( return; } Background()->setIsEditingTheme(true); - window->showRightColumn(Box(window)); + window->showRightColumn(Box(window, cloud)); } void CreateBox( not_null box, not_null window) { - Expects(window->account().sessionExists()); + CreateForExistingBox(box, window, Data::CloudTheme()); +} - box->setTitle(tr::lng_theme_editor_create_title(Ui::Text::WithEntities)); +void CreateForExistingBox( + not_null box, + not_null window, + const Data::CloudTheme &cloud) { + const auto userId = window->account().sessionExists() + ? window->account().session().userId() + : UserId(-1); + const auto amCreator = window->account().sessionExists() + && (window->account().session().userId() == cloud.createdBy); + box->setTitle(amCreator + ? (rpl::single(cloud.title) | Ui::Text::ToWithEntities()) + : tr::lng_theme_editor_create_title(Ui::Text::WithEntities)); - const auto name = box->addRow(object_ptr( + box->addRow(object_ptr( box, - st::defaultInputField, - tr::lng_theme_editor_name())); - - box->addRow( - object_ptr( - box, - tr::lng_theme_editor_create_description(), - st::boxDividerLabel), - style::margins( - st::boxRowPadding.left(), - st::boxRowPadding.left(), - st::boxRowPadding.right(), - st::boxRowPadding.right())); + (amCreator + ? tr::lng_theme_editor_attach_description + : tr::lng_theme_editor_create_description)(), + st::boxDividerLabel)); box->addRow( object_ptr( box, tr::lng_theme_editor_import_existing() | Ui::Text::ToUpper(), st::createThemeImportButton), - style::margins() + style::margins( + 0, + st::boxRowPadding.left(), + 0, + 0) )->addClickHandler([=] { ImportFromFile(&window->account().session(), box); }); - box->setFocusCallback([=] { name->setFocusFast(); }); - const auto done = [=] { - const auto title = name->getLastText().trimmed(); - if (title.isEmpty()) { - name->showError(); - return; - } box->closeBox(); - auto cloud = Data::CloudTheme(); - cloud.title = title; StartEditor(window, cloud); }; - Ui::Connect(name, &Ui::InputField::submitted, done); - box->addButton(tr::lng_box_done(), done); + Core::InstallEventFilter(box, box, [=](not_null event) { + if (event->type() == QEvent::KeyPress) { + const auto key = static_cast(event.get())->key(); + if (key == Qt::Key_Enter || key == Qt::Key_Return) { + done(); + return Core::EventFilter::Result::Cancel; + } + } + return Core::EventFilter::Result::Continue; + }); + box->addButton(tr::lng_theme_editor_create(), done); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); } void SaveThemeBox( not_null box, not_null window, + const Data::CloudTheme &cloud, const QByteArray &palette) { Expects(window->account().sessionExists()); @@ -571,7 +581,8 @@ void SaveThemeBox( const auto name = box->addRow(object_ptr( box, st::defaultInputField, - tr::lng_theme_editor_name())); + tr::lng_theme_editor_name(), + cloud.title)); const auto linkWrap = box->addRow( object_ptr(box), style::margins( @@ -583,7 +594,7 @@ void SaveThemeBox( linkWrap, st::createThemeLink, rpl::single(qsl("link")), - GenerateSlug(), + cloud.slug, true); linkWrap->widthValue( ) | rpl::start_with_next([=](int width) { diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor_box.h b/Telegram/SourceFiles/window/themes/window_theme_editor_box.h index 095c879d7..158da4575 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor_box.h +++ b/Telegram/SourceFiles/window/themes/window_theme_editor_box.h @@ -25,9 +25,14 @@ void StartEditor( void CreateBox( not_null box, not_null window); +void CreateForExistingBox( + not_null box, + not_null window, + const Data::CloudTheme &cloud); void SaveThemeBox( not_null box, not_null window, + const Data::CloudTheme &cloud, const QByteArray &palette); } // namespace Theme diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp index fc758e83b..9ea9acd23 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp @@ -8,8 +8,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/themes/window_themes_cloud_list.h" #include "window/themes/window_themes_embedded.h" +#include "window/themes/window_theme_editor_box.h" #include "window/themes/window_theme.h" #include "window/window_session_controller.h" +#include "window/window_controller.h" #include "data/data_cloud_themes.h" #include "data/data_file_origin.h" #include "data/data_document.h" @@ -109,6 +111,153 @@ constexpr auto kShowPerRow = 4; } // namespace +CloudListColors ColorsFromScheme(const EmbeddedScheme &scheme) { + auto result = CloudListColors(); + result.sent = scheme.sent; + result.received = scheme.received; + result.radiobuttonActive = scheme.radiobuttonActive; + result.radiobuttonInactive = scheme.radiobuttonInactive; + result.background = QImage( + QSize(1, 1) * cIntRetinaFactor(), + QImage::Format_ARGB32_Premultiplied); + result.background.fill(scheme.background); + return result; +} + +CloudListColors ColorsFromScheme( + const EmbeddedScheme &scheme, + const Colorizer &colorizer) { + if (!colorizer) { + return ColorsFromScheme(scheme); + } + auto copy = scheme; + Colorize(copy, colorizer); + return ColorsFromScheme(copy); +} + +CloudListCheck::CloudListCheck(const Colors &colors, bool checked) +: CloudListCheck(checked) { + setColors(colors); +} + +CloudListCheck::CloudListCheck(bool checked) +: AbstractCheckView(st::defaultRadio.duration, checked, nullptr) +, _radio(st::defaultRadio, checked, [=] { update(); }) { +} + +void CloudListCheck::setColors(const Colors &colors) { + _colors = colors; + _radio.setToggledOverride(_colors->radiobuttonActive); + _radio.setUntoggledOverride(_colors->radiobuttonInactive); + const auto size = st::settingsThemePreviewSize * cIntRetinaFactor(); + _backgroundFull = (_colors->background.size() == size) + ? _colors->background + : _colors->background.scaled( + size, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + _backgroundCacheWidth = -1; + update(); +} + +QSize CloudListCheck::getSize() const { + return st::settingsThemePreviewSize; +} + +void CloudListCheck::validateBackgroundCache(int width) { + if (_backgroundCacheWidth == width || width <= 0) { + return; + } + _backgroundCacheWidth = width; + const auto imageWidth = width * cIntRetinaFactor(); + _backgroundCache = (width == st::settingsThemePreviewSize.width()) + ? _backgroundFull + : _backgroundFull.copy( + (_backgroundFull.width() - imageWidth) / 2, + 0, + imageWidth, + _backgroundFull.height()); + Images::prepareRound(_backgroundCache, ImageRoundRadius::Large); +} + +void CloudListCheck::paint(Painter &p, int left, int top, int outerWidth) { + if (!_colors) { + return; + } else if (_colors->background.isNull()) { + paintNotSupported(p, left, top, outerWidth); + } else { + paintWithColors(p, left, top, outerWidth); + } +} + +void CloudListCheck::paintNotSupported( + Painter &p, + int left, + int top, + int outerWidth) { + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + p.setBrush(st::settingsThemeNotSupportedBg); + + const auto height = st::settingsThemePreviewSize.height(); + const auto rect = QRect(0, 0, outerWidth, height); + const auto radius = st::historyMessageRadius; + p.drawRoundedRect(rect, radius, radius); + st::settingsThemeNotSupportedIcon.paintInCenter(p, rect); +} + +void CloudListCheck::paintWithColors( + Painter &p, + int left, + int top, + int outerWidth) { + Expects(_colors.has_value()); + + validateBackgroundCache(outerWidth); + p.drawImage( + QRect(0, 0, outerWidth, st::settingsThemePreviewSize.height()), + _backgroundCache); + + const auto received = QRect( + st::settingsThemeBubblePosition, + st::settingsThemeBubbleSize); + const auto sent = QRect( + outerWidth - received.width() - st::settingsThemeBubblePosition.x(), + received.y() + received.height() + st::settingsThemeBubbleSkip, + received.width(), + received.height()); + const auto radius = st::settingsThemeBubbleRadius; + + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + + p.setBrush(_colors->received); + p.drawRoundedRect(rtlrect(received, outerWidth), radius, radius); + p.setBrush(_colors->sent); + p.drawRoundedRect(rtlrect(sent, outerWidth), radius, radius); + + const auto skip = st::settingsThemeRadioBottom / 2; + + const auto radio = _radio.getSize(); + _radio.paint( + p, + (outerWidth - radio.width()) / 2, + getSize().height() - radio.height() - st::settingsThemeRadioBottom, + outerWidth); +} + +QImage CloudListCheck::prepareRippleMask() const { + return QImage(); +} + +bool CloudListCheck::checkRippleStartPosition(QPoint position) const { + return false; +} + +void CloudListCheck::checkedChangedHook(anim::type animated) { + _radio.setChecked(checked(), animated); +} + CloudList::CloudList( not_null parent, not_null window) @@ -322,7 +471,7 @@ void CloudList::insert(int index, const Data::CloudTheme &theme) { button->setAllowTextLines(2); button->setTextBreakEverywhere(); button->show(); - button->setClickedCallback([=] { + button->addClickHandler([=] { const auto i = ranges::find(_elements, id, &Element::id); if (i == end(_elements) || id == kFakeCloudThemeId @@ -331,7 +480,10 @@ void CloudList::insert(int index, const Data::CloudTheme &theme) { } const auto documentId = i->theme.documentId; if (!documentId) { - // #TODO themes + if (amCreator(i->theme)) { + _window->window().show( + Box(CreateForExistingBox, &_window->window(), i->theme)); + } return; } const auto document = _window->session().data().document(documentId); @@ -382,7 +534,12 @@ void CloudList::refreshColors(Element &element) { void CloudList::setWaiting(Element &element, bool waiting) { element.waiting = waiting; - element.button->setPointerCursor(!waiting); + element.button->setPointerCursor( + !waiting && (element.theme.documentId || amCreator(element.theme))); +} + +bool CloudList::amCreator(const Data::CloudTheme &theme) const { + return (_window->session().userId() == theme.createdBy); } void CloudList::refreshColorsFromDocument( @@ -479,151 +636,5 @@ int CloudList::resizeGetHeight(int newWidth) { : 0; } -CloudListColors ColorsFromScheme(const EmbeddedScheme &scheme) { - auto result = CloudListColors(); - result.sent = scheme.sent; - result.received = scheme.received; - result.radiobuttonActive = scheme.radiobuttonActive; - result.radiobuttonInactive = scheme.radiobuttonInactive; - result.background = QImage( - QSize(1, 1) * cIntRetinaFactor(), - QImage::Format_ARGB32_Premultiplied); - result.background.fill(scheme.background); - return result; -} - -CloudListColors ColorsFromScheme( - const EmbeddedScheme &scheme, - const Colorizer &colorizer) { - if (!colorizer) { - return ColorsFromScheme(scheme); - } - auto copy = scheme; - Colorize(copy, colorizer); - return ColorsFromScheme(copy); -} - -CloudListCheck::CloudListCheck(const Colors &colors, bool checked) -: CloudListCheck(checked) { - setColors(colors); -} - -CloudListCheck::CloudListCheck(bool checked) -: AbstractCheckView(st::defaultRadio.duration, checked, nullptr) -, _radio(st::defaultRadio, checked, [=] { update(); }) { -} - -void CloudListCheck::setColors(const Colors &colors) { - _colors = colors; - _radio.setToggledOverride(_colors->radiobuttonActive); - _radio.setUntoggledOverride(_colors->radiobuttonInactive); - const auto size = st::settingsThemePreviewSize * cIntRetinaFactor(); - _backgroundFull = (_colors->background.size() == size) - ? _colors->background - : _colors->background.scaled( - size, - Qt::IgnoreAspectRatio, - Qt::SmoothTransformation); - _backgroundCacheWidth = -1; - update(); -} - -QSize CloudListCheck::getSize() const { - return st::settingsThemePreviewSize; -} - -void CloudListCheck::validateBackgroundCache(int width) { - if (_backgroundCacheWidth == width || width <= 0) { - return; - } - _backgroundCacheWidth = width; - const auto imageWidth = width * cIntRetinaFactor(); - _backgroundCache = (width == st::settingsThemePreviewSize.width()) - ? _backgroundFull - : _backgroundFull.copy( - (_backgroundFull.width() - imageWidth) / 2, - 0, - imageWidth, - _backgroundFull.height()); - Images::prepareRound(_backgroundCache, ImageRoundRadius::Large); -} - -void CloudListCheck::paint(Painter &p, int left, int top, int outerWidth) { - if (!_colors) { - return; - } else if (_colors->background.isNull()) { - paintNotSupported(p, left, top, outerWidth); - } else { - paintWithColors(p, left, top, outerWidth); - } -} - -void CloudListCheck::paintNotSupported( - Painter &p, - int left, - int top, - int outerWidth) { - PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); - p.setBrush(st::windowBgOver); - - p.drawRoundedRect( - QRect(0, 0, outerWidth, st::settingsThemePreviewSize.height()), - st::historyMessageRadius, - st::historyMessageRadius); -} - -void CloudListCheck::paintWithColors( - Painter &p, - int left, - int top, - int outerWidth) { - Expects(_colors.has_value()); - - validateBackgroundCache(outerWidth); - p.drawImage( - QRect(0, 0, outerWidth, st::settingsThemePreviewSize.height()), - _backgroundCache); - - const auto received = QRect( - st::settingsThemeBubblePosition, - st::settingsThemeBubbleSize); - const auto sent = QRect( - outerWidth - received.width() - st::settingsThemeBubblePosition.x(), - received.y() + received.height() + st::settingsThemeBubbleSkip, - received.width(), - received.height()); - const auto radius = st::settingsThemeBubbleRadius; - - PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); - - p.setBrush(_colors->received); - p.drawRoundedRect(rtlrect(received, outerWidth), radius, radius); - p.setBrush(_colors->sent); - p.drawRoundedRect(rtlrect(sent, outerWidth), radius, radius); - - const auto skip = st::settingsThemeRadioBottom / 2; - - const auto radio = _radio.getSize(); - _radio.paint( - p, - (outerWidth - radio.width()) / 2, - getSize().height() - radio.height() - st::settingsThemeRadioBottom, - outerWidth); -} - -QImage CloudListCheck::prepareRippleMask() const { - return QImage(); -} - -bool CloudListCheck::checkRippleStartPosition(QPoint position) const { - return false; -} - -void CloudListCheck::checkedChangedHook(anim::type animated) { - _radio.setChecked(checked(), animated); -} - } // namespace Theme } // namespace Window diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h index 4205ced95..740aec319 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h @@ -106,6 +106,7 @@ private: int resizeGetHeight(int newWidth); void updateGeometry(); + [[nodiscard]] bool amCreator(const Data::CloudTheme &theme) const; [[nodiscard]] int groupValueForId(uint64 id); const not_null _window; diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 98f71e2ee..0b6372612 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -45,8 +45,10 @@ void Controller::firstShow() { } void Controller::checkThemeEditor() { - if (Window::Theme::Background()->isEditingTheme()) { - showRightColumn(Box(this)); + using namespace Window::Theme; + if (Background()->isEditingTheme()) { + showRightColumn( + Box(this, Background()->themeObject().cloud)); } }