Added applying of chat theme from custom themes list.

This commit is contained in:
23rd
2026-07-03 21:06:29 +03:00
committed by John Preston
parent 4b3e2646a6
commit 5115314726
3 changed files with 97 additions and 31 deletions
@@ -481,7 +481,7 @@ void CloudThemes::parseThemes(const QVector<MTPTheme> &list) {
_list.clear();
_list.reserve(list.size());
for (const auto &theme : list) {
_list.push_back(CloudTheme::Parse(_session, theme));
_list.push_back(CloudTheme::Parse(_session, theme, true));
}
checkCurrentTheme();
}
@@ -7,8 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "window/themes/window_themes_cloud_list.h"
#include "base/call_delayed.h"
#include "ui/emoji_config.h"
#include "window/themes/window_themes_embedded.h"
#include "window/themes/window_theme_editor_box.h"
#include "window/themes/window_themes_chat.h"
#include "window/themes/window_theme.h"
#include "window/window_session_controller.h"
#include "window/window_controller.h"
@@ -50,6 +53,18 @@ constexpr auto kShowPerRow = 4;
return result;
}
[[nodiscard]] bool ContainsThemeWithEmoticon(
const std::vector<Data::CloudTheme> &list,
const QString &emoticon) {
const auto emoji = Ui::Emoji::Find(emoticon);
if (!emoji) {
return false;
}
return ranges::contains(list, emoji, [](const Data::CloudTheme &theme) {
return Ui::Emoji::Find(theme.emoticon);
});
}
[[nodiscard]] QImage ColorsBackgroundFromImage(const QImage &source) {
if (source.isNull()) {
return source;
@@ -110,6 +125,38 @@ constexpr auto kShowPerRow = 4;
return result;
}
[[nodiscard]] CloudListColors ColorsFromTheme(
const Data::CloudTheme &theme) {
const auto dark = IsNightMode();
const auto used = ChatThemeVariant(theme, dark);
Assert(used.has_value());
const auto &settings = theme.settings.find(*used)->second;
auto result = CloudListColors();
result.sent = settings.outgoingMessagesColors.empty()
? settings.accentColor
: settings.outgoingMessagesColors.front();
result.received = dark ? QColor(24, 24, 25) : QColor(255, 255, 255);
result.radiobuttonActive
= result.radiobuttonInactive
= (dark ? QColor(255, 255, 255) : settings.accentColor);
const auto paperColors = settings.paper
? settings.paper->backgroundColors()
: std::vector<QColor>();
if (paperColors.size() > 1) {
result.background = Images::GenerateLinearGradient(
QSize(80, 80) * style::DevicePixelRatio(),
paperColors);
} else {
result.background = QImage(
QSize(1, 1) * style::DevicePixelRatio(),
QImage::Format_ARGB32_Premultiplied);
result.background.fill(paperColors.empty()
? settings.accentColor
: paperColors.front());
}
return result;
}
[[nodiscard]] CloudListColors ColorsFromCurrentTheme() {
auto result = CloudListColors();
auto background = Background()->createCurrentImage();
@@ -334,9 +381,15 @@ rpl::producer<bool> CloudList::allShown() const {
void CloudList::setup() {
_group->setChangedCallback([=](int selected) {
const auto &object = Background()->themeObject();
_group->setValue(groupValueForId(
object.cloud.id ? object.cloud.id : kFakeCloudThemeId));
const auto i = ranges::find_if(_elements, [&](const Element &e) {
return (groupValueForId(e.theme.id) == selected)
&& !e.theme.emoticon.isEmpty()
&& !e.theme.settings.empty();
});
if (i != end(_elements)) {
return;
}
_group->setValue(groupValueForId(appliedElementId()));
});
auto cloudListChanges = rpl::single(rpl::empty) | rpl::then(
@@ -377,7 +430,8 @@ std::vector<Data::CloudTheme> CloudList::collectAll() const {
result,
object.cloud.id,
&Data::CloudTheme::id);
if (i == end(result)) {
if (i == end(result)
&& !ContainsThemeWithEmoticon(result, object.cloud.emoticon)) {
if (object.cloud.id) {
result.push_back(object.cloud);
} else {
@@ -407,37 +461,16 @@ bool CloudList::applyChangesFrom(std::vector<Data::CloudTheme> &&list) {
}
auto changed = false;
const auto limit = _showAll.current() ? list.size() : kShowPerRow;
const auto &object = Background()->themeObject();
const auto id = object.cloud.id ? object.cloud.id : kFakeCloudThemeId;
ranges::stable_sort(list, std::less<>(), [&](const Data::CloudTheme &t) {
if (t.id == id) {
return 0;
} else if (t.documentId) {
return 1;
} else {
return 2;
}
ranges::stable_sort(list, std::less<>(), [](const Data::CloudTheme &t) {
return t.documentId ? 0 : 1;
});
if (list.front().id == id) {
const auto j = ranges::find(_elements, id, &Element::id);
if (j == end(_elements)) {
insert(0, list.front());
changed = true;
} else if (j - begin(_elements) >= limit) {
std::rotate(
begin(_elements) + limit - 1,
j,
j + 1);
changed = true;
}
}
if (removeStaleUsing(list)) {
changed = true;
}
if (insertTillLimit(list, limit)) {
changed = true;
}
_group->setValue(groupValueForId(id));
_group->setValue(groupValueForId(appliedElementId()));
return changed;
}
@@ -526,8 +559,18 @@ void CloudList::insert(int index, const Data::CloudTheme &theme) {
if (button == Qt::RightButton) {
showMenu(*i);
} else if (cloud.documentId) {
++*_applyGeneration;
_window->session().data().cloudThemes().applyFromDocument(cloud);
} else if (!cloud.emoticon.isEmpty() && !cloud.settings.empty()) {
const auto generation = ++*_applyGeneration;
const auto check = _applyGeneration;
base::call_delayed(st::defaultRadio.duration, _window, [=] {
if (*check == generation) {
ApplyChatTheme(_window, cloud, IsNightMode());
}
});
} else {
++*_applyGeneration;
_window->session().data().cloudThemes().showPreview(
&_window->window(),
cloud);
@@ -577,6 +620,9 @@ void CloudList::refreshColors(Element &element) {
setWaiting(element, true);
subscribeToDownloadFinished();
}
} else if (!theme.settings.empty()) {
element.check->setColors(ColorsFromTheme(theme));
setWaiting(element, false);
} else {
element.check->setColors(CloudListColors());
}
@@ -638,14 +684,32 @@ void CloudList::showMenu(Element &element) {
void CloudList::setWaiting(Element &element, bool waiting) {
element.waiting = waiting;
element.button->setPointerCursor(
!waiting && (element.theme.documentId || amCreator(element.theme)));
element.button->setPointerCursor(!waiting
&& (element.theme.documentId
|| amCreator(element.theme)
|| !element.theme.settings.empty()));
}
bool CloudList::amCreator(const Data::CloudTheme &theme) const {
return (_window->session().userId() == theme.createdBy);
}
uint64 CloudList::appliedElementId() const {
const auto &cloud = Background()->themeObject().cloud;
const auto id = cloud.id ? cloud.id : kFakeCloudThemeId;
if (ranges::contains(_elements, id, &Element::id)) {
return id;
}
const auto emoji = Ui::Emoji::Find(cloud.emoticon);
if (!emoji) {
return id;
}
const auto i = ranges::find(_elements, emoji, [](const Element &element) {
return Ui::Emoji::Find(element.theme.emoticon);
});
return (i != end(_elements)) ? i->id() : id;
}
void CloudList::refreshColorsFromDocument(Element &element) {
Expects(element.media != nullptr);
Expects(element.media->loaded());
@@ -118,6 +118,7 @@ private:
void updateGeometry();
[[nodiscard]] bool amCreator(const Data::CloudTheme &theme) const;
[[nodiscard]] uint64 appliedElementId() const;
[[nodiscard]] int groupValueForId(uint64 id);
const not_null<Window::SessionController*> _window;
@@ -131,6 +132,7 @@ private:
base::flat_map<uint64, int> _groupValueById;
rpl::lifetime _downloadFinishedLifetime;
base::unique_qptr<Ui::PopupMenu> _contextMenu;
std::shared_ptr<int> _applyGeneration = std::make_shared<int>(0);
};