mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show custom chat wallpapers in chats.
This commit is contained in:
parent
5cbf9a2dc4
commit
bf27185feb
20 changed files with 369 additions and 121 deletions
|
@ -764,7 +764,10 @@ bool ResolveTestChatTheme(
|
||||||
}
|
}
|
||||||
const auto recache = [&](Data::CloudThemeType type) {
|
const auto recache = [&](Data::CloudThemeType type) {
|
||||||
[[maybe_unused]] auto value = theme->settings.contains(type)
|
[[maybe_unused]] auto value = theme->settings.contains(type)
|
||||||
? controller->cachedChatThemeValue(*theme, type)
|
? controller->cachedChatThemeValue(
|
||||||
|
*theme,
|
||||||
|
Data::WallPaper(0),
|
||||||
|
type)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
};
|
};
|
||||||
recache(Data::CloudThemeType::Dark);
|
recache(Data::CloudThemeType::Dark);
|
||||||
|
|
|
@ -64,45 +64,46 @@ struct PeerUpdate {
|
||||||
Migration = (1ULL << 5),
|
Migration = (1ULL << 5),
|
||||||
UnavailableReason = (1ULL << 6),
|
UnavailableReason = (1ULL << 6),
|
||||||
ChatThemeEmoji = (1ULL << 7),
|
ChatThemeEmoji = (1ULL << 7),
|
||||||
IsBlocked = (1ULL << 8),
|
ChatWallPaper = (1ULL << 8),
|
||||||
MessagesTTL = (1ULL << 9),
|
IsBlocked = (1ULL << 9),
|
||||||
FullInfo = (1ULL << 10),
|
MessagesTTL = (1ULL << 10),
|
||||||
Usernames = (1ULL << 11),
|
FullInfo = (1ULL << 11),
|
||||||
TranslationDisabled = (1ULL << 12),
|
Usernames = (1ULL << 12),
|
||||||
|
TranslationDisabled = (1ULL << 13),
|
||||||
|
|
||||||
// For users
|
// For users
|
||||||
CanShareContact = (1ULL << 13),
|
CanShareContact = (1ULL << 14),
|
||||||
IsContact = (1ULL << 14),
|
IsContact = (1ULL << 15),
|
||||||
PhoneNumber = (1ULL << 15),
|
PhoneNumber = (1ULL << 16),
|
||||||
OnlineStatus = (1ULL << 16),
|
OnlineStatus = (1ULL << 17),
|
||||||
BotCommands = (1ULL << 17),
|
BotCommands = (1ULL << 18),
|
||||||
BotCanBeInvited = (1ULL << 18),
|
BotCanBeInvited = (1ULL << 19),
|
||||||
BotStartToken = (1ULL << 19),
|
BotStartToken = (1ULL << 20),
|
||||||
CommonChats = (1ULL << 20),
|
CommonChats = (1ULL << 21),
|
||||||
HasCalls = (1ULL << 21),
|
HasCalls = (1ULL << 22),
|
||||||
SupportInfo = (1ULL << 22),
|
SupportInfo = (1ULL << 23),
|
||||||
IsBot = (1ULL << 23),
|
IsBot = (1ULL << 24),
|
||||||
EmojiStatus = (1ULL << 24),
|
EmojiStatus = (1ULL << 25),
|
||||||
|
|
||||||
// For chats and channels
|
// For chats and channels
|
||||||
InviteLinks = (1ULL << 25),
|
InviteLinks = (1ULL << 26),
|
||||||
Members = (1ULL << 26),
|
Members = (1ULL << 27),
|
||||||
Admins = (1ULL << 27),
|
Admins = (1ULL << 28),
|
||||||
BannedUsers = (1ULL << 28),
|
BannedUsers = (1ULL << 29),
|
||||||
Rights = (1ULL << 29),
|
Rights = (1ULL << 30),
|
||||||
PendingRequests = (1ULL << 30),
|
PendingRequests = (1ULL << 31),
|
||||||
Reactions = (1ULL << 31),
|
Reactions = (1ULL << 32),
|
||||||
|
|
||||||
// For channels
|
// For channels
|
||||||
ChannelAmIn = (1ULL << 32),
|
ChannelAmIn = (1ULL << 33),
|
||||||
StickersSet = (1ULL << 33),
|
StickersSet = (1ULL << 34),
|
||||||
ChannelLinkedChat = (1ULL << 34),
|
ChannelLinkedChat = (1ULL << 35),
|
||||||
ChannelLocation = (1ULL << 35),
|
ChannelLocation = (1ULL << 36),
|
||||||
Slowmode = (1ULL << 36),
|
Slowmode = (1ULL << 37),
|
||||||
GroupCall = (1ULL << 37),
|
GroupCall = (1ULL << 38),
|
||||||
|
|
||||||
// For iteration
|
// For iteration
|
||||||
LastUsedBit = (1ULL << 37),
|
LastUsedBit = (1ULL << 38),
|
||||||
};
|
};
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||||
|
|
|
@ -794,7 +794,7 @@ QString DocumentData::loadingFilePath() const {
|
||||||
|
|
||||||
bool DocumentData::displayLoading() const {
|
bool DocumentData::displayLoading() const {
|
||||||
return loading()
|
return loading()
|
||||||
? (!_loader->loadingLocal() || !_loader->autoLoading())
|
? !_loader->loadingLocal()
|
||||||
: (uploading() && !waitingForAlbum());
|
: (uploading() && !waitingForAlbum());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1093,6 +1093,22 @@ const QString &PeerData::themeEmoji() const {
|
||||||
return _themeEmoticon;
|
return _themeEmoticon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerData::setWallPaper(std::optional<Data::WallPaper> paper) {
|
||||||
|
if (!paper && !_wallPaper) {
|
||||||
|
return;
|
||||||
|
} else if (paper && _wallPaper && _wallPaper->equals(*paper)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_wallPaper = paper
|
||||||
|
? std::make_unique<Data::WallPaper>(std::move(*paper))
|
||||||
|
: nullptr;
|
||||||
|
session().changes().peerUpdated(this, UpdateFlag::ChatWallPaper);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Data::WallPaper *PeerData::wallPaper() const {
|
||||||
|
return _wallPaper.get();
|
||||||
|
}
|
||||||
|
|
||||||
void PeerData::setIsBlocked(bool is) {
|
void PeerData::setIsBlocked(bool is) {
|
||||||
const auto status = is
|
const auto status = is
|
||||||
? BlockStatus::Blocked
|
? BlockStatus::Blocked
|
||||||
|
|
|
@ -37,6 +37,7 @@ class ForumTopic;
|
||||||
class Session;
|
class Session;
|
||||||
class GroupCall;
|
class GroupCall;
|
||||||
struct ReactionId;
|
struct ReactionId;
|
||||||
|
class WallPaper;
|
||||||
|
|
||||||
[[nodiscard]] int PeerColorIndex(PeerId peerId);
|
[[nodiscard]] int PeerColorIndex(PeerId peerId);
|
||||||
|
|
||||||
|
@ -403,6 +404,9 @@ public:
|
||||||
void setThemeEmoji(const QString &emoticon);
|
void setThemeEmoji(const QString &emoticon);
|
||||||
[[nodiscard]] const QString &themeEmoji() const;
|
[[nodiscard]] const QString &themeEmoji() const;
|
||||||
|
|
||||||
|
void setWallPaper(std::optional<Data::WallPaper> paper);
|
||||||
|
[[nodiscard]] const Data::WallPaper *wallPaper() const;
|
||||||
|
|
||||||
const PeerId id;
|
const PeerId id;
|
||||||
MTPinputPeer input = MTP_inputPeerEmpty();
|
MTPinputPeer input = MTP_inputPeerEmpty();
|
||||||
|
|
||||||
|
@ -457,6 +461,7 @@ private:
|
||||||
|
|
||||||
QString _about;
|
QString _about;
|
||||||
QString _themeEmoticon;
|
QString _themeEmoticon;
|
||||||
|
std::unique_ptr<Data::WallPaper> _wallPaper;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
#include "data/data_emoji_statuses.h"
|
#include "data/data_emoji_statuses.h"
|
||||||
#include "data/data_user_names.h"
|
#include "data/data_user_names.h"
|
||||||
|
#include "data/data_wall_paper.h"
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "api/api_peer_photo.h"
|
#include "api/api_peer_photo.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
@ -462,6 +463,13 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const auto paper = update.vwallpaper()) {
|
||||||
|
user->setWallPaper(
|
||||||
|
Data::WallPaper::Create(&user->session(), *paper));
|
||||||
|
} else {
|
||||||
|
user->setWallPaper({});
|
||||||
|
}
|
||||||
|
|
||||||
user->fullUpdated();
|
user->fullUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,6 +198,16 @@ WallPaperId WallPaper::id() const {
|
||||||
return _id;
|
return _id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WallPaper::equals(const WallPaper &paper) const {
|
||||||
|
return (_flags == paper._flags)
|
||||||
|
&& (_slug == paper._slug)
|
||||||
|
&& (_backgroundColors == paper._backgroundColors)
|
||||||
|
&& (_rotation == paper._rotation)
|
||||||
|
&& (_intensity == paper._intensity)
|
||||||
|
&& (_blurred == paper._blurred)
|
||||||
|
&& (_document == paper._document);
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<QColor> WallPaper::backgroundColors() const {
|
const std::vector<QColor> WallPaper::backgroundColors() const {
|
||||||
return _backgroundColors;
|
return _backgroundColors;
|
||||||
}
|
}
|
||||||
|
@ -251,34 +261,54 @@ bool WallPaper::hasShareUrl() const {
|
||||||
return !_slug.isEmpty();
|
return !_slug.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WallPaper::shareUrl(not_null<Main::Session*> session) const {
|
QStringList WallPaper::collectShareParams() const {
|
||||||
if (!hasShareUrl()) {
|
auto result = QStringList();
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
const auto base = session->createInternalLinkFull("bg/" + _slug);
|
|
||||||
auto params = QStringList();
|
|
||||||
if (isPattern()) {
|
if (isPattern()) {
|
||||||
if (!backgroundColors().empty()) {
|
if (!backgroundColors().empty()) {
|
||||||
params.push_back(
|
result.push_back(
|
||||||
"bg_color=" + StringFromColors(backgroundColors()));
|
"bg_color=" + StringFromColors(backgroundColors()));
|
||||||
}
|
}
|
||||||
if (_intensity) {
|
if (_intensity) {
|
||||||
params.push_back("intensity=" + QString::number(_intensity));
|
result.push_back("intensity=" + QString::number(_intensity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_rotation && backgroundColors().size() == 2) {
|
if (_rotation && backgroundColors().size() == 2) {
|
||||||
params.push_back("rotation=" + QString::number(_rotation));
|
result.push_back("rotation=" + QString::number(_rotation));
|
||||||
}
|
}
|
||||||
auto mode = QStringList();
|
auto mode = QStringList();
|
||||||
if (_blurred) {
|
if (_blurred) {
|
||||||
mode.push_back("blur");
|
mode.push_back("blur");
|
||||||
}
|
}
|
||||||
if (!mode.isEmpty()) {
|
if (!mode.isEmpty()) {
|
||||||
params.push_back("mode=" + mode.join('+'));
|
result.push_back("mode=" + mode.join('+'));
|
||||||
}
|
}
|
||||||
return params.isEmpty()
|
return result;
|
||||||
? base
|
}
|
||||||
: base + '?' + params.join('&');
|
|
||||||
|
bool WallPaper::isNull() const {
|
||||||
|
return !_id && _slug.isEmpty() && _backgroundColors.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WallPaper::key() const {
|
||||||
|
if (isNull()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
const auto base = _slug.isEmpty()
|
||||||
|
? (_id
|
||||||
|
? QString::number(_id)
|
||||||
|
: StringFromColors(backgroundColors()))
|
||||||
|
: ("bg/" + _slug);
|
||||||
|
const auto params = collectShareParams();
|
||||||
|
return params.isEmpty() ? base : (base + '?' + params.join('&'));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WallPaper::shareUrl(not_null<Main::Session*> session) const {
|
||||||
|
if (!hasShareUrl()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
const auto base = session->createInternalLinkFull("bg/" + _slug);
|
||||||
|
const auto params = collectShareParams();
|
||||||
|
return params.isEmpty() ? base : (base + '?' + params.join('&'));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WallPaper::loadDocumentThumbnail() const {
|
void WallPaper::loadDocumentThumbnail() const {
|
||||||
|
|
|
@ -42,7 +42,11 @@ public:
|
||||||
|
|
||||||
void setLocalImageAsThumbnail(std::shared_ptr<Image> image);
|
void setLocalImageAsThumbnail(std::shared_ptr<Image> image);
|
||||||
|
|
||||||
|
[[nodiscard]] bool equals(const WallPaper &paper) const;
|
||||||
|
|
||||||
[[nodiscard]] WallPaperId id() const;
|
[[nodiscard]] WallPaperId id() const;
|
||||||
|
[[nodiscard]] bool isNull() const;
|
||||||
|
[[nodiscard]] QString key() const;
|
||||||
[[nodiscard]] const std::vector<QColor> backgroundColors() const;
|
[[nodiscard]] const std::vector<QColor> backgroundColors() const;
|
||||||
[[nodiscard]] DocumentData *document() const;
|
[[nodiscard]] DocumentData *document() const;
|
||||||
[[nodiscard]] Image *localThumbnail() const;
|
[[nodiscard]] Image *localThumbnail() const;
|
||||||
|
@ -103,6 +107,8 @@ public:
|
||||||
private:
|
private:
|
||||||
static constexpr auto kDefaultIntensity = 50;
|
static constexpr auto kDefaultIntensity = 50;
|
||||||
|
|
||||||
|
[[nodiscard]] QStringList collectShareParams() const;
|
||||||
|
|
||||||
WallPaperId _id = WallPaperId();
|
WallPaperId _id = WallPaperId();
|
||||||
uint64 _accessHash = 0;
|
uint64 _accessHash = 0;
|
||||||
UserId _ownerId = 0;
|
UserId _ownerId = 0;
|
||||||
|
|
|
@ -1264,6 +1264,9 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||||
if (!item->unread(this)) {
|
if (!item->unread(this)) {
|
||||||
outboxRead(item);
|
outboxRead(item);
|
||||||
}
|
}
|
||||||
|
if (item->changesWallPaper()) {
|
||||||
|
peer->updateFullForced();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (item->unread(this)) {
|
if (item->unread(this)) {
|
||||||
if (unreadCountKnown()) {
|
if (unreadCountKnown()) {
|
||||||
|
|
|
@ -2213,6 +2213,13 @@ bool HistoryItem::hasDirectLink() const {
|
||||||
return isRegular() && _history->peer->isChannel();
|
return isRegular() && _history->peer->isChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryItem::changesWallPaper() const {
|
||||||
|
if (const auto media = _media.get()) {
|
||||||
|
return media->paper() != nullptr;
|
||||||
|
}
|
||||||
|
return Has<HistoryServiceSameBackground>();
|
||||||
|
}
|
||||||
|
|
||||||
FullMsgId HistoryItem::fullId() const {
|
FullMsgId HistoryItem::fullId() const {
|
||||||
return FullMsgId(_history->peer->id, id);
|
return FullMsgId(_history->peer->id, id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -433,6 +433,7 @@ public:
|
||||||
[[nodiscard]] crl::time lastReactionsRefreshTime() const;
|
[[nodiscard]] crl::time lastReactionsRefreshTime() const;
|
||||||
|
|
||||||
[[nodiscard]] bool hasDirectLink() const;
|
[[nodiscard]] bool hasDirectLink() const;
|
||||||
|
[[nodiscard]] bool changesWallPaper() const;
|
||||||
|
|
||||||
[[nodiscard]] FullMsgId fullId() const;
|
[[nodiscard]] FullMsgId fullId() const;
|
||||||
[[nodiscard]] GlobalMsgId globalId() const;
|
[[nodiscard]] GlobalMsgId globalId() const;
|
||||||
|
|
|
@ -27,6 +27,12 @@ ServiceBox::ServiceBox(
|
||||||
, _content(std::move(content))
|
, _content(std::move(content))
|
||||||
, _button([&] {
|
, _button([&] {
|
||||||
auto result = Button();
|
auto result = Button();
|
||||||
|
result.link = _content->createViewLink();
|
||||||
|
|
||||||
|
const auto text = _content->button();
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
result.repaint = [=] { repaint(); };
|
result.repaint = [=] { repaint(); };
|
||||||
result.text.setText(st::semiboldTextStyle, _content->button());
|
result.text.setText(st::semiboldTextStyle, _content->button());
|
||||||
|
|
||||||
|
@ -39,8 +45,6 @@ ServiceBox::ServiceBox(
|
||||||
+ padding.right(),
|
+ padding.right(),
|
||||||
height);
|
height);
|
||||||
|
|
||||||
result.link = _content->createViewLink();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}())
|
}())
|
||||||
, _maxWidth(st::msgServiceGiftBoxSize.width()
|
, _maxWidth(st::msgServiceGiftBoxSize.width()
|
||||||
|
@ -67,8 +71,10 @@ ServiceBox::ServiceBox(
|
||||||
: (_title.countHeight(_maxWidth)
|
: (_title.countHeight(_maxWidth)
|
||||||
+ st::msgServiceGiftBoxTitlePadding.bottom()))
|
+ st::msgServiceGiftBoxTitlePadding.bottom()))
|
||||||
+ _subtitle.countHeight(_maxWidth)
|
+ _subtitle.countHeight(_maxWidth)
|
||||||
+ st::msgServiceGiftBoxButtonMargins.top()
|
+ (_button.empty()
|
||||||
+ _button.size.height()
|
? 0
|
||||||
|
: (st::msgServiceGiftBoxButtonMargins.top()
|
||||||
|
+ _button.size.height()))
|
||||||
+ st::msgServiceGiftBoxButtonMargins.bottom()))
|
+ st::msgServiceGiftBoxButtonMargins.bottom()))
|
||||||
, _innerSize(_size - QSize(0, st::msgServiceGiftBoxTopSkip)) {
|
, _innerSize(_size - QSize(0, st::msgServiceGiftBoxTopSkip)) {
|
||||||
}
|
}
|
||||||
|
@ -106,7 +112,7 @@ void ServiceBox::draw(Painter &p, const PaintContext &context) const {
|
||||||
top += _subtitle.countHeight(_maxWidth) + padding.bottom();
|
top += _subtitle.countHeight(_maxWidth) + padding.bottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (!_button.empty()) {
|
||||||
const auto position = buttonRect().topLeft();
|
const auto position = buttonRect().topLeft();
|
||||||
p.translate(position);
|
p.translate(position);
|
||||||
|
|
||||||
|
@ -142,7 +148,11 @@ void ServiceBox::draw(Painter &p, const PaintContext &context) const {
|
||||||
|
|
||||||
TextState ServiceBox::textState(QPoint point, StateRequest request) const {
|
TextState ServiceBox::textState(QPoint point, StateRequest request) const {
|
||||||
auto result = TextState(_parent);
|
auto result = TextState(_parent);
|
||||||
{
|
if (_button.empty()) {
|
||||||
|
if (QRect(QPoint(), _innerSize).contains(point)) {
|
||||||
|
result.link = _button.link;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const auto rect = buttonRect();
|
const auto rect = buttonRect();
|
||||||
if (rect.contains(point)) {
|
if (rect.contains(point)) {
|
||||||
result.link = _button.link;
|
result.link = _button.link;
|
||||||
|
@ -214,7 +224,9 @@ QRect ServiceBox::contentRect() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceBox::Button::toggleRipple(bool pressed) {
|
void ServiceBox::Button::toggleRipple(bool pressed) {
|
||||||
if (pressed) {
|
if (empty()) {
|
||||||
|
return;
|
||||||
|
} else if (pressed) {
|
||||||
const auto linkWidth = size.width();
|
const auto linkWidth = size.width();
|
||||||
const auto linkHeight = size.height();
|
const auto linkHeight = size.height();
|
||||||
if (!ripple) {
|
if (!ripple) {
|
||||||
|
@ -234,6 +246,10 @@ void ServiceBox::Button::toggleRipple(bool pressed) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ServiceBox::Button::empty() const {
|
||||||
|
return text.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
void ServiceBox::Button::drawBg(QPainter &p) const {
|
void ServiceBox::Button::drawBg(QPainter &p) const {
|
||||||
const auto radius = size.height() / 2.;
|
const auto radius = size.height() / 2.;
|
||||||
p.drawRoundedRect(0, 0, size.width(), size.height(), radius, radius);
|
p.drawRoundedRect(0, 0, size.width(), size.height(), radius, radius);
|
||||||
|
|
|
@ -88,6 +88,7 @@ private:
|
||||||
struct Button {
|
struct Button {
|
||||||
void drawBg(QPainter &p) const;
|
void drawBg(QPainter &p) const;
|
||||||
void toggleRipple(bool pressed);
|
void toggleRipple(bool pressed);
|
||||||
|
[[nodiscard]] bool empty() const;
|
||||||
|
|
||||||
Fn<void()> repaint;
|
Fn<void()> repaint;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_wall_paper.h"
|
#include "data/data_wall_paper.h"
|
||||||
#include "base/qthelp_url.h"
|
#include "base/qthelp_url.h"
|
||||||
|
#include "core/click_handler_types.h"
|
||||||
#include "core/local_url_handlers.h"
|
#include "core/local_url_handlers.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/text/format_values.h"
|
#include "ui/text/format_values.h"
|
||||||
|
@ -27,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/cached_round_corners.h"
|
#include "ui/cached_round_corners.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
@ -433,15 +435,21 @@ QString ThemeDocumentBox::subtitle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ThemeDocumentBox::button() {
|
QString ThemeDocumentBox::button() {
|
||||||
return tr::lng_sticker_premium_view(tr::now);
|
return _parent->data()->out()
|
||||||
|
? QString()
|
||||||
|
: tr::lng_action_set_wallpaper_button(tr::now);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClickHandlerPtr ThemeDocumentBox::createViewLink() {
|
ClickHandlerPtr ThemeDocumentBox::createViewLink() {
|
||||||
|
const auto out = _parent->data()->out();
|
||||||
const auto to = _parent->history()->peer;
|
const auto to = _parent->history()->peer;
|
||||||
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||||
//const auto my = context.other.value<ClickHandlerContext>();
|
const auto my = context.other.value<ClickHandlerContext>();
|
||||||
//if (const auto controller = my.sessionWindow.get()) {
|
if (const auto controller = my.sessionWindow.get()) {
|
||||||
//}
|
if (out) {
|
||||||
|
controller->toggleChooseChatTheme(to);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,8 @@ constexpr auto kMinAcceptableContrast = 1.14;// 4.5;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool operator==(const ChatThemeBackground &a, const ChatThemeBackground &b) {
|
bool operator==(const ChatThemeBackground &a, const ChatThemeBackground &b) {
|
||||||
return (a.prepared.cacheKey() == b.prepared.cacheKey())
|
return (a.key == b.key)
|
||||||
|
&& (a.prepared.cacheKey() == b.prepared.cacheKey())
|
||||||
&& (a.gradientForFill.cacheKey() == b.gradientForFill.cacheKey())
|
&& (a.gradientForFill.cacheKey() == b.gradientForFill.cacheKey())
|
||||||
&& (a.tile == b.tile)
|
&& (a.tile == b.tile)
|
||||||
&& (a.patternOpacity == b.patternOpacity);
|
&& (a.patternOpacity == b.patternOpacity);
|
||||||
|
@ -222,9 +223,14 @@ void ChatTheme::adjustPalette(const ChatThemeDescriptor &descriptor) {
|
||||||
if (overrideOutBg) {
|
if (overrideOutBg) {
|
||||||
set(p.msgOutBg(), descriptor.bubblesData.colors.front());
|
set(p.msgOutBg(), descriptor.bubblesData.colors.front());
|
||||||
}
|
}
|
||||||
const auto &background = descriptor.backgroundData.colors;
|
const auto &data = descriptor.backgroundData;
|
||||||
if (!background.empty()) {
|
const auto &background = data.colors;
|
||||||
const auto average = CountAverageColor(background);
|
const auto useImage = !data.isPattern
|
||||||
|
&& (!data.path.isEmpty() || !data.bytes.isEmpty());
|
||||||
|
if (useImage || !background.empty()) {
|
||||||
|
const auto average = useImage
|
||||||
|
? Ui::CountAverageColor(_mutableBackground.prepared)
|
||||||
|
: CountAverageColor(background);
|
||||||
adjust(p.msgServiceBg(), average);
|
adjust(p.msgServiceBg(), average);
|
||||||
adjust(p.msgServiceBgSelected(), average);
|
adjust(p.msgServiceBgSelected(), average);
|
||||||
adjust(p.historyScrollBg(), average);
|
adjust(p.historyScrollBg(), average);
|
||||||
|
@ -407,6 +413,7 @@ void ChatTheme::setBackground(ChatThemeBackground &&background) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatTheme::updateBackgroundImageFrom(ChatThemeBackground &&background) {
|
void ChatTheme::updateBackgroundImageFrom(ChatThemeBackground &&background) {
|
||||||
|
_mutableBackground.key = background.key;
|
||||||
_mutableBackground.prepared = std::move(background.prepared);
|
_mutableBackground.prepared = std::move(background.prepared);
|
||||||
_mutableBackground.preparedForTiled = std::move(
|
_mutableBackground.preparedForTiled = std::move(
|
||||||
background.preparedForTiled);
|
background.preparedForTiled);
|
||||||
|
@ -1028,6 +1035,16 @@ ChatThemeBackground PrepareBackgroundImage(
|
||||||
} else if (data.colors.empty()) {
|
} else if (data.colors.empty()) {
|
||||||
prepared.setDevicePixelRatio(style::DevicePixelRatio());
|
prepared.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
}
|
}
|
||||||
|
if (!prepared.isNull()
|
||||||
|
&& !data.isPattern
|
||||||
|
&& data.forDarkMode
|
||||||
|
&& data.darkModeDimming > 0) {
|
||||||
|
const auto ratio = int(prepared.devicePixelRatio());
|
||||||
|
auto p = QPainter(&prepared);
|
||||||
|
p.fillRect(
|
||||||
|
QRect(0, 0, prepared.width() / ratio, prepared.height() / ratio),
|
||||||
|
QColor(0, 0, 0, 255 * data.darkModeDimming / 100));
|
||||||
|
}
|
||||||
const auto imageMonoColor = (data.colors.size() < 2)
|
const auto imageMonoColor = (data.colors.size() < 2)
|
||||||
? CalculateImageMonoColor(prepared)
|
? CalculateImageMonoColor(prepared)
|
||||||
: std::nullopt;
|
: std::nullopt;
|
||||||
|
@ -1038,6 +1055,7 @@ ChatThemeBackground PrepareBackgroundImage(
|
||||||
? Ui::GenerateDitheredGradient(data.colors, data.gradientRotation)
|
? Ui::GenerateDitheredGradient(data.colors, data.gradientRotation)
|
||||||
: QImage();
|
: QImage();
|
||||||
return ChatThemeBackground{
|
return ChatThemeBackground{
|
||||||
|
.key = data.key,
|
||||||
.prepared = prepared,
|
.prepared = prepared,
|
||||||
.preparedForTiled = PrepareImageForTiled(prepared),
|
.preparedForTiled = PrepareImageForTiled(prepared),
|
||||||
.gradientForFill = std::move(gradientForFill),
|
.gradientForFill = std::move(gradientForFill),
|
||||||
|
|
|
@ -23,6 +23,7 @@ struct ChatPaintContext;
|
||||||
struct BubblePattern;
|
struct BubblePattern;
|
||||||
|
|
||||||
struct ChatThemeBackground {
|
struct ChatThemeBackground {
|
||||||
|
QString key;
|
||||||
QImage prepared;
|
QImage prepared;
|
||||||
QImage preparedForTiled;
|
QImage preparedForTiled;
|
||||||
QImage gradientForFill;
|
QImage gradientForFill;
|
||||||
|
@ -42,13 +43,16 @@ bool operator==(const ChatThemeBackground &a, const ChatThemeBackground &b);
|
||||||
bool operator!=(const ChatThemeBackground &a, const ChatThemeBackground &b);
|
bool operator!=(const ChatThemeBackground &a, const ChatThemeBackground &b);
|
||||||
|
|
||||||
struct ChatThemeBackgroundData {
|
struct ChatThemeBackgroundData {
|
||||||
|
QString key;
|
||||||
QString path;
|
QString path;
|
||||||
QByteArray bytes;
|
QByteArray bytes;
|
||||||
bool gzipSvg = false;
|
bool gzipSvg = false;
|
||||||
std::vector<QColor> colors;
|
std::vector<QColor> colors;
|
||||||
bool isPattern = false;
|
bool isPattern = false;
|
||||||
float64 patternOpacity = 0.;
|
float64 patternOpacity = 0.;
|
||||||
|
int darkModeDimming = 0;
|
||||||
bool isBlurred = false;
|
bool isBlurred = false;
|
||||||
|
bool forDarkMode = false;
|
||||||
bool generateGradient = false;
|
bool generateGradient = false;
|
||||||
int gradientRotation = 0;
|
int gradientRotation = 0;
|
||||||
};
|
};
|
||||||
|
@ -113,26 +117,10 @@ struct ChatThemeKey {
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return (id != 0);
|
return (id != 0);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
inline bool operator<(ChatThemeKey a, ChatThemeKey b) {
|
friend inline auto operator<=>(ChatThemeKey, ChatThemeKey) = default;
|
||||||
return (a.id < b.id) || ((a.id == b.id) && (a.dark < b.dark));
|
friend inline bool operator==(ChatThemeKey, ChatThemeKey) = default;
|
||||||
}
|
};
|
||||||
inline bool operator>(ChatThemeKey a, ChatThemeKey b) {
|
|
||||||
return (b < a);
|
|
||||||
}
|
|
||||||
inline bool operator<=(ChatThemeKey a, ChatThemeKey b) {
|
|
||||||
return !(b < a);
|
|
||||||
}
|
|
||||||
inline bool operator>=(ChatThemeKey a, ChatThemeKey b) {
|
|
||||||
return !(a < b);
|
|
||||||
}
|
|
||||||
inline bool operator==(ChatThemeKey a, ChatThemeKey b) {
|
|
||||||
return (a.id == b.id) && (a.dark == b.dark);
|
|
||||||
}
|
|
||||||
inline bool operator!=(ChatThemeKey a, ChatThemeKey b) {
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ChatThemeDescriptor {
|
struct ChatThemeDescriptor {
|
||||||
ChatThemeKey key;
|
ChatThemeKey key;
|
||||||
|
|
|
@ -383,7 +383,10 @@ void ChooseThemeController::initList() {
|
||||||
_chosen = chosen;
|
_chosen = chosen;
|
||||||
entry->chosen = true;
|
entry->chosen = true;
|
||||||
if (entry->theme || !entry->key) {
|
if (entry->theme || !entry->key) {
|
||||||
_controller->overridePeerTheme(_peer, entry->theme);
|
_controller->overridePeerTheme(
|
||||||
|
_peer,
|
||||||
|
entry->theme,
|
||||||
|
entry->emoji);
|
||||||
}
|
}
|
||||||
_inner->update();
|
_inner->update();
|
||||||
}
|
}
|
||||||
|
@ -534,6 +537,7 @@ void ChooseThemeController::fill(
|
||||||
});
|
});
|
||||||
_controller->cachedChatThemeValue(
|
_controller->cachedChatThemeValue(
|
||||||
theme,
|
theme,
|
||||||
|
Data::WallPaper(0),
|
||||||
type
|
type
|
||||||
) | rpl::filter([=](const std::shared_ptr<ChatTheme> &data) {
|
) | rpl::filter([=](const std::shared_ptr<ChatTheme> &data) {
|
||||||
return data && (data->key() == key);
|
return data && (data->key() == key);
|
||||||
|
@ -549,7 +553,10 @@ void ChooseThemeController::fill(
|
||||||
i->theme = std::move(data);
|
i->theme = std::move(data);
|
||||||
i->preview = GeneratePreview(theme);
|
i->preview = GeneratePreview(theme);
|
||||||
if (_chosen == i->emoji->text()) {
|
if (_chosen == i->emoji->text()) {
|
||||||
_controller->overridePeerTheme(_peer, i->theme);
|
_controller->overridePeerTheme(
|
||||||
|
_peer,
|
||||||
|
i->theme,
|
||||||
|
i->emoji);
|
||||||
}
|
}
|
||||||
_inner->update();
|
_inner->update();
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_cloud_themes.h"
|
#include "data/data_cloud_themes.h"
|
||||||
|
@ -45,6 +46,44 @@ namespace {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ResolvedPaper {
|
||||||
|
Data::WallPaper paper;
|
||||||
|
std::shared_ptr<Data::DocumentMedia> media;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<std::optional<ResolvedPaper>> PeerWallPaperValue(
|
||||||
|
not_null<PeerData*> peer) {
|
||||||
|
return peer->session().changes().peerFlagsValue(
|
||||||
|
peer,
|
||||||
|
Data::PeerUpdate::Flag::ChatWallPaper
|
||||||
|
) | rpl::map([=]() -> rpl::producer<std::optional<ResolvedPaper>> {
|
||||||
|
const auto paper = peer->wallPaper();
|
||||||
|
const auto single = [](std::optional<ResolvedPaper> value) {
|
||||||
|
return rpl::single(std::move(value));
|
||||||
|
};
|
||||||
|
if (!paper) {
|
||||||
|
return single({});
|
||||||
|
}
|
||||||
|
const auto document = paper->document();
|
||||||
|
auto value = ResolvedPaper{
|
||||||
|
*paper,
|
||||||
|
document ? document->createMediaView() : nullptr,
|
||||||
|
};
|
||||||
|
if (!value.media || value.media->loaded(true)) {
|
||||||
|
return single(std::move(value));
|
||||||
|
}
|
||||||
|
paper->loadDocument();
|
||||||
|
return single(
|
||||||
|
value
|
||||||
|
) | rpl::then(document->session().downloaderTaskFinished(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return value.media->loaded(true);
|
||||||
|
}) | rpl::take(1) | rpl::map_to(
|
||||||
|
std::optional<ResolvedPaper>(value)
|
||||||
|
));
|
||||||
|
}) | rpl::flatten_latest();
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto MaybeChatThemeDataValueFromPeer(
|
[[nodiscard]] auto MaybeChatThemeDataValueFromPeer(
|
||||||
not_null<PeerData*> peer)
|
not_null<PeerData*> peer)
|
||||||
-> rpl::producer<std::optional<Data::CloudTheme>> {
|
-> rpl::producer<std::optional<Data::CloudTheme>> {
|
||||||
|
@ -58,6 +97,7 @@ namespace {
|
||||||
|
|
||||||
struct ResolvedTheme {
|
struct ResolvedTheme {
|
||||||
std::optional<Data::CloudTheme> theme;
|
std::optional<Data::CloudTheme> theme;
|
||||||
|
std::optional<ResolvedPaper> paper;
|
||||||
bool dark = false;
|
bool dark = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,9 +106,13 @@ struct ResolvedTheme {
|
||||||
-> rpl::producer<ResolvedTheme> {
|
-> rpl::producer<ResolvedTheme> {
|
||||||
return rpl::combine(
|
return rpl::combine(
|
||||||
MaybeChatThemeDataValueFromPeer(peer),
|
MaybeChatThemeDataValueFromPeer(peer),
|
||||||
|
PeerWallPaperValue(peer),
|
||||||
Theme::IsThemeDarkValue() | rpl::distinct_until_changed()
|
Theme::IsThemeDarkValue() | rpl::distinct_until_changed()
|
||||||
) | rpl::map([](std::optional<Data::CloudTheme> theme, bool night) {
|
) | rpl::map([](
|
||||||
return ResolvedTheme{ std::move(theme), night };
|
std::optional<Data::CloudTheme> theme,
|
||||||
|
std::optional<ResolvedPaper> paper,
|
||||||
|
bool night) {
|
||||||
|
return ResolvedTheme{ std::move(theme), std::move(paper), night };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,13 +382,23 @@ auto ChatThemeValueFromPeer(
|
||||||
peer
|
peer
|
||||||
) | rpl::map([=](ResolvedTheme resolved)
|
) | rpl::map([=](ResolvedTheme resolved)
|
||||||
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>> {
|
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>> {
|
||||||
return resolved.theme
|
if (!resolved.theme && !resolved.paper) {
|
||||||
? controller->cachedChatThemeValue(
|
return rpl::single(controller->defaultChatTheme());
|
||||||
*resolved.theme,
|
}
|
||||||
(resolved.dark
|
const auto theme = resolved.theme.value_or(Data::CloudTheme());
|
||||||
? Data::CloudThemeType::Dark
|
const auto paper = resolved.paper
|
||||||
: Data::CloudThemeType::Light))
|
? resolved.paper->paper
|
||||||
: rpl::single(controller->defaultChatTheme());
|
: Data::WallPaper(0);
|
||||||
|
const auto type = resolved.dark
|
||||||
|
? Data::CloudThemeType::Dark
|
||||||
|
: Data::CloudThemeType::Light;
|
||||||
|
if (paper.document()
|
||||||
|
&& resolved.paper->media
|
||||||
|
&& !resolved.paper->media->loaded()
|
||||||
|
&& !controller->chatThemeAlreadyCached(theme, paper, type)) {
|
||||||
|
return rpl::single(controller->defaultChatTheme());
|
||||||
|
}
|
||||||
|
return controller->cachedChatThemeValue(theme, paper, type);
|
||||||
}) | rpl::flatten_latest(
|
}) | rpl::flatten_latest(
|
||||||
) | rpl::distinct_until_changed();
|
) | rpl::distinct_until_changed();
|
||||||
|
|
||||||
|
@ -354,7 +408,8 @@ auto ChatThemeValueFromPeer(
|
||||||
) | rpl::map([=](
|
) | rpl::map([=](
|
||||||
std::shared_ptr<Ui::ChatTheme> &&cloud,
|
std::shared_ptr<Ui::ChatTheme> &&cloud,
|
||||||
PeerThemeOverride &&overriden) {
|
PeerThemeOverride &&overriden) {
|
||||||
return (overriden.peer == peer.get())
|
return (overriden.peer == peer.get()
|
||||||
|
&& Ui::Emoji::Find(peer->themeEmoji()) != overriden.emoji)
|
||||||
? std::move(overriden.theme)
|
? std::move(overriden.theme)
|
||||||
: std::move(cloud);
|
: std::move(cloud);
|
||||||
});
|
});
|
||||||
|
|
|
@ -97,9 +97,15 @@ constexpr auto kMaxChatEntryHistorySize = 50;
|
||||||
constexpr auto kDayBaseFile = ":/gui/day-custom-base.tdesktop-theme"_cs;
|
constexpr auto kDayBaseFile = ":/gui/day-custom-base.tdesktop-theme"_cs;
|
||||||
constexpr auto kNightBaseFile = ":/gui/night-custom-base.tdesktop-theme"_cs;
|
constexpr auto kNightBaseFile = ":/gui/night-custom-base.tdesktop-theme"_cs;
|
||||||
|
|
||||||
|
[[nodiscard]] Fn<void(style::palette&)> PrepareDefaultPaletteCallback() {
|
||||||
|
return [=](style::palette &palette) {
|
||||||
|
palette.reset();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] Fn<void(style::palette&)> PreparePaletteCallback(
|
[[nodiscard]] Fn<void(style::palette&)> PreparePaletteCallback(
|
||||||
bool dark,
|
bool dark,
|
||||||
std::optional<QColor> accent) {
|
std::optional<QColor> accent) {
|
||||||
return [=](style::palette &palette) {
|
return [=](style::palette &palette) {
|
||||||
using namespace Theme;
|
using namespace Theme;
|
||||||
const auto &embedded = EmbeddedThemes();
|
const auto &embedded = EmbeddedThemes();
|
||||||
|
@ -727,10 +733,23 @@ void SessionNavigation::showPollResults(
|
||||||
showSection(std::make_shared<Info::Memento>(poll, contextId), params);
|
showSection(std::make_shared<Info::Memento>(poll, contextId), params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SessionController::CachedThemeKey {
|
||||||
|
Ui::ChatThemeKey theme;
|
||||||
|
QString paper;
|
||||||
|
|
||||||
|
friend inline auto operator<=>(
|
||||||
|
const CachedThemeKey&,
|
||||||
|
const CachedThemeKey&) = default;
|
||||||
|
[[nodiscard]] explicit operator bool() const {
|
||||||
|
return theme || !paper.isEmpty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct SessionController::CachedTheme {
|
struct SessionController::CachedTheme {
|
||||||
std::weak_ptr<Ui::ChatTheme> theme;
|
std::weak_ptr<Ui::ChatTheme> theme;
|
||||||
std::shared_ptr<Data::DocumentMedia> media;
|
std::shared_ptr<Data::DocumentMedia> media;
|
||||||
Data::WallPaper paper;
|
Data::WallPaper paper;
|
||||||
|
bool basedOnDark = false;
|
||||||
bool caching = false;
|
bool caching = false;
|
||||||
rpl::lifetime lifetime;
|
rpl::lifetime lifetime;
|
||||||
};
|
};
|
||||||
|
@ -2052,19 +2071,29 @@ void SessionController::openDocument(
|
||||||
|
|
||||||
auto SessionController::cachedChatThemeValue(
|
auto SessionController::cachedChatThemeValue(
|
||||||
const Data::CloudTheme &data,
|
const Data::CloudTheme &data,
|
||||||
|
const Data::WallPaper &paper,
|
||||||
Data::CloudThemeType type)
|
Data::CloudThemeType type)
|
||||||
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>> {
|
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>> {
|
||||||
const auto key = Ui::ChatThemeKey{
|
const auto themeKey = Ui::ChatThemeKey{
|
||||||
data.id,
|
data.id,
|
||||||
(type == Data::CloudThemeType::Dark),
|
(type == Data::CloudThemeType::Dark),
|
||||||
};
|
};
|
||||||
const auto settings = data.settings.find(type);
|
if (!themeKey && paper.isNull()) {
|
||||||
if (!key
|
|
||||||
|| (settings == end(data.settings))
|
|
||||||
|| !settings->second.paper
|
|
||||||
|| settings->second.paper->backgroundColors().empty()) {
|
|
||||||
return rpl::single(_defaultChatTheme);
|
return rpl::single(_defaultChatTheme);
|
||||||
}
|
}
|
||||||
|
const auto settings = data.settings.find(type);
|
||||||
|
if (!data.id && settings == end(data.settings)) {
|
||||||
|
return rpl::single(_defaultChatTheme);
|
||||||
|
}
|
||||||
|
if (paper.isNull()
|
||||||
|
&& (!settings->second.paper
|
||||||
|
|| settings->second.paper->backgroundColors().empty())) {
|
||||||
|
return rpl::single(_defaultChatTheme);
|
||||||
|
}
|
||||||
|
const auto key = CachedThemeKey{
|
||||||
|
themeKey,
|
||||||
|
!paper.isNull() ? paper.key() : settings->second.paper->key(),
|
||||||
|
};
|
||||||
const auto i = _customChatThemes.find(key);
|
const auto i = _customChatThemes.find(key);
|
||||||
if (i != end(_customChatThemes)) {
|
if (i != end(_customChatThemes)) {
|
||||||
if (auto strong = i->second.theme.lock()) {
|
if (auto strong = i->second.theme.lock()) {
|
||||||
|
@ -2073,7 +2102,7 @@ auto SessionController::cachedChatThemeValue(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == end(_customChatThemes) || !i->second.caching) {
|
if (i == end(_customChatThemes) || !i->second.caching) {
|
||||||
cacheChatTheme(data, type);
|
cacheChatTheme(key, data, paper, type);
|
||||||
}
|
}
|
||||||
const auto limit = Data::CloudThemes::TestingColors() ? (1 << 20) : 1;
|
const auto limit = Data::CloudThemes::TestingColors() ? (1 << 20) : 1;
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
|
@ -2081,7 +2110,8 @@ auto SessionController::cachedChatThemeValue(
|
||||||
_defaultChatTheme
|
_defaultChatTheme
|
||||||
) | rpl::then(_cachedThemesStream.events(
|
) | rpl::then(_cachedThemesStream.events(
|
||||||
) | rpl::filter([=](const std::shared_ptr<Ui::ChatTheme> &theme) {
|
) | rpl::filter([=](const std::shared_ptr<Ui::ChatTheme> &theme) {
|
||||||
if (theme->key() != key) {
|
if (theme->key() != key.theme
|
||||||
|
|| theme->background().key != key.paper) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pushLastUsedChatTheme(theme);
|
pushLastUsedChatTheme(theme);
|
||||||
|
@ -2089,6 +2119,24 @@ auto SessionController::cachedChatThemeValue(
|
||||||
}) | rpl::take(limit));
|
}) | rpl::take(limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SessionController::chatThemeAlreadyCached(
|
||||||
|
const Data::CloudTheme &data,
|
||||||
|
const Data::WallPaper &paper,
|
||||||
|
Data::CloudThemeType type) {
|
||||||
|
Expects(paper.document() != nullptr);
|
||||||
|
|
||||||
|
const auto key = CachedThemeKey{
|
||||||
|
Ui::ChatThemeKey{
|
||||||
|
data.id,
|
||||||
|
(type == Data::CloudThemeType::Dark),
|
||||||
|
},
|
||||||
|
paper.key(),
|
||||||
|
};
|
||||||
|
const auto i = _customChatThemes.find(key);
|
||||||
|
return (i != end(_customChatThemes))
|
||||||
|
&& (i->second.theme.lock() != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void SessionController::pushLastUsedChatTheme(
|
void SessionController::pushLastUsedChatTheme(
|
||||||
const std::shared_ptr<Ui::ChatTheme> &theme) {
|
const std::shared_ptr<Ui::ChatTheme> &theme) {
|
||||||
const auto i = ranges::find(_lastUsedCustomChatThemes, theme);
|
const auto i = ranges::find(_lastUsedCustomChatThemes, theme);
|
||||||
|
@ -2124,10 +2172,12 @@ void SessionController::clearCachedChatThemes() {
|
||||||
|
|
||||||
void SessionController::overridePeerTheme(
|
void SessionController::overridePeerTheme(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
std::shared_ptr<Ui::ChatTheme> theme) {
|
std::shared_ptr<Ui::ChatTheme> theme,
|
||||||
|
EmojiPtr emoji) {
|
||||||
_peerThemeOverride = PeerThemeOverride{
|
_peerThemeOverride = PeerThemeOverride{
|
||||||
peer,
|
peer,
|
||||||
theme ? theme : _defaultChatTheme,
|
theme ? theme : _defaultChatTheme,
|
||||||
|
emoji,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2154,25 +2204,28 @@ void SessionController::pushDefaultChatBackground() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionController::cacheChatTheme(
|
void SessionController::cacheChatTheme(
|
||||||
|
CachedThemeKey key,
|
||||||
const Data::CloudTheme &data,
|
const Data::CloudTheme &data,
|
||||||
|
const Data::WallPaper &paper,
|
||||||
Data::CloudThemeType type) {
|
Data::CloudThemeType type) {
|
||||||
Expects(data.id != 0);
|
Expects(data.id != 0 || !paper.isNull());
|
||||||
|
|
||||||
const auto dark = (type == Data::CloudThemeType::Dark);
|
const auto dark = (type == Data::CloudThemeType::Dark);
|
||||||
const auto key = Ui::ChatThemeKey{ data.id, dark };
|
|
||||||
const auto i = data.settings.find(type);
|
const auto i = data.settings.find(type);
|
||||||
Assert(i != end(data.settings));
|
Assert((!data.id || (i != end(data.settings)))
|
||||||
const auto &paper = i->second.paper;
|
&& (!paper.isNull()
|
||||||
Assert(paper.has_value());
|
|| (i->second.paper.has_value()
|
||||||
Assert(!paper->backgroundColors().empty());
|
&& !i->second.paper->backgroundColors().empty())));
|
||||||
const auto document = paper->document();
|
const auto &use = !paper.isNull() ? paper : *i->second.paper;
|
||||||
|
const auto document = use.document();
|
||||||
const auto media = document ? document->createMediaView() : nullptr;
|
const auto media = document ? document->createMediaView() : nullptr;
|
||||||
paper->loadDocument();
|
use.loadDocument();
|
||||||
auto &theme = [&]() -> CachedTheme& {
|
auto &theme = [&]() -> CachedTheme& {
|
||||||
const auto i = _customChatThemes.find(key);
|
const auto i = _customChatThemes.find(key);
|
||||||
if (i != end(_customChatThemes)) {
|
if (i != end(_customChatThemes)) {
|
||||||
i->second.media = media;
|
i->second.media = media;
|
||||||
i->second.paper = *paper;
|
i->second.paper = use;
|
||||||
|
i->second.basedOnDark = dark;
|
||||||
i->second.caching = true;
|
i->second.caching = true;
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
|
@ -2180,15 +2233,16 @@ void SessionController::cacheChatTheme(
|
||||||
key,
|
key,
|
||||||
CachedTheme{
|
CachedTheme{
|
||||||
.media = media,
|
.media = media,
|
||||||
.paper = *paper,
|
.paper = use,
|
||||||
|
.basedOnDark = dark,
|
||||||
.caching = true,
|
.caching = true,
|
||||||
}).first->second;
|
}).first->second;
|
||||||
}();
|
}();
|
||||||
auto descriptor = Ui::ChatThemeDescriptor{
|
auto descriptor = Ui::ChatThemeDescriptor{
|
||||||
.key = key,
|
.key = key.theme,
|
||||||
.preparePalette = PreparePaletteCallback(
|
.preparePalette = (data.id
|
||||||
dark,
|
? PreparePaletteCallback(dark, i->second.accentColor)
|
||||||
i->second.accentColor),
|
: PrepareDefaultPaletteCallback()),
|
||||||
.backgroundData = backgroundData(theme),
|
.backgroundData = backgroundData(theme),
|
||||||
.bubblesData = PrepareBubblesData(data, type),
|
.bubblesData = PrepareBubblesData(data, type),
|
||||||
.basedOnDark = dark,
|
.basedOnDark = dark,
|
||||||
|
@ -2215,7 +2269,10 @@ void SessionController::cacheChatThemeDone(
|
||||||
std::shared_ptr<Ui::ChatTheme> result) {
|
std::shared_ptr<Ui::ChatTheme> result) {
|
||||||
Expects(result != nullptr);
|
Expects(result != nullptr);
|
||||||
|
|
||||||
const auto key = result->key();
|
const auto key = CachedThemeKey{
|
||||||
|
result->key(),
|
||||||
|
result->background().key,
|
||||||
|
};
|
||||||
const auto i = _customChatThemes.find(key);
|
const auto i = _customChatThemes.find(key);
|
||||||
if (i == end(_customChatThemes)) {
|
if (i == end(_customChatThemes)) {
|
||||||
return;
|
return;
|
||||||
|
@ -2257,7 +2314,8 @@ void SessionController::updateCustomThemeBackground(CachedTheme &theme) {
|
||||||
=,
|
=,
|
||||||
result = Ui::PrepareBackgroundImage(data)
|
result = Ui::PrepareBackgroundImage(data)
|
||||||
]() mutable {
|
]() mutable {
|
||||||
const auto i = _customChatThemes.find(key);
|
const auto cacheKey = CachedThemeKey{ key, result.key };
|
||||||
|
const auto i = _customChatThemes.find(cacheKey);
|
||||||
if (i != end(_customChatThemes)) {
|
if (i != end(_customChatThemes)) {
|
||||||
if (const auto strong = i->second.theme.lock()) {
|
if (const auto strong = i->second.theme.lock()) {
|
||||||
strong->updateBackgroundImageFrom(std::move(result));
|
strong->updateBackgroundImageFrom(std::move(result));
|
||||||
|
@ -2280,14 +2338,20 @@ Ui::ChatThemeBackgroundData SessionController::backgroundData(
|
||||||
const auto patternOpacity = paper.patternOpacity();
|
const auto patternOpacity = paper.patternOpacity();
|
||||||
const auto isBlurred = paper.isBlurred();
|
const auto isBlurred = paper.isBlurred();
|
||||||
const auto gradientRotation = paper.gradientRotation();
|
const auto gradientRotation = paper.gradientRotation();
|
||||||
|
const auto darkModeDimming = isPattern
|
||||||
|
? 100
|
||||||
|
: std::clamp(paper.patternIntensity(), 0, 100);
|
||||||
return {
|
return {
|
||||||
|
.key = paper.key(),
|
||||||
.path = paperPath,
|
.path = paperPath,
|
||||||
.bytes = paperBytes,
|
.bytes = paperBytes,
|
||||||
.gzipSvg = gzipSvg,
|
.gzipSvg = gzipSvg,
|
||||||
.colors = colors,
|
.colors = colors,
|
||||||
.isPattern = isPattern,
|
.isPattern = isPattern,
|
||||||
.patternOpacity = patternOpacity,
|
.patternOpacity = patternOpacity,
|
||||||
|
.darkModeDimming = darkModeDimming,
|
||||||
.isBlurred = isBlurred,
|
.isBlurred = isBlurred,
|
||||||
|
.forDarkMode = theme.basedOnDark,
|
||||||
.generateGradient = generateGradient,
|
.generateGradient = generateGradient,
|
||||||
.gradientRotation = gradientRotation,
|
.gradientRotation = gradientRotation,
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,6 +71,7 @@ enum class CloudThemeType;
|
||||||
class Thread;
|
class Thread;
|
||||||
class Forum;
|
class Forum;
|
||||||
class ForumTopic;
|
class ForumTopic;
|
||||||
|
class WallPaper;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace HistoryView::Reactions {
|
namespace HistoryView::Reactions {
|
||||||
|
@ -108,6 +109,7 @@ enum class ResolveType {
|
||||||
struct PeerThemeOverride {
|
struct PeerThemeOverride {
|
||||||
PeerData *peer = nullptr;
|
PeerData *peer = nullptr;
|
||||||
std::shared_ptr<Ui::ChatTheme> theme;
|
std::shared_ptr<Ui::ChatTheme> theme;
|
||||||
|
EmojiPtr emoji = nullptr;
|
||||||
};
|
};
|
||||||
bool operator==(const PeerThemeOverride &a, const PeerThemeOverride &b);
|
bool operator==(const PeerThemeOverride &a, const PeerThemeOverride &b);
|
||||||
bool operator!=(const PeerThemeOverride &a, const PeerThemeOverride &b);
|
bool operator!=(const PeerThemeOverride &a, const PeerThemeOverride &b);
|
||||||
|
@ -538,8 +540,13 @@ public:
|
||||||
}
|
}
|
||||||
[[nodiscard]] auto cachedChatThemeValue(
|
[[nodiscard]] auto cachedChatThemeValue(
|
||||||
const Data::CloudTheme &data,
|
const Data::CloudTheme &data,
|
||||||
|
const Data::WallPaper &paper,
|
||||||
Data::CloudThemeType type)
|
Data::CloudThemeType type)
|
||||||
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>>;
|
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>>;
|
||||||
|
[[nodiscard]] bool chatThemeAlreadyCached(
|
||||||
|
const Data::CloudTheme &data,
|
||||||
|
const Data::WallPaper &paper,
|
||||||
|
Data::CloudThemeType type);
|
||||||
void setChatStyleTheme(const std::shared_ptr<Ui::ChatTheme> &theme);
|
void setChatStyleTheme(const std::shared_ptr<Ui::ChatTheme> &theme);
|
||||||
void clearCachedChatThemes();
|
void clearCachedChatThemes();
|
||||||
void pushLastUsedChatTheme(const std::shared_ptr<Ui::ChatTheme> &theme);
|
void pushLastUsedChatTheme(const std::shared_ptr<Ui::ChatTheme> &theme);
|
||||||
|
@ -547,7 +554,8 @@ public:
|
||||||
|
|
||||||
void overridePeerTheme(
|
void overridePeerTheme(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
std::shared_ptr<Ui::ChatTheme> theme);
|
std::shared_ptr<Ui::ChatTheme> theme,
|
||||||
|
EmojiPtr emoji);
|
||||||
void clearPeerThemeOverride(not_null<PeerData*> peer);
|
void clearPeerThemeOverride(not_null<PeerData*> peer);
|
||||||
[[nodiscard]] auto peerThemeOverrideValue() const
|
[[nodiscard]] auto peerThemeOverrideValue() const
|
||||||
-> rpl::producer<PeerThemeOverride> {
|
-> rpl::producer<PeerThemeOverride> {
|
||||||
|
@ -586,6 +594,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct CachedThemeKey;
|
||||||
struct CachedTheme;
|
struct CachedTheme;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
@ -616,7 +625,9 @@ private:
|
||||||
|
|
||||||
void pushDefaultChatBackground();
|
void pushDefaultChatBackground();
|
||||||
void cacheChatTheme(
|
void cacheChatTheme(
|
||||||
|
CachedThemeKey key,
|
||||||
const Data::CloudTheme &data,
|
const Data::CloudTheme &data,
|
||||||
|
const Data::WallPaper &paper,
|
||||||
Data::CloudThemeType type);
|
Data::CloudThemeType type);
|
||||||
void cacheChatThemeDone(std::shared_ptr<Ui::ChatTheme> result);
|
void cacheChatThemeDone(std::shared_ptr<Ui::ChatTheme> result);
|
||||||
void updateCustomThemeBackground(CachedTheme &theme);
|
void updateCustomThemeBackground(CachedTheme &theme);
|
||||||
|
@ -668,7 +679,7 @@ private:
|
||||||
rpl::event_stream<> _filtersMenuChanged;
|
rpl::event_stream<> _filtersMenuChanged;
|
||||||
|
|
||||||
std::shared_ptr<Ui::ChatTheme> _defaultChatTheme;
|
std::shared_ptr<Ui::ChatTheme> _defaultChatTheme;
|
||||||
base::flat_map<Ui::ChatThemeKey, CachedTheme> _customChatThemes;
|
base::flat_map<CachedThemeKey, CachedTheme> _customChatThemes;
|
||||||
rpl::event_stream<std::shared_ptr<Ui::ChatTheme>> _cachedThemesStream;
|
rpl::event_stream<std::shared_ptr<Ui::ChatTheme>> _cachedThemesStream;
|
||||||
const std::unique_ptr<Ui::ChatStyle> _chatStyle;
|
const std::unique_ptr<Ui::ChatStyle> _chatStyle;
|
||||||
std::weak_ptr<Ui::ChatTheme> _chatStyleTheme;
|
std::weak_ptr<Ui::ChatTheme> _chatStyleTheme;
|
||||||
|
|
Loading…
Add table
Reference in a new issue