Load fullres images of new wallpapers.

This commit is contained in:
John Preston 2019-01-16 16:25:29 +04:00
parent 04350af96f
commit 0f9c2a62fe
16 changed files with 290 additions and 168 deletions

View File

@ -18,6 +18,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_overview.h" #include "styles/style_overview.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
namespace {
constexpr auto kBackgroundsInRow = 3;
} // namespace
class BackgroundBox::Inner class BackgroundBox::Inner
: public Ui::RpWidget : public Ui::RpWidget
, private MTP::Sender , private MTP::Sender
@ -42,10 +48,9 @@ private:
Fn<void(int index)> _backgroundChosenCallback; Fn<void(int index)> _backgroundChosenCallback;
int _bgCount = 0;
int _rows = 0;
int _over = -1; int _over = -1;
int _overDown = -1; int _overDown = -1;
std::unique_ptr<Ui::RoundCheckbox> _check; // this is not a widget std::unique_ptr<Ui::RoundCheckbox> _check; // this is not a widget
}; };
@ -67,12 +72,9 @@ void BackgroundBox::prepare() {
} }
void BackgroundBox::backgroundChosen(int index) { void BackgroundBox::backgroundChosen(int index) {
if (index >= 0 && index < Auth().data().wallpapersCount()) { const auto &papers = Auth().data().wallpapers();
const auto &paper = Auth().data().wallpaper(index); if (index >= 0 && index < papers.size()) {
App::main()->setChatBackground(paper); App::main()->setChatBackground(papers[index]);
using Update = Window::Theme::BackgroundUpdate;
Window::Theme::Background()->notify(Update(Update::Type::Start, !paper.id));
} }
closeBox(); closeBox();
} }
@ -80,24 +82,21 @@ void BackgroundBox::backgroundChosen(int index) {
BackgroundBox::Inner::Inner(QWidget *parent) : RpWidget(parent) BackgroundBox::Inner::Inner(QWidget *parent) : RpWidget(parent)
, _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [=] { update(); })) { , _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [=] { update(); })) {
_check->setChecked(true, Ui::RoundCheckbox::SetStyle::Fast); _check->setChecked(true, Ui::RoundCheckbox::SetStyle::Fast);
if (!Auth().data().wallpapersCount()) { if (Auth().data().wallpapers().empty()) {
resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); resize(kBackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
request(MTPaccount_GetWallPapers(
MTP_int(0)
)).done([=](const MTPaccount_WallPapers &result) {
result.match([&](const MTPDaccount_wallPapers &data) {
Auth().data().setWallpapers(data.vwallpapers.v);
updateWallpapers();
}, [&](const MTPDaccount_wallPapersNotModified &) {
LOG(("API Error: account.wallPapersNotModified received."));
});
}).send();
} else { } else {
updateWallpapers(); updateWallpapers();
} }
request(MTPaccount_GetWallPapers(
MTP_int(Auth().data().wallpapersHash())
)).done([=](const MTPaccount_WallPapers &result) {
if (Auth().data().updateWallpapers(result)) {
updateWallpapers();
}
}).send();
subscribe(Auth().downloaderTaskFinished(), [this] { update(); }); subscribe(Auth().downloaderTaskFinished(), [=] { update(); });
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) { subscribe(Window::Theme::Background(), [=](const Window::Theme::BackgroundUpdate &update) {
if (update.paletteChanged()) { if (update.paletteChanged()) {
_check->invalidateCache(); _check->invalidateCache();
} }
@ -106,15 +105,16 @@ BackgroundBox::Inner::Inner(QWidget *parent) : RpWidget(parent)
} }
void BackgroundBox::Inner::updateWallpapers() { void BackgroundBox::Inner::updateWallpapers() {
_bgCount = Auth().data().wallpapersCount(); const auto &papers = Auth().data().wallpapers();
_rows = _bgCount / BackgroundsInRow; const auto count = papers.size();
if (_bgCount % BackgroundsInRow) ++_rows; const auto rows = (count / kBackgroundsInRow)
+ (count % kBackgroundsInRow ? 1 : 0);
resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, _rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); resize(kBackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
for (int i = 0; i < BackgroundsInRow * 3; ++i) {
if (i >= _bgCount) break;
Auth().data().wallpaper(i).thumb->load(Data::FileOrigin()); const auto preload = kBackgroundsInRow * 3;
for (const auto &paper : papers | ranges::view::take(preload)) {
paper.thumb->load(Data::FileOrigin());
} }
} }
@ -122,52 +122,68 @@ void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
QRect r(e->rect()); QRect r(e->rect());
Painter p(this); Painter p(this);
if (_rows) { const auto &papers = Auth().data().wallpapers();
for (int i = 0; i < _rows; ++i) { if (papers.empty()) {
if ((st::backgroundSize.height() + st::backgroundPadding) * (i + 1) <= r.top()) continue;
for (int j = 0; j < BackgroundsInRow; ++j) {
int index = i * BackgroundsInRow + j;
if (index >= _bgCount) break;
const auto &paper = Auth().data().wallpaper(index);
paper.thumb->load(Data::FileOrigin());
int x = st::backgroundPadding + j * (st::backgroundSize.width() + st::backgroundPadding);
int y = st::backgroundPadding + i * (st::backgroundSize.height() + st::backgroundPadding);
const auto &pix = paper.thumb->pix(
Data::FileOrigin(),
st::backgroundSize.width(),
st::backgroundSize.height());
p.drawPixmap(x, y, pix);
if (paper.id == Window::Theme::Background()->id()) {
auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
_check->paint(p, getms(), checkLeft, checkTop, width());
}
}
}
} else {
p.setFont(st::noContactsFont); p.setFont(st::noContactsFont);
p.setPen(st::noContactsColor); p.setPen(st::noContactsColor);
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
return;
}
auto row = 0;
auto column = 0;
for (const auto &paper : papers) {
const auto increment = gsl::finally([&] {
++column;
if (column == kBackgroundsInRow) {
column = 0;
++row;
}
});
if ((st::backgroundSize.height() + st::backgroundPadding) * (row + 1) <= r.top()) {
continue;
}
paper.thumb->load(Data::FileOrigin());
int x = st::backgroundPadding + column * (st::backgroundSize.width() + st::backgroundPadding);
int y = st::backgroundPadding + row * (st::backgroundSize.height() + st::backgroundPadding);
const auto &pix = paper.thumb->pix(
Data::FileOrigin(),
st::backgroundSize.width(),
st::backgroundSize.height());
p.drawPixmap(x, y, pix);
if (paper.id == Window::Theme::Background()->id()) {
auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
_check->paint(p, getms(), checkLeft, checkTop, width());
}
} }
} }
void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) { void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
int x = e->pos().x(), y = e->pos().y(); const auto newOver = [&] {
int row = int((y - st::backgroundPadding) / (st::backgroundSize.height() + st::backgroundPadding)); const auto x = e->pos().x();
if (y - row * (st::backgroundSize.height() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.height()) row = _rows + 1; const auto y = e->pos().y();
const auto width = st::backgroundSize.width();
int col = int((x - st::backgroundPadding) / (st::backgroundSize.width() + st::backgroundPadding)); const auto height = st::backgroundSize.height();
if (x - col * (st::backgroundSize.width() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.width()) row = _rows + 1; const auto skip = st::backgroundPadding;
const auto row = int((y - skip) / (height + skip));
int newOver = row * BackgroundsInRow + col; const auto column = int((x - skip) / (width + skip));
if (newOver >= _bgCount) newOver = -1; if (y - row * (height + skip) > skip + height) {
if (newOver != _over) { return -1;
} else if (x - column * (width + skip) > skip + width) {
return -1;
}
const auto result = row * kBackgroundsInRow + column;
return (result < Auth().data().wallpapers().size()) ? result : -1;
}();
if (_over != newOver) {
_over = newOver; _over = newOver;
setCursor((_over >= 0 || _overDown >= 0) ? style::cur_pointer : style::cur_default); setCursor((_over >= 0 || _overDown >= 0)
? style::cur_pointer
: style::cur_default);
} }
} }

View File

@ -81,7 +81,6 @@ enum {
WebPageUserId = 701000, WebPageUserId = 701000,
CacheBackgroundTimeout = 3000, // cache background scaled image after 3s CacheBackgroundTimeout = 3000, // cache background scaled image after 3s
BackgroundsInRow = 3,
UpdateDelayConstPart = 8 * 3600, // 8 hour min time between update check requests UpdateDelayConstPart = 8 * 3600, // 8 hour min time between update check requests
UpdateDelayRandPart = 8 * 3600, // 8 hour max - min time between update check requests UpdateDelayRandPart = 8 * 3600, // 8 hour max - min time between update check requests

View File

@ -478,10 +478,13 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
auto &d = attributes[i].c_documentAttributeImageSize(); auto &d = attributes[i].c_documentAttributeImageSize();
dimensions = QSize(d.vw.v, d.vh.v); dimensions = QSize(d.vw.v, d.vh.v);
} break; } break;
case mtpc_documentAttributeAnimated: if (type == FileDocument || type == StickerDocument || type == VideoDocument) { case mtpc_documentAttributeAnimated:
type = AnimatedDocument; if (type == FileDocument
_additional = nullptr; || type == StickerDocument
} break; || type == VideoDocument) {
type = AnimatedDocument;
_additional = nullptr;
} break;
case mtpc_documentAttributeSticker: { case mtpc_documentAttributeSticker: {
auto &d = attributes[i].c_documentAttributeSticker(); auto &d = attributes[i].c_documentAttributeSticker();
if (type == FileDocument) { if (type == FileDocument) {
@ -490,7 +493,8 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
} }
if (sticker()) { if (sticker()) {
sticker()->alt = qs(d.valt); sticker()->alt = qs(d.valt);
if (sticker()->set.type() != mtpc_inputStickerSetID || d.vstickerset.type() == mtpc_inputStickerSetID) { if (sticker()->set.type() != mtpc_inputStickerSetID
|| d.vstickerset.type() == mtpc_inputStickerSetID) {
sticker()->set = d.vstickerset; sticker()->set = d.vstickerset;
} }
} }
@ -498,7 +502,9 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
case mtpc_documentAttributeVideo: { case mtpc_documentAttributeVideo: {
auto &d = attributes[i].c_documentAttributeVideo(); auto &d = attributes[i].c_documentAttributeVideo();
if (type == FileDocument) { if (type == FileDocument) {
type = d.is_round_message() ? RoundVideoDocument : VideoDocument; type = d.is_round_message()
? RoundVideoDocument
: VideoDocument;
} }
_duration = d.vduration.v; _duration = d.vduration.v;
_supportsStreaming = d.is_supports_streaming(); _supportsStreaming = d.is_supports_streaming();
@ -568,6 +574,24 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
validateGoodThumbnail(); validateGoodThumbnail();
} }
bool DocumentData::checkWallPaperProperties() {
if (type != FileDocument
|| !thumb
|| !dimensions.width()
|| !dimensions.height()
|| dimensions.width() > Storage::kMaxWallPaperDimension
|| dimensions.height() > Storage::kMaxWallPaperDimension
|| size > Storage::kMaxWallPaperInMemory) {
return false;
}
type = WallPaperDocument;
return true;
}
bool DocumentData::isWallPaper() const {
return (type == WallPaperDocument);
}
Storage::Cache::Key DocumentData::goodThumbnailCacheKey() const { Storage::Cache::Key DocumentData::goodThumbnailCacheKey() const {
return Data::DocumentThumbCacheKey(_dc, id); return Data::DocumentThumbCacheKey(_dc, id);
} }
@ -610,7 +634,8 @@ void DocumentData::setGoodThumbnail(QImage &&image, QByteArray &&bytes) {
bool DocumentData::saveToCache() const { bool DocumentData::saveToCache() const {
return (type == StickerDocument && size < Storage::kMaxStickerInMemory) return (type == StickerDocument && size < Storage::kMaxStickerInMemory)
|| (isAnimation() && size < Storage::kMaxAnimationInMemory) || (isAnimation() && size < Storage::kMaxAnimationInMemory)
|| (isVoiceMessage() && size < Storage::kMaxVoiceInMemory); || (isVoiceMessage() && size < Storage::kMaxVoiceInMemory)
|| (type == WallPaperDocument);
} }
void DocumentData::unload() { void DocumentData::unload() {

View File

@ -122,7 +122,7 @@ public:
FilePathResolveType type = FilePathResolveCached, FilePathResolveType type = FilePathResolveCached,
bool forceSavingAs = false) const; bool forceSavingAs = false) const;
bool saveToCache() const; [[nodiscard]] bool saveToCache() const;
void performActionOnLoad(); void performActionOnLoad();
@ -158,6 +158,8 @@ public:
void setData(const QByteArray &data) { void setData(const QByteArray &data) {
_data = data; _data = data;
} }
bool checkWallPaperProperties();
bool isWallPaper() const;
bool hasGoodStickerThumb() const; bool hasGoodStickerThumb() const;

View File

@ -44,6 +44,7 @@ namespace Data {
namespace { namespace {
constexpr auto kMaxNotifyCheckDelay = 24 * 3600 * TimeMs(1000); constexpr auto kMaxNotifyCheckDelay = 24 * 3600 * TimeMs(1000);
constexpr auto kMaxWallpaperSize = 10 * 1024 * 1024;
using ViewElement = HistoryView::Element; using ViewElement = HistoryView::Element;
@ -3055,40 +3056,52 @@ PeerData *Session::proxyPromoted() const {
return _proxyPromoted; return _proxyPromoted;
} }
int Session::wallpapersCount() const { bool Session::updateWallpapers(const MTPaccount_WallPapers &data) {
return _wallpapers.size(); return data.match([&](const MTPDaccount_wallPapers &data) {
setWallpapers(data.vwallpapers.v, data.vhash.v);
return true;
}, [&](const MTPDaccount_wallPapersNotModified &) {
return false;
});
} }
const WallPaper &Session::wallpaper(int index) const { void Session::setWallpapers(const QVector<MTPWallPaper> &data, int32 hash) {
Expects(index >= 0 && index < _wallpapers.size()); _wallpapersHash = hash;
return _wallpapers[index];
}
void Session::setWallpapers(const QVector<MTPWallPaper> &data) {
_wallpapers.clear(); _wallpapers.clear();
_wallpapers.reserve(data.size() + 1); _wallpapers.reserve(data.size() + 1);
auto oldBackground = Images::Create(qsl(":/gui/art/bg_initial.jpg"), "JPG"); const auto oldBackground = Images::Create(
_wallpapers.push_back({ qsl(":/gui/art/bg_initial.jpg"),
Window::Theme::kInitialBackground, "JPG");
oldBackground, if (oldBackground) {
oldBackground _wallpapers.push_back({
}); Window::Theme::kInitialBackground,
oldBackground
});
}
for (const auto &paper : data) { for (const auto &paper : data) {
paper.match([&](const MTPDwallPaper &paper) { paper.match([&](const MTPDwallPaper &paper) {
const auto document = Auth().data().document(paper.vdocument); const auto document = this->document(paper.vdocument);
if (document->thumb) { if (document->checkWallPaperProperties()) {
_wallpapers.push_back({ _wallpapers.push_back({
paper.vid.v ? int32(paper.vid.v) : INT_MAX, paper.vid.v,
document->thumb,
document->thumb, document->thumb,
document,
}); });
} }
}); });
} }
} }
const std::vector<WallPaper> &Session::wallpapers() const {
return _wallpapers;
}
int32 Session::wallpapersHash() const {
return _wallpapersHash;
}
void Session::clearLocalStorage() { void Session::clearLocalStorage() {
clear(); clear();

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h" #include "history/history_location_manager.h"
#include "base/timer.h" #include "base/timer.h"
class Image;
class HistoryItem; class HistoryItem;
class BoxContent; class BoxContent;
struct WebPageCollage; struct WebPageCollage;
@ -51,9 +52,9 @@ enum class FeedUpdateFlag;
struct FeedUpdate; struct FeedUpdate;
struct WallPaper { struct WallPaper {
int32 id = 0; WallPaperId id = WallPaperId();
ImagePtr thumb; ImagePtr thumb;
ImagePtr full; DocumentData *document = nullptr;
}; };
class Session final { class Session final {
@ -530,9 +531,9 @@ public:
return _groups; return _groups;
} }
int wallpapersCount() const; bool updateWallpapers(const MTPaccount_WallPapers &data);
const WallPaper &wallpaper(int index) const; const std::vector<WallPaper> &wallpapers() const;
void setWallpapers(const QVector<MTPWallPaper> &data); int32 wallpapersHash() const;
void clearLocalStorage(); void clearLocalStorage();
@ -639,7 +640,6 @@ private:
void unmuteByFinished(); void unmuteByFinished();
void unmuteByFinishedDelayed(TimeMs delay); void unmuteByFinishedDelayed(TimeMs delay);
void updateNotifySettingsLocal(not_null<PeerData*> peer); void updateNotifySettingsLocal(not_null<PeerData*> peer);
void sendNotifySettingsUpdates();
template <typename Method> template <typename Method>
void enumerateItemViews( void enumerateItemViews(
@ -653,6 +653,8 @@ private:
void step_typings(TimeMs ms, bool timer); void step_typings(TimeMs ms, bool timer);
void setWallpapers(const QVector<MTPWallPaper> &data, int32 hash);
not_null<AuthSession*> _session; not_null<AuthSession*> _session;
Storage::DatabasePointer _cache; Storage::DatabasePointer _cache;
@ -797,6 +799,7 @@ private:
rpl::event_stream<SendActionAnimationUpdate> _sendActionAnimationUpdate; rpl::event_stream<SendActionAnimationUpdate> _sendActionAnimationUpdate;
std::vector<WallPaper> _wallpapers; std::vector<WallPaper> _wallpapers;
int32 _wallpapersHash = 0;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;

View File

@ -270,6 +270,7 @@ using DocumentId = uint64;
using WebPageId = uint64; using WebPageId = uint64;
using GameId = uint64; using GameId = uint64;
using PollId = uint64; using PollId = uint64;
using WallPaperId = uint64;
constexpr auto CancelledWebPageId = WebPageId(0xFFFFFFFFFFFFFFFFULL); constexpr auto CancelledWebPageId = WebPageId(0xFFFFFFFFFFFFFFFFULL);
using PreparedPhotoThumbs = QMap<char, QImage>; using PreparedPhotoThumbs = QMap<char, QImage>;
@ -309,6 +310,7 @@ enum DocumentType {
AnimatedDocument = 4, AnimatedDocument = 4,
VoiceDocument = 5, VoiceDocument = 5,
RoundVideoDocument = 6, RoundVideoDocument = 6,
WallPaperDocument = 7,
}; };
using MediaKey = QPair<uint64, uint64>; using MediaKey = QPair<uint64, uint64>;

View File

@ -133,6 +133,7 @@ WebPageType ParseWebPageType(const MTPDwebPage &page) {
if (type == qstr("photo")) return WebPageType::Photo; if (type == qstr("photo")) return WebPageType::Photo;
if (type == qstr("video")) return WebPageType::Video; if (type == qstr("video")) return WebPageType::Video;
if (type == qstr("profile")) return WebPageType::Profile; if (type == qstr("profile")) return WebPageType::Profile;
if (type == qstr("telegram_wallpaper")) return WebPageType::WallPaper;
return page.has_cached_page() return page.has_cached_page()
? WebPageType::ArticleWithIV ? WebPageType::ArticleWithIV
: WebPageType::Article; : WebPageType::Article;
@ -217,6 +218,10 @@ bool WebPageData::applyChanges(
pendingTill = newPendingTill; pendingTill = newPendingTill;
++version; ++version;
if (type == WebPageType::WallPaper) {
document->checkWallPaperProperties();
}
replaceDocumentGoodThumbnail(); replaceDocumentGoodThumbnail();
return true; return true;

View File

@ -14,6 +14,7 @@ enum class WebPageType {
Photo, Photo,
Video, Video,
Profile, Profile,
WallPaper,
Article, Article,
ArticleWithIV, ArticleWithIV,
}; };

View File

@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/widgets/dropdown_menu.h" #include "ui/widgets/dropdown_menu.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/image/image_source.h"
#include "ui/focus_persister.h" #include "ui/focus_persister.h"
#include "ui/resize_area.h" #include "ui/resize_area.h"
#include "ui/text_options.h" #include "ui/text_options.h"
@ -1414,8 +1415,16 @@ void MainWidget::updateScrollColors() {
void MainWidget::setChatBackground(const Data::WallPaper &background) { void MainWidget::setChatBackground(const Data::WallPaper &background) {
_background = std::make_unique<Data::WallPaper>(background); _background = std::make_unique<Data::WallPaper>(background);
_background->full->loadEvenCancelled(Data::FileOrigin()); if (_background->document) {
_background->document->save(Data::FileOrigin(), QString());
} else if (_background->thumb) {
_background->thumb->loadEvenCancelled(Data::FileOrigin());
}
checkChatBackground(); checkChatBackground();
const auto tile = (background.id == Window::Theme::kInitialBackground);
using Update = Window::Theme::BackgroundUpdate;
Window::Theme::Background()->notify(Update(Update::Type::Start, tile));
} }
bool MainWidget::chatBackgroundLoading() { bool MainWidget::chatBackgroundLoading() {
@ -1424,27 +1433,65 @@ bool MainWidget::chatBackgroundLoading() {
float64 MainWidget::chatBackgroundProgress() const { float64 MainWidget::chatBackgroundProgress() const {
if (_background) { if (_background) {
return _background->full->progress(); if (_background->document) {
return _background->document->progress();
} else if (_background->thumb) {
return _background->thumb->progress();
}
} }
return 1.; return 1.;
} }
void MainWidget::checkChatBackground() { void MainWidget::checkChatBackground() {
if (_background) { using namespace Window::Theme;
if (_background->full->loaded()) {
if (_background->full->isNull()) { if (!_background) {
Window::Theme::Background()->setImage(Window::Theme::kDefaultBackground); return;
} else if (false
|| _background->id == Window::Theme::kInitialBackground
|| _background->id == Window::Theme::kDefaultBackground) {
Window::Theme::Background()->setImage(_background->id);
} else {
Window::Theme::Background()->setImage(_background->id, _background->full->pix(Data::FileOrigin()).toImage());
}
_background = nullptr;
crl::on_main(this, [=] { update(); });
}
} }
const auto document = _background->document;
if (document && !document->loaded()) {
return;
} else if (!document && !_background->thumb->loaded()) {
return;
}
auto image = [&] {
if (!document) {
const auto &thumb = _background->thumb;
return thumb
? thumb->pixNoCache(Data::FileOrigin()).toImage()
: QImage();
}
auto bytes = document->data();
auto format = QByteArray();
const auto path = document->filepath();
if (bytes.isEmpty()) {
QFile f(document->filepath());
if (f.size() <= App::kImageSizeLimit
&& f.open(QIODevice::ReadOnly)) {
bytes = f.readAll();
}
}
return bytes.isEmpty()
? QImage()
: App::readImage(bytes, &format, false, nullptr);
}();
if (image.isNull()) {
Background()->setImage(kDefaultBackground);
} else if (false
|| _background->id == kInitialBackground
|| _background->id == kDefaultBackground) {
Background()->setImage(_background->id);
} else {
Background()->setImage(
_background->id,
std::move(image));
}
const auto tile = (_background->id == kInitialBackground);
Background()->setTile(tile);
_background = nullptr;
crl::on_main(this, [=] { update(); });
} }
ImagePtr MainWidget::newBackgroundThumb() { ImagePtr MainWidget::newBackgroundThumb() {
@ -1483,14 +1530,14 @@ void MainWidget::setInnerFocus() {
void MainWidget::scheduleViewIncrement(HistoryItem *item) { void MainWidget::scheduleViewIncrement(HistoryItem *item) {
PeerData *peer = item->history()->peer; PeerData *peer = item->history()->peer;
ViewsIncrement::iterator i = _viewsIncremented.find(peer); auto i = _viewsIncremented.find(peer);
if (i != _viewsIncremented.cend()) { if (i != _viewsIncremented.cend()) {
if (i.value().contains(item->id)) return; if (i.value().contains(item->id)) return;
} else { } else {
i = _viewsIncremented.insert(peer, ViewsIncrementMap()); i = _viewsIncremented.insert(peer, ViewsIncrementMap());
} }
i.value().insert(item->id, true); i.value().insert(item->id, true);
ViewsIncrement::iterator j = _viewsToIncrement.find(peer); auto j = _viewsToIncrement.find(peer);
if (j == _viewsToIncrement.cend()) { if (j == _viewsToIncrement.cend()) {
j = _viewsToIncrement.insert(peer, ViewsIncrementMap()); j = _viewsToIncrement.insert(peer, ViewsIncrementMap());
_viewsIncrementTimer.start(SendViewsTimeout); _viewsIncrementTimer.start(SendViewsTimeout);
@ -1499,7 +1546,7 @@ void MainWidget::scheduleViewIncrement(HistoryItem *item) {
} }
void MainWidget::onViewsIncrement() { void MainWidget::onViewsIncrement() {
for (ViewsIncrement::iterator i = _viewsToIncrement.begin(); i != _viewsToIncrement.cend();) { for (auto i = _viewsToIncrement.begin(); i != _viewsToIncrement.cend();) {
if (_viewsIncrementRequests.contains(i.key())) { if (_viewsIncrementRequests.contains(i.key())) {
++i; ++i;
continue; continue;
@ -1519,7 +1566,7 @@ void MainWidget::onViewsIncrement() {
void MainWidget::viewsIncrementDone(QVector<MTPint> ids, const MTPVector<MTPint> &result, mtpRequestId req) { void MainWidget::viewsIncrementDone(QVector<MTPint> ids, const MTPVector<MTPint> &result, mtpRequestId req) {
auto &v = result.v; auto &v = result.v;
if (ids.size() == v.size()) { if (ids.size() == v.size()) {
for (ViewsIncrementRequests::iterator i = _viewsIncrementRequests.begin(); i != _viewsIncrementRequests.cend(); ++i) { for (auto i = _viewsIncrementRequests.begin(); i != _viewsIncrementRequests.cend(); ++i) {
if (i.value() == req) { if (i.value() == req) {
PeerData *peer = i.key(); PeerData *peer = i.key();
ChannelId channel = peerToChannel(peer->id); ChannelId channel = peerToChannel(peer->id);
@ -1541,7 +1588,7 @@ void MainWidget::viewsIncrementDone(QVector<MTPint> ids, const MTPVector<MTPint>
bool MainWidget::viewsIncrementFail(const RPCError &error, mtpRequestId req) { bool MainWidget::viewsIncrementFail(const RPCError &error, mtpRequestId req) {
if (MTP::isDefaultHandledError(error)) return false; if (MTP::isDefaultHandledError(error)) return false;
for (ViewsIncrementRequests::iterator i = _viewsIncrementRequests.begin(); i != _viewsIncrementRequests.cend(); ++i) { for (auto i = _viewsIncrementRequests.begin(); i != _viewsIncrementRequests.cend(); ++i) {
if (i.value() == req) { if (i.value() == req) {
_viewsIncrementRequests.erase(i); _viewsIncrementRequests.erase(i);
break; break;
@ -2274,7 +2321,9 @@ void MainWidget::animationCallback() {
} }
void MainWidget::paintEvent(QPaintEvent *e) { void MainWidget::paintEvent(QPaintEvent *e) {
if (_background) checkChatBackground(); if (_background) {
checkChatBackground();
}
Painter p(this); Painter p(this);
auto progress = _a_show.current(getms(), 1.); auto progress = _a_show.current(getms(), 1.);
@ -3059,25 +3108,19 @@ void MainWidget::ptsWaiterStartTimerFor(ChannelData *channel, int32 ms) {
} }
void MainWidget::failDifferenceStartTimerFor(ChannelData *channel) { void MainWidget::failDifferenceStartTimerFor(ChannelData *channel) {
int32 ms = 0; auto &timeout = [&]() -> int32& {
ChannelFailDifferenceTimeout::iterator i; if (!channel) {
if (channel) { return _failDifferenceTimeout;
i = _channelFailDifferenceTimeout.find(channel);
if (i == _channelFailDifferenceTimeout.cend()) {
i = _channelFailDifferenceTimeout.insert(channel, 1);
} }
ms = i.value() * 1000; const auto i = _channelFailDifferenceTimeout.find(channel);
} else { return (i == _channelFailDifferenceTimeout.end())
ms = _failDifferenceTimeout * 1000; ? _channelFailDifferenceTimeout.insert(channel, 1).value()
} : i.value();
if (getDifferenceTimeChanged(channel, ms, _channelGetDifferenceTimeAfterFail, _getDifferenceTimeAfterFail)) { }();
if (getDifferenceTimeChanged(channel, timeout * 1000, _channelGetDifferenceTimeAfterFail, _getDifferenceTimeAfterFail)) {
onGetDifferenceTimeAfterFail(); onGetDifferenceTimeAfterFail();
} }
if (channel) { if (timeout < 64) timeout *= 2;
if (i.value() < 64) i.value() *= 2;
} else {
if (_failDifferenceTimeout < 64) _failDifferenceTimeout *= 2;
}
} }
bool MainWidget::ptsUpdateAndApply(int32 pts, int32 ptsCount, const MTPUpdates &updates) { bool MainWidget::ptsUpdateAndApply(int32 pts, int32 ptsCount, const MTPUpdates &updates) {

View File

@ -523,8 +523,7 @@ private:
bool _isIdle = false; bool _isIdle = false;
int32 _failDifferenceTimeout = 1; // growing timeout for getDifference calls, if it fails int32 _failDifferenceTimeout = 1; // growing timeout for getDifference calls, if it fails
typedef QMap<ChannelData*, int32> ChannelFailDifferenceTimeout; QMap<ChannelData*, int32> _channelFailDifferenceTimeout; // growing timeout for getChannelDifference calls, if it fails
ChannelFailDifferenceTimeout _channelFailDifferenceTimeout; // growing timeout for getChannelDifference calls, if it fails
SingleTimer _failDifferenceTimer; SingleTimer _failDifferenceTimer;
TimeMs _lastUpdateTime = 0; TimeMs _lastUpdateTime = 0;
@ -538,13 +537,10 @@ private:
PhotoData *_deletingPhoto = nullptr; PhotoData *_deletingPhoto = nullptr;
typedef QMap<MsgId, bool> ViewsIncrementMap; using ViewsIncrementMap = QMap<MsgId, bool>;
typedef QMap<PeerData*, ViewsIncrementMap> ViewsIncrement; QMap<PeerData*, ViewsIncrementMap> _viewsIncremented, _viewsToIncrement;
ViewsIncrement _viewsIncremented, _viewsToIncrement; QMap<PeerData*, mtpRequestId> _viewsIncrementRequests;
typedef QMap<PeerData*, mtpRequestId> ViewsIncrementRequests; QMap<mtpRequestId, PeerData*> _viewsIncrementByRequest;
ViewsIncrementRequests _viewsIncrementRequests;
typedef QMap<mtpRequestId, PeerData*> ViewsIncrementByRequest;
ViewsIncrementByRequest _viewsIncrementByRequest;
SingleTimer _viewsIncrementTimer; SingleTimer _viewsIncrementTimer;
std::unique_ptr<Data::WallPaper> _background; std::unique_ptr<Data::WallPaper> _background;

View File

@ -19,7 +19,9 @@ struct Key;
constexpr auto kMaxFileInMemory = 10 * 1024 * 1024; // 10 MB max file could be hold in memory constexpr auto kMaxFileInMemory = 10 * 1024 * 1024; // 10 MB max file could be hold in memory
constexpr auto kMaxVoiceInMemory = 2 * 1024 * 1024; // 2 MB audio is hold in memory and auto loaded constexpr auto kMaxVoiceInMemory = 2 * 1024 * 1024; // 2 MB audio is hold in memory and auto loaded
constexpr auto kMaxStickerInMemory = 2 * 1024 * 1024; // 2 MB stickers hold in memory, auto loaded and displayed inline constexpr auto kMaxStickerInMemory = 2 * 1024 * 1024; // 2 MB stickers hold in memory, auto loaded and displayed inline
constexpr auto kMaxWallPaperInMemory = kMaxFileInMemory;
constexpr auto kMaxAnimationInMemory = kMaxFileInMemory; // 10 MB gif and mp4 animations held in memory while playing constexpr auto kMaxAnimationInMemory = kMaxFileInMemory; // 10 MB gif and mp4 animations held in memory while playing
constexpr auto kMaxWallPaperDimension = 4096; // 4096x4096 is max area.
class Downloader final { class Downloader final {
public: public:

View File

@ -3956,7 +3956,7 @@ void readSavedGifs() {
} }
} }
void writeBackground(int32 id, const QImage &img) { void writeBackground(WallPaperId id, const QImage &img) {
if (!_working() || !_backgroundCanWrite) { if (!_working() || !_backgroundCanWrite) {
return; return;
} }
@ -3982,10 +3982,13 @@ void writeBackground(int32 id, const QImage &img) {
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
quint32 size = sizeof(qint32) quint32 size = sizeof(qint32)
+ sizeof(quint32) + sizeof(quint64)
+ (bmp.isEmpty() ? 0 : (sizeof(quint32) + bmp.size())); + Serialize::bytearraySize(bmp);
EncryptedDescriptor data(size); EncryptedDescriptor data(size);
data.stream << qint32(id) << bmp; data.stream
<< qint32(Window::Theme::internal::kLegacyBackgroundId)
<< quint64(id)
<< bmp;
FileWriteDescriptor file(backgroundKey); FileWriteDescriptor file(backgroundKey);
file.writeEncrypted(data); file.writeEncrypted(data);
@ -4007,8 +4010,15 @@ bool readBackground() {
} }
QByteArray bmpData; QByteArray bmpData;
qint32 id; qint32 legacyId;
bg.stream >> id >> bmpData; quint64 id;
bg.stream >> legacyId;
if (legacyId == Window::Theme::internal::kLegacyBackgroundId) {
bg.stream >> id;
} else {
id = Window::Theme::internal::FromLegacyBackgroundId(legacyId);
}
bg.stream >> bmpData;
auto oldEmptyImage = (bg.stream.status() != QDataStream::Ok); auto oldEmptyImage = (bg.stream.status() != QDataStream::Ok);
if (oldEmptyImage if (oldEmptyImage
|| id == Window::Theme::kInitialBackground || id == Window::Theme::kInitialBackground

View File

@ -136,7 +136,7 @@ void writeSavedGifs();
void readSavedGifs(); void readSavedGifs();
int32 countSavedGifsHash(); int32 countSavedGifsHash();
void writeBackground(int32 id, const QImage &img); void writeBackground(WallPaperId id, const QImage &img);
bool readBackground(); bool readBackground();
void writeTheme(const Window::Theme::Saved &saved); void writeTheme(const Window::Theme::Saved &saved);

View File

@ -389,7 +389,7 @@ void ChatBackground::start() {
} }
} }
void ChatBackground::setImage(int32 id, QImage &&image) { void ChatBackground::setImage(WallPaperId id, QImage &&image) {
auto needResetAdjustable = (id == kDefaultBackground) auto needResetAdjustable = (id == kDefaultBackground)
&& (_id != kDefaultBackground) && (_id != kDefaultBackground)
&& !nightMode() && !nightMode()
@ -528,7 +528,7 @@ void ChatBackground::adjustPaletteUsingBackground(const QImage &img) {
} }
} }
int32 ChatBackground::id() const { WallPaperId ChatBackground::id() const {
return _id; return _id;
} }

View File

@ -11,17 +11,22 @@ namespace Window {
namespace Theme { namespace Theme {
namespace internal { namespace internal {
constexpr int32 kUninitializedBackground = -999; constexpr auto FromLegacyBackgroundId(int32 legacyId) -> WallPaperId {
constexpr int32 kTestingThemeBackground = -666; return uint64(0xFFFFFFFF00000000ULL) | uint64(uint32(legacyId));
constexpr int32 kTestingDefaultBackground = -665; }
constexpr int32 kTestingEditorBackground = -664;
constexpr auto kUninitializedBackground = FromLegacyBackgroundId(-999);
constexpr auto kTestingThemeBackground = FromLegacyBackgroundId(-666);
constexpr auto kTestingDefaultBackground = FromLegacyBackgroundId(-665);
constexpr auto kTestingEditorBackground = FromLegacyBackgroundId(-664);
constexpr auto kLegacyBackgroundId = int32(-111);
} // namespace internal } // namespace internal
constexpr int32 kThemeBackground = -2; constexpr auto kThemeBackground = internal::FromLegacyBackgroundId(-2);
constexpr int32 kCustomBackground = -1; constexpr auto kCustomBackground = internal::FromLegacyBackgroundId(-1);
constexpr int32 kInitialBackground = 0; constexpr auto kInitialBackground = internal::FromLegacyBackgroundId(0);
constexpr int32 kDefaultBackground = 105; constexpr auto kDefaultBackground = internal::FromLegacyBackgroundId(105);
struct Cached { struct Cached {
QByteArray colors; QByteArray colors;
@ -98,7 +103,7 @@ public:
// This method is setting the default (themed) image if none was set yet. // This method is setting the default (themed) image if none was set yet.
void start(); void start();
void setImage(int32 id, QImage &&image = QImage()); void setImage(WallPaperId id, QImage &&image = QImage());
void setTile(bool tile); void setTile(bool tile);
void setTileDayValue(bool tile); void setTileDayValue(bool tile);
void setTileNightValue(bool tile); void setTileNightValue(bool tile);
@ -111,7 +116,7 @@ public:
void setTestingDefaultTheme(); void setTestingDefaultTheme();
void revert(); void revert();
int32 id() const; WallPaperId id() const;
const QPixmap &pixmap() const { const QPixmap &pixmap() const {
return _pixmap; return _pixmap;
} }
@ -152,7 +157,7 @@ private:
friend void KeepApplied(); friend void KeepApplied();
friend bool IsNonDefaultBackground(); friend bool IsNonDefaultBackground();
int32 _id = internal::kUninitializedBackground; WallPaperId _id = internal::kUninitializedBackground;
QPixmap _pixmap; QPixmap _pixmap;
QPixmap _pixmapForTiled; QPixmap _pixmapForTiled;
bool _nightMode = false; bool _nightMode = false;
@ -163,7 +168,7 @@ private:
QImage _themeImage; QImage _themeImage;
bool _themeTile = false; bool _themeTile = false;
int32 _idForRevert = internal::kUninitializedBackground; WallPaperId _idForRevert = internal::kUninitializedBackground;
QImage _imageForRevert; QImage _imageForRevert;
bool _tileForRevert = false; bool _tileForRevert = false;