Upload wallpapers to the cloud.
This commit is contained in:
parent
890aacaeee
commit
95565c39ed
|
@ -5142,7 +5142,6 @@ void ApiWrap::photoUploadReady(
|
|||
)).done(applier).afterRequest(history->sendRequestId).send();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ApiWrap::clearPeerPhoto(not_null<PhotoData*> photo) {
|
||||
|
|
|
@ -110,7 +110,7 @@ BackgroundBox::Inner::Inner(QWidget *parent) : RpWidget(parent)
|
|||
, _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [=] { update(); })) {
|
||||
_check->setChecked(true, Ui::RoundCheckbox::SetStyle::Fast);
|
||||
if (Auth().data().wallpapers().empty()) {
|
||||
resize(kBackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
resize(st::boxWideWidth, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
} else {
|
||||
updatePapers();
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ void BackgroundBox::Inner::updatePapers() {
|
|||
const auto rows = (count / kBackgroundsInRow)
|
||||
+ (count % kBackgroundsInRow ? 1 : 0);
|
||||
|
||||
resize(kBackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
resize(st::boxWideWidth, rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
|
||||
|
||||
const auto preload = kBackgroundsInRow * 3;
|
||||
for (const auto &paper : _papers | ranges::view::take(preload)) {
|
||||
|
|
|
@ -943,7 +943,7 @@ backgroundCheck: ServiceCheck {
|
|||
diameter: 18px;
|
||||
shift: 2px;
|
||||
thickness: 2px;
|
||||
tip: point(8px, 13px);
|
||||
tip: point(7px, 13px);
|
||||
small: 3px;
|
||||
large: 6px;
|
||||
stroke: 2px;
|
||||
|
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/data_wall_paper.h"
|
||||
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_session.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "core/application.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto FromLegacyBackgroundId(int32 legacyId) -> WallPaperId {
|
||||
return uint64(0xFFFFFFFF00000000ULL) | uint64(uint32(legacyId));
|
||||
}
|
||||
|
||||
constexpr auto kUninitializedBackground = FromLegacyBackgroundId(-999);
|
||||
constexpr auto kTestingThemeBackground = FromLegacyBackgroundId(-666);
|
||||
constexpr auto kTestingDefaultBackground = FromLegacyBackgroundId(-665);
|
||||
constexpr auto kTestingEditorBackground = FromLegacyBackgroundId(-664);
|
||||
constexpr auto kThemeBackground = FromLegacyBackgroundId(-2);
|
||||
constexpr auto kCustomBackground = FromLegacyBackgroundId(-1);
|
||||
constexpr auto kLegacy1DefaultBackground = FromLegacyBackgroundId(0);
|
||||
constexpr auto kDefaultBackground = 5947530738516623361;
|
||||
constexpr auto kIncorrectDefaultBackground = FromLegacyBackgroundId(105);
|
||||
|
||||
quint32 SerializeMaybeColor(std::optional<QColor> color) {
|
||||
return color
|
||||
? ((quint32(std::clamp(color->red(), 0, 255)) << 16)
|
||||
| (quint32(std::clamp(color->green(), 0, 255)) << 8)
|
||||
| quint32(std::clamp(color->blue(), 0, 255)))
|
||||
: quint32(-1);
|
||||
}
|
||||
|
||||
std::optional<QColor> MaybeColorFromSerialized(quint32 serialized) {
|
||||
return (serialized == quint32(-1))
|
||||
? std::nullopt
|
||||
: std::make_optional(QColor(
|
||||
int((serialized >> 16) & 0xFFU),
|
||||
int((serialized >> 8) & 0xFFU),
|
||||
int(serialized & 0xFFU)));
|
||||
}
|
||||
|
||||
std::optional<QColor> ColorFromString(const QString &string) {
|
||||
if (string.size() != 6) {
|
||||
return {};
|
||||
} else if (ranges::find_if(string, [](QChar ch) {
|
||||
return (ch < 'a' || ch > 'f')
|
||||
&& (ch < 'A' || ch > 'F')
|
||||
&& (ch < '0' || ch > '9');
|
||||
}) != string.end()) {
|
||||
return {};
|
||||
}
|
||||
const auto component = [](const QString &text, int index) {
|
||||
const auto decimal = [](QChar hex) {
|
||||
const auto code = hex.unicode();
|
||||
return (code >= '0' && code <= '9')
|
||||
? int(code - '0')
|
||||
: (code >= 'a' && code <= 'f')
|
||||
? int(code - 'a' + 0x0a)
|
||||
: int(code - 'A' + 0x0a);
|
||||
};
|
||||
index *= 2;
|
||||
return decimal(text[index]) * 0x10 + decimal(text[index + 1]);
|
||||
};
|
||||
return QColor(
|
||||
component(string, 0),
|
||||
component(string, 1),
|
||||
component(string, 2),
|
||||
255);
|
||||
}
|
||||
|
||||
QString StringFromColor(QColor color) {
|
||||
const auto component = [](int value) {
|
||||
const auto hex = [](int value) {
|
||||
value = std::clamp(value, 0, 15);
|
||||
return (value > 9)
|
||||
? ('a' + (value - 10))
|
||||
: ('0' + value);
|
||||
};
|
||||
return QString() + hex(value / 16) + hex(value % 16);
|
||||
};
|
||||
return component(color.red())
|
||||
+ component(color.green())
|
||||
+ component(color.blue());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WallPaper::WallPaper(WallPaperId id) : _id(id) {
|
||||
}
|
||||
|
||||
void WallPaper::setLocalImageAsThumbnail(std::shared_ptr<Image> image) {
|
||||
Expects(IsDefaultWallPaper(*this)
|
||||
|| IsLegacy1DefaultWallPaper(*this)
|
||||
|| IsCustomWallPaper(*this));
|
||||
Expects(_thumbnail == nullptr);
|
||||
|
||||
_thumbnail = std::move(image);
|
||||
}
|
||||
|
||||
WallPaperId WallPaper::id() const {
|
||||
return _id;
|
||||
}
|
||||
|
||||
std::optional<QColor> WallPaper::backgroundColor() const {
|
||||
return _backgroundColor;
|
||||
}
|
||||
|
||||
DocumentData *WallPaper::document() const {
|
||||
return _document;
|
||||
}
|
||||
|
||||
Image *WallPaper::thumbnail() const {
|
||||
return _thumbnail
|
||||
? _thumbnail.get()
|
||||
: _document
|
||||
? _document->thumbnail()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
bool WallPaper::isPattern() const {
|
||||
return _flags & MTPDwallPaper::Flag::f_pattern;
|
||||
}
|
||||
|
||||
bool WallPaper::isDefault() const {
|
||||
return _flags & MTPDwallPaper::Flag::f_default;
|
||||
}
|
||||
|
||||
bool WallPaper::isCreator() const {
|
||||
return _flags & MTPDwallPaper::Flag::f_creator;
|
||||
}
|
||||
|
||||
bool WallPaper::isDark() const {
|
||||
return _flags & MTPDwallPaper::Flag::f_dark;
|
||||
}
|
||||
|
||||
bool WallPaper::isLocal() const {
|
||||
return !document() && thumbnail();
|
||||
}
|
||||
|
||||
bool WallPaper::isBlurred() const {
|
||||
return _settings & MTPDwallPaperSettings::Flag::f_blur;
|
||||
}
|
||||
|
||||
int WallPaper::patternIntensity() const {
|
||||
return _intensity;
|
||||
}
|
||||
|
||||
bool WallPaper::hasShareUrl() const {
|
||||
return !_slug.isEmpty();
|
||||
}
|
||||
|
||||
QString WallPaper::shareUrl() const {
|
||||
if (!hasShareUrl()) {
|
||||
return QString();
|
||||
}
|
||||
const auto base = Core::App().createInternalLinkFull("bg/" + _slug);
|
||||
auto params = QStringList();
|
||||
if (isPattern()) {
|
||||
if (_backgroundColor) {
|
||||
params.push_back("bg_color=" + StringFromColor(*_backgroundColor));
|
||||
}
|
||||
if (_intensity) {
|
||||
params.push_back("intensity=" + QString::number(_intensity));
|
||||
}
|
||||
}
|
||||
auto mode = QStringList();
|
||||
if (_settings & MTPDwallPaperSettings::Flag::f_blur) {
|
||||
mode.push_back("blur");
|
||||
}
|
||||
if (_settings & MTPDwallPaperSettings::Flag::f_motion) {
|
||||
mode.push_back("motion");
|
||||
}
|
||||
if (!mode.isEmpty()) {
|
||||
params.push_back("mode=" + mode.join('+'));
|
||||
}
|
||||
return params.isEmpty()
|
||||
? base
|
||||
: base + '?' + params.join('&');
|
||||
}
|
||||
|
||||
void WallPaper::loadThumbnail() const {
|
||||
if (_thumbnail) {
|
||||
_thumbnail->load(fileOrigin());
|
||||
}
|
||||
if (_document) {
|
||||
_document->loadThumbnail(fileOrigin());
|
||||
}
|
||||
}
|
||||
|
||||
void WallPaper::loadDocument() const {
|
||||
if (_document) {
|
||||
_document->save(fileOrigin(), QString());
|
||||
}
|
||||
}
|
||||
|
||||
FileOrigin WallPaper::fileOrigin() const {
|
||||
return FileOriginWallpaper(_id, _accessHash);
|
||||
}
|
||||
|
||||
MTPWallPaperSettings WallPaper::mtpSettings() const {
|
||||
return MTP_wallPaperSettings(
|
||||
MTP_flags(_settings),
|
||||
(_backgroundColor
|
||||
? MTP_int(SerializeMaybeColor(_backgroundColor))
|
||||
: MTP_int(0)),
|
||||
MTP_int(_intensity));
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withUrlParams(
|
||||
const QMap<QString, QString> ¶ms) const {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
auto result = *this;
|
||||
result._settings = Flag(0);
|
||||
result._backgroundColor = ColorFromString(_slug);
|
||||
result._intensity = kDefaultIntensity;
|
||||
|
||||
if (auto mode = params.value("mode"); !mode.isEmpty()) {
|
||||
const auto list = mode.replace('+', ' ').split(' ');
|
||||
for (const auto &change : list) {
|
||||
if (change == qstr("blur")) {
|
||||
result._settings |= Flag::f_blur;
|
||||
} else if (change == qstr("motion")) {
|
||||
result._settings |= Flag::f_motion;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const auto color = ColorFromString(params.value("bg_color"))) {
|
||||
result._settings |= Flag::f_background_color;
|
||||
result._backgroundColor = color;
|
||||
}
|
||||
if (const auto string = params.value("intensity"); !string.isEmpty()) {
|
||||
auto ok = false;
|
||||
const auto intensity = string.toInt(&ok);
|
||||
if (ok && base::in_range(intensity, 0, 101)) {
|
||||
result._settings |= Flag::f_intensity;
|
||||
result._intensity = intensity;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withBlurred(bool blurred) const {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
auto result = *this;
|
||||
if (blurred) {
|
||||
result._settings |= Flag::f_blur;
|
||||
} else {
|
||||
result._settings &= ~Flag::f_blur;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withPatternIntensity(int intensity) const {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
auto result = *this;
|
||||
result._settings |= Flag::f_intensity;
|
||||
result._intensity = intensity;
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withBackgroundColor(QColor color) const {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
auto result = *this;
|
||||
result._settings |= Flag::f_background_color;
|
||||
result._backgroundColor = color;
|
||||
if (ColorFromString(_slug)) {
|
||||
result._slug = StringFromColor(color);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withParamsFrom(const WallPaper &other) const {
|
||||
auto result = *this;
|
||||
result._settings = other._settings;
|
||||
if (other._backgroundColor || !ColorFromString(_slug)) {
|
||||
result._backgroundColor = other._backgroundColor;
|
||||
if (ColorFromString(_slug)) {
|
||||
result._slug = StringFromColor(*result._backgroundColor);
|
||||
}
|
||||
}
|
||||
result._intensity = other._intensity;
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withoutImageData() const {
|
||||
auto result = *this;
|
||||
result._thumbnail = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::Create(const MTPWallPaper &data) {
|
||||
return data.match([](const MTPDwallPaper &data) {
|
||||
return Create(data);
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::Create(const MTPDwallPaper &data) {
|
||||
using Flag = MTPDwallPaper::Flag;
|
||||
|
||||
const auto document = Auth().data().processDocument(
|
||||
data.vdocument);
|
||||
if (!document->checkWallPaperProperties()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto result = WallPaper(data.vid.v);
|
||||
result._accessHash = data.vaccess_hash.v;
|
||||
result._flags = data.vflags.v;
|
||||
result._slug = qs(data.vslug);
|
||||
result._document = document;
|
||||
if (data.has_settings()) {
|
||||
const auto isPattern = ((result._flags & Flag::f_pattern) != 0);
|
||||
data.vsettings.match([&](const MTPDwallPaperSettings &data) {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
result._settings = data.vflags.v;
|
||||
if (isPattern && data.has_background_color()) {
|
||||
result._backgroundColor = MaybeColorFromSerialized(
|
||||
data.vbackground_color.v);
|
||||
} else {
|
||||
result._settings &= ~Flag::f_background_color;
|
||||
}
|
||||
if (isPattern && data.has_intensity()) {
|
||||
result._intensity = data.vintensity.v;
|
||||
} else {
|
||||
result._settings &= ~Flag::f_intensity;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray WallPaper::serialize() const {
|
||||
auto size = sizeof(quint64) // _id
|
||||
+ sizeof(quint64) // _accessHash
|
||||
+ sizeof(qint32) // _flags
|
||||
+ Serialize::stringSize(_slug)
|
||||
+ sizeof(qint32) // _settings
|
||||
+ sizeof(quint32) // _backgroundColor
|
||||
+ sizeof(qint32); // _intensity
|
||||
|
||||
auto result = QByteArray();
|
||||
result.reserve(size);
|
||||
{
|
||||
auto stream = QDataStream(&result, QIODevice::WriteOnly);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
stream
|
||||
<< quint64(_id)
|
||||
<< quint64(_accessHash)
|
||||
<< qint32(_flags)
|
||||
<< _slug
|
||||
<< qint32(_settings)
|
||||
<< SerializeMaybeColor(_backgroundColor)
|
||||
<< qint32(_intensity);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::FromSerialized(
|
||||
const QByteArray &serialized) {
|
||||
if (serialized.isEmpty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto id = quint64();
|
||||
auto accessHash = quint64();
|
||||
auto flags = qint32();
|
||||
auto slug = QString();
|
||||
auto settings = qint32();
|
||||
auto backgroundColor = quint32();
|
||||
auto intensity = qint32();
|
||||
|
||||
auto stream = QDataStream(serialized);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
stream
|
||||
>> id
|
||||
>> accessHash
|
||||
>> flags
|
||||
>> slug
|
||||
>> settings
|
||||
>> backgroundColor
|
||||
>> intensity;
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
return std::nullopt;
|
||||
} else if (intensity < 0 || intensity > 100) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto result = WallPaper(id);
|
||||
result._accessHash = accessHash;
|
||||
result._flags = MTPDwallPaper::Flags::from_raw(flags);
|
||||
result._slug = slug;
|
||||
result._settings = MTPDwallPaperSettings::Flags::from_raw(settings);
|
||||
result._backgroundColor = MaybeColorFromSerialized(backgroundColor);
|
||||
result._intensity = intensity;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::FromLegacySerialized(
|
||||
quint64 id,
|
||||
quint64 accessHash,
|
||||
quint32 flags,
|
||||
QString slug) {
|
||||
auto result = WallPaper(id);
|
||||
result._accessHash = accessHash;
|
||||
result._flags = MTPDwallPaper::Flags::from_raw(flags);
|
||||
result._slug = slug;
|
||||
result._backgroundColor = ColorFromString(slug);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::FromLegacyId(qint32 legacyId) {
|
||||
auto result = WallPaper(FromLegacyBackgroundId(legacyId));
|
||||
if (!IsCustomWallPaper(result)) {
|
||||
result._flags = MTPDwallPaper::Flag::f_default;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::FromColorSlug(const QString &slug) {
|
||||
if (const auto color = ColorFromString(slug)) {
|
||||
auto result = CustomWallPaper();
|
||||
result._slug = slug;
|
||||
result._backgroundColor = color;
|
||||
return result;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
WallPaper ThemeWallPaper() {
|
||||
return WallPaper(kThemeBackground);
|
||||
}
|
||||
|
||||
bool IsThemeWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kThemeBackground);
|
||||
}
|
||||
|
||||
WallPaper CustomWallPaper() {
|
||||
return WallPaper(kCustomBackground);
|
||||
}
|
||||
|
||||
bool IsCustomWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kCustomBackground);
|
||||
}
|
||||
|
||||
WallPaper Legacy1DefaultWallPaper() {
|
||||
return WallPaper(kLegacy1DefaultBackground);
|
||||
}
|
||||
|
||||
bool IsLegacy1DefaultWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kLegacy1DefaultBackground);
|
||||
}
|
||||
|
||||
WallPaper DefaultWallPaper() {
|
||||
return WallPaper(kDefaultBackground);
|
||||
}
|
||||
|
||||
bool IsDefaultWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kDefaultBackground)
|
||||
|| (paper.id() == kIncorrectDefaultBackground);
|
||||
}
|
||||
|
||||
QColor PatternColor(QColor background) {
|
||||
const auto hue = background.hueF();
|
||||
const auto saturation = background.saturationF();
|
||||
const auto value = background.valueF();
|
||||
return QColor::fromHsvF(
|
||||
hue,
|
||||
std::min(1.0, saturation + 0.05 + 0.1 * (1. - saturation)),
|
||||
(value > 0.5
|
||||
? std::max(0., value * 0.65)
|
||||
: std::max(0., std::min(1., 1. - value * 0.65))),
|
||||
0.4
|
||||
).toRgb();
|
||||
}
|
||||
|
||||
QImage PreparePatternImage(
|
||||
QImage image,
|
||||
QColor bg,
|
||||
QColor fg,
|
||||
int intensity) {
|
||||
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
image = std::move(image).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
// Similar to ColorizePattern.
|
||||
// But here we set bg to all 'alpha=0' pixels and fg to opaque ones.
|
||||
|
||||
const auto width = image.width();
|
||||
const auto height = image.height();
|
||||
const auto alpha = anim::interpolate(
|
||||
0,
|
||||
255,
|
||||
fg.alphaF() * std::clamp(intensity / 100., 0., 1.));
|
||||
if (!alpha) {
|
||||
image.fill(bg);
|
||||
return image;
|
||||
}
|
||||
fg.setAlpha(255);
|
||||
const auto patternBg = anim::shifted(bg);
|
||||
const auto patternFg = anim::shifted(fg);
|
||||
|
||||
const auto resultBytesPerPixel = (image.depth() >> 3);
|
||||
constexpr auto resultIntsPerPixel = 1;
|
||||
const auto resultIntsPerLine = (image.bytesPerLine() >> 2);
|
||||
const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel;
|
||||
auto resultInts = reinterpret_cast<uint32*>(image.bits());
|
||||
Assert(resultIntsAdded >= 0);
|
||||
Assert(image.depth() == static_cast<int>((resultIntsPerPixel * sizeof(uint32)) << 3));
|
||||
Assert(image.bytesPerLine() == (resultIntsPerLine << 2));
|
||||
|
||||
const auto maskBytesPerPixel = (image.depth() >> 3);
|
||||
const auto maskBytesPerLine = image.bytesPerLine();
|
||||
const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel;
|
||||
|
||||
// We want to read the last byte of four available.
|
||||
// This is the difference with style::colorizeImage.
|
||||
auto maskBytes = image.constBits() + (maskBytesPerPixel - 1);
|
||||
Assert(maskBytesAdded >= 0);
|
||||
Assert(image.depth() == (maskBytesPerPixel << 3));
|
||||
for (auto y = 0; y != height; ++y) {
|
||||
for (auto x = 0; x != width; ++x) {
|
||||
const auto maskOpacity = static_cast<anim::ShiftedMultiplier>(
|
||||
*maskBytes) + 1;
|
||||
const auto fgOpacity = (maskOpacity * alpha) >> 8;
|
||||
const auto bgOpacity = 256 - fgOpacity;
|
||||
*resultInts = anim::unshifted(
|
||||
patternBg * bgOpacity + patternFg * fgOpacity);
|
||||
maskBytes += maskBytesPerPixel;
|
||||
resultInts += resultIntsPerPixel;
|
||||
}
|
||||
maskBytes += maskBytesAdded;
|
||||
resultInts += resultIntsAdded;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
QImage PrepareBlurredBackground(QImage image) {
|
||||
constexpr auto kSize = 900;
|
||||
constexpr auto kRadius = 24;
|
||||
if (image.width() > kSize || image.height() > kSize) {
|
||||
image = image.scaled(
|
||||
kSize,
|
||||
kSize,
|
||||
Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
return Images::BlurLargeImage(image, kRadius);
|
||||
}
|
||||
|
||||
namespace details {
|
||||
|
||||
WallPaper UninitializedWallPaper() {
|
||||
return WallPaper(kUninitializedBackground);
|
||||
}
|
||||
|
||||
bool IsUninitializedWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kUninitializedBackground);
|
||||
}
|
||||
|
||||
WallPaper TestingThemeWallPaper() {
|
||||
return WallPaper(kTestingThemeBackground);
|
||||
}
|
||||
|
||||
bool IsTestingThemeWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kTestingThemeBackground);
|
||||
}
|
||||
|
||||
WallPaper TestingDefaultWallPaper() {
|
||||
return WallPaper(kTestingDefaultBackground);
|
||||
}
|
||||
|
||||
bool IsTestingDefaultWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kTestingDefaultBackground);
|
||||
}
|
||||
|
||||
WallPaper TestingEditorWallPaper() {
|
||||
return WallPaper(kTestingEditorBackground);
|
||||
}
|
||||
|
||||
bool IsTestingEditorWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kTestingEditorBackground);
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace Data
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class Image;
|
||||
|
||||
namespace Data {
|
||||
|
||||
struct FileOrigin;
|
||||
|
||||
class WallPaper {
|
||||
public:
|
||||
explicit WallPaper(WallPaperId id);
|
||||
|
||||
void setLocalImageAsThumbnail(std::shared_ptr<Image> image);
|
||||
|
||||
[[nodiscard]] WallPaperId id() const;
|
||||
[[nodiscard]] std::optional<QColor> backgroundColor() const;
|
||||
[[nodiscard]] DocumentData *document() const;
|
||||
[[nodiscard]] Image *thumbnail() const;
|
||||
[[nodiscard]] bool isPattern() const;
|
||||
[[nodiscard]] bool isDefault() const;
|
||||
[[nodiscard]] bool isCreator() const;
|
||||
[[nodiscard]] bool isDark() const;
|
||||
[[nodiscard]] bool isLocal() const;
|
||||
[[nodiscard]] bool isBlurred() const;
|
||||
[[nodiscard]] int patternIntensity() const;
|
||||
[[nodiscard]] bool hasShareUrl() const;
|
||||
[[nodiscard]] QString shareUrl() const;
|
||||
|
||||
void loadDocument() const;
|
||||
void loadThumbnail() const;
|
||||
[[nodiscard]] FileOrigin fileOrigin() const;
|
||||
[[nodiscard]] MTPWallPaperSettings mtpSettings() const;
|
||||
|
||||
[[nodiscard]] WallPaper withUrlParams(
|
||||
const QMap<QString, QString> ¶ms) const;
|
||||
[[nodiscard]] WallPaper withBlurred(bool blurred) const;
|
||||
[[nodiscard]] WallPaper withPatternIntensity(int intensity) const;
|
||||
[[nodiscard]] WallPaper withBackgroundColor(QColor color) const;
|
||||
[[nodiscard]] WallPaper withParamsFrom(const WallPaper &other) const;
|
||||
[[nodiscard]] WallPaper withoutImageData() const;
|
||||
|
||||
[[nodiscard]] static std::optional<WallPaper> Create(
|
||||
const MTPWallPaper &data);
|
||||
[[nodiscard]] static std::optional<WallPaper> Create(
|
||||
const MTPDwallPaper &data);
|
||||
|
||||
[[nodiscard]] QByteArray serialize() const;
|
||||
[[nodiscard]] static std::optional<WallPaper> FromSerialized(
|
||||
const QByteArray &serialized);
|
||||
[[nodiscard]] static std::optional<WallPaper> FromLegacySerialized(
|
||||
quint64 id,
|
||||
quint64 accessHash,
|
||||
quint32 flags,
|
||||
QString slug);
|
||||
[[nodiscard]] static std::optional<WallPaper> FromLegacyId(
|
||||
qint32 legacyId);
|
||||
[[nodiscard]] static std::optional<WallPaper> FromColorSlug(
|
||||
const QString &slug);
|
||||
|
||||
private:
|
||||
static constexpr auto kDefaultIntensity = 40;
|
||||
|
||||
WallPaperId _id = WallPaperId();
|
||||
uint64 _accessHash = 0;
|
||||
MTPDwallPaper::Flags _flags;
|
||||
QString _slug;
|
||||
|
||||
MTPDwallPaperSettings::Flags _settings;
|
||||
std::optional<QColor> _backgroundColor;
|
||||
int _intensity = kDefaultIntensity;
|
||||
|
||||
DocumentData *_document = nullptr;
|
||||
std::shared_ptr<Image> _thumbnail;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] WallPaper ThemeWallPaper();
|
||||
[[nodiscard]] bool IsThemeWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper CustomWallPaper();
|
||||
[[nodiscard]] bool IsCustomWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper Legacy1DefaultWallPaper();
|
||||
[[nodiscard]] bool IsLegacy1DefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper DefaultWallPaper();
|
||||
[[nodiscard]] bool IsDefaultWallPaper(const WallPaper &paper);
|
||||
|
||||
QColor PatternColor(QColor background);
|
||||
QImage PreparePatternImage(
|
||||
QImage image,
|
||||
QColor bg,
|
||||
QColor fg,
|
||||
int intensity);
|
||||
QImage PrepareBlurredBackground(QImage image);
|
||||
|
||||
namespace details {
|
||||
|
||||
[[nodiscard]] WallPaper UninitializedWallPaper();
|
||||
[[nodiscard]] bool IsUninitializedWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper TestingThemeWallPaper();
|
||||
[[nodiscard]] bool IsTestingThemeWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper TestingDefaultWallPaper();
|
||||
[[nodiscard]] bool IsTestingDefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper TestingEditorWallPaper();
|
||||
[[nodiscard]] bool IsTestingEditorWallPaper(const WallPaper &paper);
|
||||
|
||||
} // namespace details
|
||||
} // namespace Data
|
|
@ -75,7 +75,9 @@ struct Uploader::File {
|
|||
|
||||
Uploader::File::File(const SendMediaReady &media) : media(media) {
|
||||
partsCount = media.parts.size();
|
||||
if (type() == SendMediaType::File || type() == SendMediaType::Audio) {
|
||||
if (type() == SendMediaType::File
|
||||
|| type() == SendMediaType::WallPaper
|
||||
|| type() == SendMediaType::Audio) {
|
||||
setDocSize(media.file.isEmpty()
|
||||
? media.data.size()
|
||||
: media.filesize);
|
||||
|
@ -89,7 +91,9 @@ Uploader::File::File(const std::shared_ptr<FileLoadResult> &file)
|
|||
|| type() == SendMediaType::Secure)
|
||||
? file->fileparts.size()
|
||||
: file->thumbparts.size();
|
||||
if (type() == SendMediaType::File || type() == SendMediaType::Audio) {
|
||||
if (type() == SendMediaType::File
|
||||
|| type() == SendMediaType::WallPaper
|
||||
|| type() == SendMediaType::Audio) {
|
||||
setDocSize(file->filesize);
|
||||
} else {
|
||||
docSize = docPartSize = docPartsCount = 0;
|
||||
|
@ -149,6 +153,7 @@ void Uploader::uploadMedia(
|
|||
if (media.type == SendMediaType::Photo) {
|
||||
Auth().data().processPhoto(media.photo, media.photoThumbs);
|
||||
} else if (media.type == SendMediaType::File
|
||||
|| media.type == SendMediaType::WallPaper
|
||||
|| media.type == SendMediaType::Audio) {
|
||||
const auto document = media.photoThumbs.empty()
|
||||
? Auth().data().processDocument(media.document)
|
||||
|
@ -157,6 +162,9 @@ void Uploader::uploadMedia(
|
|||
base::duplicate(media.photoThumbs.front().second));
|
||||
if (!media.data.isEmpty()) {
|
||||
document->setData(media.data);
|
||||
if (media.type == SendMediaType::WallPaper) {
|
||||
document->checkWallPaperProperties();
|
||||
}
|
||||
if (document->saveToCache()
|
||||
&& media.data.size() <= Storage::kMaxFileInMemory) {
|
||||
Auth().data().cache().put(
|
||||
|
@ -184,6 +192,7 @@ void Uploader::upload(
|
|||
photo->uploadingData = std::make_unique<Data::UploadState>(
|
||||
file->partssize);
|
||||
} else if (file->type == SendMediaType::File
|
||||
|| file->type == SendMediaType::WallPaper
|
||||
|| file->type == SendMediaType::Audio) {
|
||||
const auto document = file->thumb.isNull()
|
||||
? Auth().data().processDocument(file->document)
|
||||
|
@ -197,6 +206,9 @@ void Uploader::upload(
|
|||
std::move(file->goodThumbnailBytes));
|
||||
if (!file->content.isEmpty()) {
|
||||
document->setData(file->content);
|
||||
if (file->type == SendMediaType::WallPaper) {
|
||||
document->checkWallPaperProperties();
|
||||
}
|
||||
if (document->saveToCache()
|
||||
&& file->content.size() <= Storage::kMaxFileInMemory) {
|
||||
Auth().data().cache().put(
|
||||
|
@ -220,6 +232,7 @@ void Uploader::currentFailed() {
|
|||
if (j->second.type() == SendMediaType::Photo) {
|
||||
_photoFailed.fire_copy(j->first);
|
||||
} else if (j->second.type() == SendMediaType::File
|
||||
|| j->second.type() == SendMediaType::WallPaper
|
||||
|| j->second.type() == SendMediaType::Audio) {
|
||||
const auto document = Auth().data().document(j->second.id());
|
||||
if (document->uploading()) {
|
||||
|
@ -318,6 +331,7 @@ void Uploader::sendNext() {
|
|||
MTP_bytes(md5));
|
||||
_photoReady.fire({ uploadingId, silent, file });
|
||||
} else if (uploadingData.type() == SendMediaType::File
|
||||
|| uploadingData.type() == SendMediaType::WallPaper
|
||||
|| uploadingData.type() == SendMediaType::Audio) {
|
||||
QByteArray docMd5(32, Qt::Uninitialized);
|
||||
hashMd5Hex(uploadingData.md5Hash.result(), docMd5.data());
|
||||
|
@ -389,6 +403,7 @@ void Uploader::sendNext() {
|
|||
* uploadingData.docPartSize;
|
||||
toSend = content.mid(offset, uploadingData.docPartSize);
|
||||
if ((uploadingData.type() == SendMediaType::File
|
||||
|| uploadingData.type() == SendMediaType::WallPaper
|
||||
|| uploadingData.type() == SendMediaType::Audio)
|
||||
&& uploadingData.docSentParts <= kUseBigFilesFrom) {
|
||||
uploadingData.md5Hash.feed(toSend.constData(), toSend.size());
|
||||
|
@ -530,6 +545,7 @@ void Uploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
|
|||
}
|
||||
_photoProgress.fire_copy(fullId);
|
||||
} else if (file.type() == SendMediaType::File
|
||||
|| file.type() == SendMediaType::WallPaper
|
||||
|| file.type() == SendMediaType::Audio) {
|
||||
const auto document = Auth().data().document(file.id());
|
||||
if (document->uploading()) {
|
||||
|
|
|
@ -234,6 +234,71 @@ SendMediaReady PreparePeerPhoto(PeerId peerId, QImage &&image) {
|
|||
0);
|
||||
}
|
||||
|
||||
SendMediaReady PrepareWallPaper(const QImage &image) {
|
||||
PreparedPhotoThumbs thumbnails;
|
||||
QVector<MTPPhotoSize> sizes;
|
||||
|
||||
QByteArray jpeg;
|
||||
QBuffer jpegBuffer(&jpeg);
|
||||
image.save(&jpegBuffer, "JPG", 87);
|
||||
|
||||
const auto scaled = [&](int size) {
|
||||
return image.scaled(
|
||||
size,
|
||||
size,
|
||||
Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
};
|
||||
const auto push = [&](const char *type, QImage &&image) {
|
||||
sizes.push_back(MTP_photoSize(
|
||||
MTP_string(type),
|
||||
MTP_fileLocationUnavailable(
|
||||
MTP_long(0),
|
||||
MTP_int(0),
|
||||
MTP_long(0)),
|
||||
MTP_int(image.width()),
|
||||
MTP_int(image.height()), MTP_int(0)));
|
||||
thumbnails.emplace(type[0], std::move(image));
|
||||
};
|
||||
push("s", scaled(320));
|
||||
|
||||
const auto filename = qsl("wallpaper.jpg");
|
||||
auto attributes = QVector<MTPDocumentAttribute>(
|
||||
1,
|
||||
MTP_documentAttributeFilename(MTP_string(filename)));
|
||||
attributes.push_back(MTP_documentAttributeImageSize(
|
||||
MTP_int(image.width()),
|
||||
MTP_int(image.height())));
|
||||
const auto id = rand_value<DocumentId>();
|
||||
const auto document = MTP_document(
|
||||
MTP_flags(0),
|
||||
MTP_long(id),
|
||||
MTP_long(0),
|
||||
MTP_bytes(QByteArray()),
|
||||
MTP_int(unixtime()),
|
||||
MTP_string("image/jpeg"),
|
||||
MTP_int(jpeg.size()),
|
||||
MTP_vector<MTPPhotoSize>(sizes),
|
||||
MTP_int(MTP::maindc()),
|
||||
MTP_vector<MTPDocumentAttribute>(attributes));
|
||||
|
||||
return SendMediaReady(
|
||||
SendMediaType::WallPaper,
|
||||
QString(), // filepath
|
||||
filename,
|
||||
jpeg.size(),
|
||||
jpeg,
|
||||
id,
|
||||
0,
|
||||
QString(),
|
||||
PeerId(),
|
||||
MTP_photoEmpty(MTP_long(0)),
|
||||
thumbnails,
|
||||
document,
|
||||
QByteArray(),
|
||||
0);
|
||||
}
|
||||
|
||||
TaskQueue::TaskQueue(TimeMs stopTimeoutMs) {
|
||||
if (stopTimeoutMs > 0) {
|
||||
_stopTimer = new QTimer(this);
|
||||
|
|
|
@ -20,6 +20,7 @@ enum class SendMediaType {
|
|||
Photo,
|
||||
Audio,
|
||||
File,
|
||||
WallPaper,
|
||||
Secure,
|
||||
};
|
||||
|
||||
|
@ -83,6 +84,7 @@ struct SendMediaReady {
|
|||
};
|
||||
|
||||
SendMediaReady PreparePeerPhoto(PeerId peerId, QImage &&image);
|
||||
SendMediaReady PrepareWallPaper(const QImage &image);
|
||||
|
||||
using TaskId = void*; // no interface, just id
|
||||
|
||||
|
|
|
@ -10,592 +10,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/themes/window_theme_preview.h"
|
||||
#include "mainwidget.h"
|
||||
#include "auth_session.h"
|
||||
#include "core/application.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/file_upload.h"
|
||||
#include "base/parse_helper.h"
|
||||
#include "base/zlib_help.h"
|
||||
#include "data/data_session.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "boxes/background_box.h"
|
||||
#include "core/application.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_history.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto FromLegacyBackgroundId(int32 legacyId) -> WallPaperId {
|
||||
return uint64(0xFFFFFFFF00000000ULL) | uint64(uint32(legacyId));
|
||||
}
|
||||
|
||||
constexpr auto kUninitializedBackground = FromLegacyBackgroundId(-999);
|
||||
constexpr auto kTestingThemeBackground = FromLegacyBackgroundId(-666);
|
||||
constexpr auto kTestingDefaultBackground = FromLegacyBackgroundId(-665);
|
||||
constexpr auto kTestingEditorBackground = FromLegacyBackgroundId(-664);
|
||||
constexpr auto kThemeBackground = FromLegacyBackgroundId(-2);
|
||||
constexpr auto kCustomBackground = FromLegacyBackgroundId(-1);
|
||||
constexpr auto kLegacy1DefaultBackground = FromLegacyBackgroundId(0);
|
||||
constexpr auto kDefaultBackground = 5947530738516623361;
|
||||
constexpr auto kIncorrectDefaultBackground = FromLegacyBackgroundId(105);
|
||||
|
||||
quint32 SerializeMaybeColor(std::optional<QColor> color) {
|
||||
return color
|
||||
? ((quint32(std::clamp(color->red(), 0, 255)) << 16)
|
||||
| (quint32(std::clamp(color->green(), 0, 255)) << 8)
|
||||
| quint32(std::clamp(color->blue(), 0, 255)))
|
||||
: quint32(-1);
|
||||
}
|
||||
|
||||
std::optional<QColor> MaybeColorFromSerialized(quint32 serialized) {
|
||||
return (serialized == quint32(-1))
|
||||
? std::nullopt
|
||||
: std::make_optional(QColor(
|
||||
int((serialized >> 16) & 0xFFU),
|
||||
int((serialized >> 8) & 0xFFU),
|
||||
int(serialized & 0xFFU)));
|
||||
}
|
||||
|
||||
std::optional<QColor> ColorFromString(const QString &string) {
|
||||
if (string.size() != 6) {
|
||||
return {};
|
||||
} else if (ranges::find_if(string, [](QChar ch) {
|
||||
return (ch < 'a' || ch > 'f')
|
||||
&& (ch < 'A' || ch > 'F')
|
||||
&& (ch < '0' || ch > '9');
|
||||
}) != string.end()) {
|
||||
return {};
|
||||
}
|
||||
const auto component = [](const QString &text, int index) {
|
||||
const auto decimal = [](QChar hex) {
|
||||
const auto code = hex.unicode();
|
||||
return (code >= '0' && code <= '9')
|
||||
? int(code - '0')
|
||||
: (code >= 'a' && code <= 'f')
|
||||
? int(code - 'a' + 0x0a)
|
||||
: int(code - 'A' + 0x0a);
|
||||
};
|
||||
index *= 2;
|
||||
return decimal(text[index]) * 0x10 + decimal(text[index + 1]);
|
||||
};
|
||||
return QColor(
|
||||
component(string, 0),
|
||||
component(string, 1),
|
||||
component(string, 2),
|
||||
255);
|
||||
}
|
||||
|
||||
QString StringFromColor(QColor color) {
|
||||
const auto component = [](int value) {
|
||||
const auto hex = [](int value) {
|
||||
value = std::clamp(value, 0, 15);
|
||||
return (value > 9)
|
||||
? ('a' + (value - 10))
|
||||
: ('0' + value);
|
||||
};
|
||||
return QString() + hex(value / 16) + hex(value % 16);
|
||||
};
|
||||
return component(color.red())
|
||||
+ component(color.green())
|
||||
+ component(color.blue());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WallPaper::WallPaper(WallPaperId id) : _id(id) {
|
||||
}
|
||||
|
||||
void WallPaper::setLocalImageAsThumbnail(std::shared_ptr<Image> image) {
|
||||
Expects(IsDefaultWallPaper(*this)
|
||||
|| IsLegacy1DefaultWallPaper(*this)
|
||||
|| IsCustomWallPaper(*this));
|
||||
Expects(_thumbnail == nullptr);
|
||||
|
||||
_thumbnail = std::move(image);
|
||||
}
|
||||
|
||||
WallPaperId WallPaper::id() const {
|
||||
return _id;
|
||||
}
|
||||
|
||||
std::optional<QColor> WallPaper::backgroundColor() const {
|
||||
return _backgroundColor;
|
||||
}
|
||||
|
||||
DocumentData *WallPaper::document() const {
|
||||
return _document;
|
||||
}
|
||||
|
||||
Image *WallPaper::thumbnail() const {
|
||||
return _thumbnail
|
||||
? _thumbnail.get()
|
||||
: _document
|
||||
? _document->thumbnail()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
bool WallPaper::isPattern() const {
|
||||
return _flags & MTPDwallPaper::Flag::f_pattern;
|
||||
}
|
||||
|
||||
bool WallPaper::isDefault() const {
|
||||
return _flags & MTPDwallPaper::Flag::f_default;
|
||||
}
|
||||
|
||||
bool WallPaper::isCreator() const {
|
||||
return _flags & MTPDwallPaper::Flag::f_creator;
|
||||
}
|
||||
|
||||
bool WallPaper::isDark() const {
|
||||
return _flags & MTPDwallPaper::Flag::f_dark;
|
||||
}
|
||||
|
||||
bool WallPaper::isLocal() const {
|
||||
return !document() && thumbnail();
|
||||
}
|
||||
|
||||
bool WallPaper::isBlurred() const {
|
||||
return _settings & MTPDwallPaperSettings::Flag::f_blur;
|
||||
}
|
||||
|
||||
int WallPaper::patternIntensity() const {
|
||||
return _intensity;
|
||||
}
|
||||
|
||||
bool WallPaper::hasShareUrl() const {
|
||||
return !_slug.isEmpty();
|
||||
}
|
||||
|
||||
QString WallPaper::shareUrl() const {
|
||||
if (!hasShareUrl()) {
|
||||
return QString();
|
||||
}
|
||||
const auto base = Core::App().createInternalLinkFull("bg/" + _slug);
|
||||
auto params = QStringList();
|
||||
if (isPattern()) {
|
||||
if (_backgroundColor) {
|
||||
params.push_back("bg_color=" + StringFromColor(*_backgroundColor));
|
||||
}
|
||||
if (_intensity) {
|
||||
params.push_back("intensity=" + QString::number(_intensity));
|
||||
}
|
||||
}
|
||||
auto mode = QStringList();
|
||||
if (_settings & MTPDwallPaperSettings::Flag::f_blur) {
|
||||
mode.push_back("blur");
|
||||
}
|
||||
if (_settings & MTPDwallPaperSettings::Flag::f_motion) {
|
||||
mode.push_back("motion");
|
||||
}
|
||||
if (!mode.isEmpty()) {
|
||||
params.push_back("mode=" + mode.join('+'));
|
||||
}
|
||||
return params.isEmpty()
|
||||
? base
|
||||
: base + '?' + params.join('&');
|
||||
}
|
||||
|
||||
void WallPaper::loadThumbnail() const {
|
||||
if (_thumbnail) {
|
||||
_thumbnail->load(fileOrigin());
|
||||
}
|
||||
if (_document) {
|
||||
_document->loadThumbnail(fileOrigin());
|
||||
}
|
||||
}
|
||||
|
||||
void WallPaper::loadDocument() const {
|
||||
if (_document) {
|
||||
_document->save(fileOrigin(), QString());
|
||||
}
|
||||
}
|
||||
|
||||
FileOrigin WallPaper::fileOrigin() const {
|
||||
return FileOriginWallpaper(_id, _accessHash);
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withUrlParams(
|
||||
const QMap<QString, QString> ¶ms) const {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
auto result = *this;
|
||||
result._settings = Flag(0);
|
||||
result._backgroundColor = ColorFromString(_slug);
|
||||
result._intensity = kDefaultIntensity;
|
||||
|
||||
if (auto mode = params.value("mode"); !mode.isEmpty()) {
|
||||
const auto list = mode.replace('+', ' ').split(' ');
|
||||
for (const auto &change : list) {
|
||||
if (change == qstr("blur")) {
|
||||
result._settings |= Flag::f_blur;
|
||||
} else if (change == qstr("motion")) {
|
||||
result._settings |= Flag::f_motion;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const auto color = ColorFromString(params.value("bg_color"))) {
|
||||
result._settings |= Flag::f_background_color;
|
||||
result._backgroundColor = color;
|
||||
}
|
||||
if (const auto string = params.value("intensity"); !string.isEmpty()) {
|
||||
auto ok = false;
|
||||
const auto intensity = string.toInt(&ok);
|
||||
if (ok && base::in_range(intensity, 0, 101)) {
|
||||
result._settings |= Flag::f_intensity;
|
||||
result._intensity = intensity;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withBlurred(bool blurred) const {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
auto result = *this;
|
||||
if (blurred) {
|
||||
result._settings |= Flag::f_blur;
|
||||
} else {
|
||||
result._settings &= ~Flag::f_blur;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withPatternIntensity(int intensity) const {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
auto result = *this;
|
||||
result._settings |= Flag::f_intensity;
|
||||
result._intensity = intensity;
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withBackgroundColor(QColor color) const {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
auto result = *this;
|
||||
result._settings |= Flag::f_background_color;
|
||||
result._backgroundColor = color;
|
||||
if (ColorFromString(_slug)) {
|
||||
result._slug = StringFromColor(color);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withParamsFrom(const WallPaper &other) const {
|
||||
auto result = *this;
|
||||
result._settings = other._settings;
|
||||
if (other._backgroundColor || !ColorFromString(_slug)) {
|
||||
result._backgroundColor = other._backgroundColor;
|
||||
if (ColorFromString(_slug)) {
|
||||
result._slug = StringFromColor(*result._backgroundColor);
|
||||
}
|
||||
}
|
||||
result._intensity = other._intensity;
|
||||
return result;
|
||||
}
|
||||
|
||||
WallPaper WallPaper::withoutImageData() const {
|
||||
auto result = *this;
|
||||
result._thumbnail = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::Create(const MTPWallPaper &data) {
|
||||
return data.match([](const MTPDwallPaper &data) {
|
||||
return Create(data);
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::Create(const MTPDwallPaper &data) {
|
||||
using Flag = MTPDwallPaper::Flag;
|
||||
|
||||
const auto document = Auth().data().processDocument(
|
||||
data.vdocument);
|
||||
if (!document->checkWallPaperProperties()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto result = WallPaper(data.vid.v);
|
||||
result._accessHash = data.vaccess_hash.v;
|
||||
result._flags = data.vflags.v;
|
||||
result._slug = qs(data.vslug);
|
||||
result._document = document;
|
||||
if (data.has_settings()) {
|
||||
const auto isPattern = ((result._flags & Flag::f_pattern) != 0);
|
||||
data.vsettings.match([&](const MTPDwallPaperSettings &data) {
|
||||
using Flag = MTPDwallPaperSettings::Flag;
|
||||
|
||||
result._settings = data.vflags.v;
|
||||
if (isPattern && data.has_background_color()) {
|
||||
result._backgroundColor = MaybeColorFromSerialized(
|
||||
data.vbackground_color.v);
|
||||
} else {
|
||||
result._settings &= ~Flag::f_background_color;
|
||||
}
|
||||
if (isPattern && data.has_intensity()) {
|
||||
result._intensity = data.vintensity.v;
|
||||
} else {
|
||||
result._settings &= ~Flag::f_intensity;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray WallPaper::serialize() const {
|
||||
auto size = sizeof(quint64) // _id
|
||||
+ sizeof(quint64) // _accessHash
|
||||
+ sizeof(qint32) // _flags
|
||||
+ Serialize::stringSize(_slug)
|
||||
+ sizeof(qint32) // _settings
|
||||
+ sizeof(quint32) // _backgroundColor
|
||||
+ sizeof(qint32); // _intensity
|
||||
|
||||
auto result = QByteArray();
|
||||
result.reserve(size);
|
||||
{
|
||||
auto stream = QDataStream(&result, QIODevice::WriteOnly);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
stream
|
||||
<< quint64(_id)
|
||||
<< quint64(_accessHash)
|
||||
<< qint32(_flags)
|
||||
<< _slug
|
||||
<< qint32(_settings)
|
||||
<< SerializeMaybeColor(_backgroundColor)
|
||||
<< qint32(_intensity);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::FromSerialized(
|
||||
const QByteArray &serialized) {
|
||||
if (serialized.isEmpty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto id = quint64();
|
||||
auto accessHash = quint64();
|
||||
auto flags = qint32();
|
||||
auto slug = QString();
|
||||
auto settings = qint32();
|
||||
auto backgroundColor = quint32();
|
||||
auto intensity = qint32();
|
||||
|
||||
auto stream = QDataStream(serialized);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
stream
|
||||
>> id
|
||||
>> accessHash
|
||||
>> flags
|
||||
>> slug
|
||||
>> settings
|
||||
>> backgroundColor
|
||||
>> intensity;
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
return std::nullopt;
|
||||
} else if (intensity < 0 || intensity > 100) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto result = WallPaper(id);
|
||||
result._accessHash = accessHash;
|
||||
result._flags = MTPDwallPaper::Flags::from_raw(flags);
|
||||
result._slug = slug;
|
||||
result._settings = MTPDwallPaperSettings::Flags::from_raw(settings);
|
||||
result._backgroundColor = MaybeColorFromSerialized(backgroundColor);
|
||||
result._intensity = intensity;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::FromLegacySerialized(
|
||||
quint64 id,
|
||||
quint64 accessHash,
|
||||
quint32 flags,
|
||||
QString slug) {
|
||||
auto result = WallPaper(id);
|
||||
result._accessHash = accessHash;
|
||||
result._flags = MTPDwallPaper::Flags::from_raw(flags);
|
||||
result._slug = slug;
|
||||
result._backgroundColor = ColorFromString(slug);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::FromLegacyId(qint32 legacyId) {
|
||||
auto result = WallPaper(FromLegacyBackgroundId(legacyId));
|
||||
if (!IsCustomWallPaper(result)) {
|
||||
result._flags = MTPDwallPaper::Flag::f_default;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WallPaper> WallPaper::FromColorSlug(const QString &slug) {
|
||||
if (const auto color = ColorFromString(slug)) {
|
||||
auto result = CustomWallPaper();
|
||||
result._slug = slug;
|
||||
result._backgroundColor = color;
|
||||
return result;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
WallPaper ThemeWallPaper() {
|
||||
return WallPaper(kThemeBackground);
|
||||
}
|
||||
|
||||
bool IsThemeWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kThemeBackground);
|
||||
}
|
||||
|
||||
WallPaper CustomWallPaper() {
|
||||
return WallPaper(kCustomBackground);
|
||||
}
|
||||
|
||||
bool IsCustomWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kCustomBackground);
|
||||
}
|
||||
|
||||
WallPaper Legacy1DefaultWallPaper() {
|
||||
return WallPaper(kLegacy1DefaultBackground);
|
||||
}
|
||||
|
||||
bool IsLegacy1DefaultWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kLegacy1DefaultBackground);
|
||||
}
|
||||
|
||||
WallPaper DefaultWallPaper() {
|
||||
return WallPaper(kDefaultBackground);
|
||||
}
|
||||
|
||||
bool IsDefaultWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kDefaultBackground)
|
||||
|| (paper.id() == kIncorrectDefaultBackground);
|
||||
}
|
||||
|
||||
QColor PatternColor(QColor background) {
|
||||
const auto hue = background.hueF();
|
||||
const auto saturation = background.saturationF();
|
||||
const auto value = background.valueF();
|
||||
return QColor::fromHsvF(
|
||||
hue,
|
||||
std::min(1.0, saturation + 0.05 + 0.1 * (1. - saturation)),
|
||||
(value > 0.5
|
||||
? std::max(0., value * 0.65)
|
||||
: std::max(0., std::min(1., 1. - value * 0.65))),
|
||||
0.4
|
||||
).toRgb();
|
||||
}
|
||||
|
||||
QImage PreparePatternImage(
|
||||
QImage image,
|
||||
QColor bg,
|
||||
QColor fg,
|
||||
int intensity) {
|
||||
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
image = std::move(image).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
// Similar to ColorizePattern.
|
||||
// But here we set bg to all 'alpha=0' pixels and fg to opaque ones.
|
||||
|
||||
const auto width = image.width();
|
||||
const auto height = image.height();
|
||||
const auto alpha = anim::interpolate(
|
||||
0,
|
||||
255,
|
||||
fg.alphaF() * std::clamp(intensity / 100., 0., 1.));
|
||||
if (!alpha) {
|
||||
image.fill(bg);
|
||||
return image;
|
||||
}
|
||||
fg.setAlpha(255);
|
||||
const auto patternBg = anim::shifted(bg);
|
||||
const auto patternFg = anim::shifted(fg);
|
||||
|
||||
const auto resultBytesPerPixel = (image.depth() >> 3);
|
||||
constexpr auto resultIntsPerPixel = 1;
|
||||
const auto resultIntsPerLine = (image.bytesPerLine() >> 2);
|
||||
const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel;
|
||||
auto resultInts = reinterpret_cast<uint32*>(image.bits());
|
||||
Assert(resultIntsAdded >= 0);
|
||||
Assert(image.depth() == static_cast<int>((resultIntsPerPixel * sizeof(uint32)) << 3));
|
||||
Assert(image.bytesPerLine() == (resultIntsPerLine << 2));
|
||||
|
||||
const auto maskBytesPerPixel = (image.depth() >> 3);
|
||||
const auto maskBytesPerLine = image.bytesPerLine();
|
||||
const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel;
|
||||
|
||||
// We want to read the last byte of four available.
|
||||
// This is the difference with style::colorizeImage.
|
||||
auto maskBytes = image.constBits() + (maskBytesPerPixel - 1);
|
||||
Assert(maskBytesAdded >= 0);
|
||||
Assert(image.depth() == (maskBytesPerPixel << 3));
|
||||
for (auto y = 0; y != height; ++y) {
|
||||
for (auto x = 0; x != width; ++x) {
|
||||
const auto maskOpacity = static_cast<anim::ShiftedMultiplier>(
|
||||
*maskBytes) + 1;
|
||||
const auto fgOpacity = (maskOpacity * alpha) >> 8;
|
||||
const auto bgOpacity = 256 - fgOpacity;
|
||||
*resultInts = anim::unshifted(
|
||||
patternBg * bgOpacity + patternFg * fgOpacity);
|
||||
maskBytes += maskBytesPerPixel;
|
||||
resultInts += resultIntsPerPixel;
|
||||
}
|
||||
maskBytes += maskBytesAdded;
|
||||
resultInts += resultIntsAdded;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
QImage PrepareBlurredBackground(QImage image) {
|
||||
constexpr auto kSize = 900;
|
||||
constexpr auto kRadius = 24;
|
||||
if (image.width() > kSize || image.height() > kSize) {
|
||||
image = image.scaled(
|
||||
kSize,
|
||||
kSize,
|
||||
Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
return Images::BlurLargeImage(image, kRadius);
|
||||
}
|
||||
|
||||
namespace details {
|
||||
|
||||
WallPaper UninitializedWallPaper() {
|
||||
return WallPaper(kUninitializedBackground);
|
||||
}
|
||||
|
||||
bool IsUninitializedWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kUninitializedBackground);
|
||||
}
|
||||
|
||||
WallPaper TestingThemeWallPaper() {
|
||||
return WallPaper(kTestingThemeBackground);
|
||||
}
|
||||
|
||||
bool IsTestingThemeWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kTestingThemeBackground);
|
||||
}
|
||||
|
||||
WallPaper TestingDefaultWallPaper() {
|
||||
return WallPaper(kTestingDefaultBackground);
|
||||
}
|
||||
|
||||
bool IsTestingDefaultWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kTestingDefaultBackground);
|
||||
}
|
||||
|
||||
WallPaper TestingEditorWallPaper() {
|
||||
return WallPaper(kTestingEditorBackground);
|
||||
}
|
||||
|
||||
bool IsTestingEditorWallPaper(const WallPaper &paper) {
|
||||
return (paper.id() == kTestingEditorBackground);
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace Data
|
||||
|
||||
namespace Window {
|
||||
namespace Theme {
|
||||
namespace {
|
||||
|
@ -954,9 +381,71 @@ void ChatBackground::start() {
|
|||
if (!Local::readBackground()) {
|
||||
set(Data::ThemeWallPaper());
|
||||
}
|
||||
refreshSession();
|
||||
subscribe(Core::App().authSessionChanged(), [=] {
|
||||
refreshSession();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ChatBackground::refreshSession() {
|
||||
const auto session = AuthSession::Exists() ? &Auth() : nullptr;
|
||||
if (_session != session) {
|
||||
_session = session;
|
||||
checkUploadWallPaper();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatBackground::checkUploadWallPaper() {
|
||||
if (!_session) {
|
||||
_wallPaperUploadLifetime = rpl::lifetime();
|
||||
_wallPaperUploadId = FullMsgId();
|
||||
_wallPaperRequestId = 0;
|
||||
return;
|
||||
}
|
||||
if (const auto id = base::take(_wallPaperUploadId)) {
|
||||
_session->uploader().cancel(id);
|
||||
}
|
||||
if (const auto id = base::take(_wallPaperRequestId)) {
|
||||
_session->api().request(id).cancel();
|
||||
}
|
||||
if (!Data::IsCustomWallPaper(_paper) || _original.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto ready = PrepareWallPaper(_original);
|
||||
const auto documentId = ready.id;
|
||||
_wallPaperUploadId = FullMsgId(0, clientMsgId());
|
||||
_session->uploader().uploadMedia(_wallPaperUploadId, ready);
|
||||
if (_wallPaperUploadLifetime) {
|
||||
return;
|
||||
}
|
||||
_wallPaperUploadLifetime = _session->uploader().documentReady(
|
||||
) | rpl::start_with_next([=](const Storage::UploadedDocument &data) {
|
||||
if (data.fullId != _wallPaperUploadId) {
|
||||
return;
|
||||
}
|
||||
_wallPaperUploadId = FullMsgId();
|
||||
_wallPaperRequestId = _session->api().request(
|
||||
MTPaccount_UploadWallPaper(
|
||||
data.file,
|
||||
MTP_string("image/jpeg"),
|
||||
_paper.mtpSettings()
|
||||
)
|
||||
).done([=](const MTPWallPaper &result) {
|
||||
result.match([&](const MTPDwallPaper &data) {
|
||||
_session->data().documentConvert(
|
||||
_session->data().document(documentId),
|
||||
data.vdocument);
|
||||
});
|
||||
if (const auto paper = Data::WallPaper::Create(result)) {
|
||||
_paper = *paper;
|
||||
writeNewBackgroundSettings();
|
||||
}
|
||||
}).send();
|
||||
});
|
||||
}
|
||||
|
||||
void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
image = ProcessBackgroundImage(std::move(image));
|
||||
|
||||
|
@ -1041,6 +530,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
|||
notify(BackgroundUpdate(BackgroundUpdate::Type::TestingTheme, tile()), true);
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::ApplyingTheme, tile()), true);
|
||||
}
|
||||
checkUploadWallPaper();
|
||||
}
|
||||
|
||||
void ChatBackground::setPreparedImage(QImage original, QImage prepared) {
|
||||
|
|
|
@ -7,109 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
class Image;
|
||||
#include "data/data_wall_paper.h"
|
||||
|
||||
namespace Data {
|
||||
|
||||
struct FileOrigin;
|
||||
|
||||
class WallPaper {
|
||||
public:
|
||||
explicit WallPaper(WallPaperId id);
|
||||
|
||||
void setLocalImageAsThumbnail(std::shared_ptr<Image> image);
|
||||
|
||||
[[nodiscard]] WallPaperId id() const;
|
||||
[[nodiscard]] std::optional<QColor> backgroundColor() const;
|
||||
[[nodiscard]] DocumentData *document() const;
|
||||
[[nodiscard]] Image *thumbnail() const;
|
||||
[[nodiscard]] bool isPattern() const;
|
||||
[[nodiscard]] bool isDefault() const;
|
||||
[[nodiscard]] bool isCreator() const;
|
||||
[[nodiscard]] bool isDark() const;
|
||||
[[nodiscard]] bool isLocal() const;
|
||||
[[nodiscard]] bool isBlurred() const;
|
||||
[[nodiscard]] int patternIntensity() const;
|
||||
[[nodiscard]] bool hasShareUrl() const;
|
||||
[[nodiscard]] QString shareUrl() const;
|
||||
|
||||
void loadDocument() const;
|
||||
void loadThumbnail() const;
|
||||
[[nodiscard]] FileOrigin fileOrigin() const;
|
||||
|
||||
[[nodiscard]] WallPaper withUrlParams(
|
||||
const QMap<QString, QString> ¶ms) const;
|
||||
[[nodiscard]] WallPaper withBlurred(bool blurred) const;
|
||||
[[nodiscard]] WallPaper withPatternIntensity(int intensity) const;
|
||||
[[nodiscard]] WallPaper withBackgroundColor(QColor color) const;
|
||||
[[nodiscard]] WallPaper withParamsFrom(const WallPaper &other) const;
|
||||
[[nodiscard]] WallPaper withoutImageData() const;
|
||||
|
||||
[[nodiscard]] static std::optional<WallPaper> Create(
|
||||
const MTPWallPaper &data);
|
||||
[[nodiscard]] static std::optional<WallPaper> Create(
|
||||
const MTPDwallPaper &data);
|
||||
|
||||
[[nodiscard]] QByteArray serialize() const;
|
||||
[[nodiscard]] static std::optional<WallPaper> FromSerialized(
|
||||
const QByteArray &serialized);
|
||||
[[nodiscard]] static std::optional<WallPaper> FromLegacySerialized(
|
||||
quint64 id,
|
||||
quint64 accessHash,
|
||||
quint32 flags,
|
||||
QString slug);
|
||||
[[nodiscard]] static std::optional<WallPaper> FromLegacyId(
|
||||
qint32 legacyId);
|
||||
[[nodiscard]] static std::optional<WallPaper> FromColorSlug(
|
||||
const QString &slug);
|
||||
|
||||
private:
|
||||
static constexpr auto kDefaultIntensity = 40;
|
||||
|
||||
WallPaperId _id = WallPaperId();
|
||||
uint64 _accessHash = 0;
|
||||
MTPDwallPaper::Flags _flags;
|
||||
QString _slug;
|
||||
|
||||
MTPDwallPaperSettings::Flags _settings;
|
||||
std::optional<QColor> _backgroundColor;
|
||||
int _intensity = kDefaultIntensity;
|
||||
|
||||
DocumentData *_document = nullptr;
|
||||
std::shared_ptr<Image> _thumbnail;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] WallPaper ThemeWallPaper();
|
||||
[[nodiscard]] bool IsThemeWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper CustomWallPaper();
|
||||
[[nodiscard]] bool IsCustomWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper Legacy1DefaultWallPaper();
|
||||
[[nodiscard]] bool IsLegacy1DefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper DefaultWallPaper();
|
||||
[[nodiscard]] bool IsDefaultWallPaper(const WallPaper &paper);
|
||||
|
||||
QColor PatternColor(QColor background);
|
||||
QImage PreparePatternImage(
|
||||
QImage image,
|
||||
QColor bg,
|
||||
QColor fg,
|
||||
int intensity);
|
||||
QImage PrepareBlurredBackground(QImage image);
|
||||
|
||||
namespace details {
|
||||
|
||||
[[nodiscard]] WallPaper UninitializedWallPaper();
|
||||
[[nodiscard]] bool IsUninitializedWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper TestingThemeWallPaper();
|
||||
[[nodiscard]] bool IsTestingThemeWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper TestingDefaultWallPaper();
|
||||
[[nodiscard]] bool IsTestingDefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] WallPaper TestingEditorWallPaper();
|
||||
[[nodiscard]] bool IsTestingEditorWallPaper(const WallPaper &paper);
|
||||
|
||||
} // namespace details
|
||||
} // namespace Data
|
||||
class AuthSession;
|
||||
|
||||
namespace Window {
|
||||
namespace Theme {
|
||||
|
@ -185,7 +85,9 @@ struct BackgroundUpdate {
|
|||
bool tiled;
|
||||
};
|
||||
|
||||
class ChatBackground : public base::Observable<BackgroundUpdate> {
|
||||
class ChatBackground
|
||||
: public base::Observable<BackgroundUpdate>
|
||||
, private base::Subscriber {
|
||||
public:
|
||||
ChatBackground();
|
||||
|
||||
|
@ -251,6 +153,8 @@ private:
|
|||
void keepApplied(const QString &path, bool write);
|
||||
[[nodiscard]] bool isNonDefaultThemeOrBackground();
|
||||
[[nodiscard]] bool isNonDefaultBackground();
|
||||
void refreshSession();
|
||||
void checkUploadWallPaper();
|
||||
|
||||
friend bool IsNightMode();
|
||||
friend void SetNightModeValue(bool nightMode);
|
||||
|
@ -259,6 +163,7 @@ private:
|
|||
friend void KeepApplied();
|
||||
friend bool IsNonDefaultBackground();
|
||||
|
||||
AuthSession *_session = nullptr;
|
||||
Data::WallPaper _paper = Data::details::UninitializedWallPaper();
|
||||
std::optional<QColor> _paperColor;
|
||||
QImage _original;
|
||||
|
@ -278,6 +183,9 @@ private:
|
|||
bool _tileForRevert = false;
|
||||
|
||||
std::vector<AdjustableColor> _adjustableColors;
|
||||
FullMsgId _wallPaperUploadId;
|
||||
mtpRequestId _wallPaperRequestId = 0;
|
||||
rpl::lifetime _wallPaperUploadLifetime;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -207,6 +207,8 @@
|
|||
<(src_loc)/data/data_user.h
|
||||
<(src_loc)/data/data_user_photos.cpp
|
||||
<(src_loc)/data/data_user_photos.h
|
||||
<(src_loc)/data/data_wall_paper.cpp
|
||||
<(src_loc)/data/data_wall_paper.h
|
||||
<(src_loc)/data/data_web_page.cpp
|
||||
<(src_loc)/data/data_web_page.h
|
||||
<(src_loc)/dialogs/dialogs_entry.cpp
|
||||
|
|
Loading…
Reference in New Issue