Change Stickers::Set from value to object type.

This commit is contained in:
John Preston 2020-05-28 14:00:51 +04:00
parent 897e432f40
commit 803593cd8d
33 changed files with 894 additions and 671 deletions

View File

@ -301,6 +301,8 @@ PRIVATE
chat_helpers/stickers_dice_pack.h
chat_helpers/stickers_list_widget.cpp
chat_helpers/stickers_list_widget.h
chat_helpers/stickers_set.cpp
chat_helpers/stickers_set.h
chat_helpers/tabbed_panel.cpp
chat_helpers/tabbed_panel.h
chat_helpers/tabbed_section.cpp

View File

@ -1890,16 +1890,17 @@ void ApiWrap::saveStickerSets(
auto it = sets.find(removedSetId);
if (it != sets.cend()) {
const auto set = it->second.get();
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) {
if (set->stickers.indexOf(i->first) >= 0) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
if (!(it->flags & MTPDstickerSet::Flag::f_archived)) {
MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
if (!(set->flags & MTPDstickerSet::Flag::f_archived)) {
const auto setId = set->mtpInput();
auto requestId = request(MTPmessages_UninstallStickerSet(setId)).done([this](const MTPBool &result, mtpRequestId requestId) {
stickerSetDisenabled(requestId);
@ -1909,60 +1910,69 @@ void ApiWrap::saveStickerSets(
_stickerSetDisenableRequests.insert(requestId);
int removeIndex = _session->data().stickerSetsOrder().indexOf(it->id);
int removeIndex = _session->data().stickerSetsOrder().indexOf(set->id);
if (removeIndex >= 0) _session->data().stickerSetsOrderRef().removeAt(removeIndex);
if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)
&& !(it->flags & MTPDstickerSet_ClientFlag::f_special)) {
if (!(set->flags & MTPDstickerSet_ClientFlag::f_featured)
&& !(set->flags & MTPDstickerSet_ClientFlag::f_special)) {
sets.erase(it);
} else {
if (it->flags & MTPDstickerSet::Flag::f_archived) {
if (set->flags & MTPDstickerSet::Flag::f_archived) {
writeArchived = true;
}
it->flags &= ~(MTPDstickerSet::Flag::f_installed_date | MTPDstickerSet::Flag::f_archived);
it->installDate = TimeId(0);
set->flags &= ~(MTPDstickerSet::Flag::f_installed_date | MTPDstickerSet::Flag::f_archived);
set->installDate = TimeId(0);
}
}
}
}
// Clear all installed flags, set only for sets from order.
for (auto &set : sets) {
if (!(set.flags & MTPDstickerSet::Flag::f_archived)) {
set.flags &= ~MTPDstickerSet::Flag::f_installed_date;
for (auto &[id, set] : sets) {
if (!(set->flags & MTPDstickerSet::Flag::f_archived)) {
set->flags &= ~MTPDstickerSet::Flag::f_installed_date;
}
}
auto &order = _session->data().stickerSetsOrderRef();
order.clear();
for_const (auto setId, _stickersOrder) {
for (const auto setId : std::as_const(_stickersOrder)) {
auto it = sets.find(setId);
if (it != sets.cend()) {
if ((it->flags & MTPDstickerSet::Flag::f_archived) && !localRemoved.contains(it->id)) {
MTPInputStickerSet mtpSetId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
const auto set = it->second.get();
if ((set->flags & MTPDstickerSet::Flag::f_archived) && !localRemoved.contains(set->id)) {
const auto mtpSetId = set->mtpInput();
auto requestId = request(MTPmessages_InstallStickerSet(mtpSetId, MTP_boolFalse())).done([this](const MTPmessages_StickerSetInstallResult &result, mtpRequestId requestId) {
const auto requestId = request(MTPmessages_InstallStickerSet(
mtpSetId,
MTP_boolFalse()
)).done([=](
const MTPmessages_StickerSetInstallResult &result,
mtpRequestId requestId) {
stickerSetDisenabled(requestId);
}).fail([this](const RPCError &error, mtpRequestId requestId) {
}).fail([=](
const RPCError &error,
mtpRequestId requestId) {
stickerSetDisenabled(requestId);
}).afterDelay(kSmallDelayMs).send();
_stickerSetDisenableRequests.insert(requestId);
it->flags &= ~MTPDstickerSet::Flag::f_archived;
set->flags &= ~MTPDstickerSet::Flag::f_archived;
writeArchived = true;
}
order.push_back(setId);
it->flags |= MTPDstickerSet::Flag::f_installed_date;
if (!it->installDate) {
it->installDate = base::unixtime::now();
set->flags |= MTPDstickerSet::Flag::f_installed_date;
if (!set->installDate) {
set->installDate = base::unixtime::now();
}
}
}
for (auto it = sets.begin(); it != sets.cend();) {
if ((it->flags & MTPDstickerSet_ClientFlag::f_featured)
|| (it->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->flags & MTPDstickerSet::Flag::f_archived)
|| (it->flags & MTPDstickerSet_ClientFlag::f_special)) {
const auto set = it->second.get();
if ((set->flags & MTPDstickerSet_ClientFlag::f_featured)
|| (set->flags & MTPDstickerSet::Flag::f_installed_date)
|| (set->flags & MTPDstickerSet::Flag::f_archived)
|| (set->flags & MTPDstickerSet_ClientFlag::f_special)) {
++it;
} else {
it = sets.erase(it);
@ -3341,7 +3351,7 @@ void ApiWrap::readFeaturedSets() {
for (auto setId : _featuredSetsRead) {
auto it = sets.find(setId);
if (it != sets.cend()) {
it->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
it->second->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
wrappedIds.append(MTP_long(setId));
if (count) {
--count;

View File

@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/flat_map.h"
#include "base/flat_set.h"
#include "mtproto/sender.h"
#include "chat_helpers/stickers.h"
#include "chat_helpers/stickers_set.h"
#include "data/data_messages.h"
class TaskQueue;

View File

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "mtproto/facade.h"
#include "app.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"

View File

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h"
#include "ui/image/image.h"
#include "ui/image/image_location_factory.h"
#include "ui/text/text_utilities.h"
#include "ui/emoji_config.h"
#include "lottie/lottie_multi_player.h"
@ -115,7 +116,7 @@ private:
int32 _setHash = 0;
MTPDstickerSet::Flags _setFlags = 0;
TimeId _setInstallDate = TimeId(0);
ImagePtr _setThumbnail;
ImageWithLocation _setThumbnail;
MTPInputStickerSet _input;
@ -299,25 +300,29 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
_setFlags = set.vflags().v;
_setInstallDate = set.vinstalled_date().value_or(0);
if (const auto thumb = set.vthumb()) {
_setThumbnail = Images::Create(set, *thumb);
_setThumbnail = Images::FromPhotoSize(
&_controller->session(),
set,
*thumb);
} else {
_setThumbnail = ImagePtr();
_setThumbnail = ImageWithLocation();
}
auto &sets = _controller->session().data().stickerSetsRef();
const auto it = sets.find(_setId);
if (it != sets.cend()) {
const auto set = it->second.get();
using ClientFlag = MTPDstickerSet_ClientFlag;
const auto clientFlags = it->flags
const auto clientFlags = set->flags
& (ClientFlag::f_featured
| ClientFlag::f_not_loaded
| ClientFlag::f_unread
| ClientFlag::f_special);
_setFlags |= clientFlags;
it->flags = _setFlags;
it->installDate = _setInstallDate;
it->stickers = _pack;
it->emoji = _emoji;
it->thumbnail = _setThumbnail;
set->flags = _setFlags;
set->installDate = _setInstallDate;
set->stickers = _pack;
set->emoji = _emoji;
set->setThumbnail(_setThumbnail);
}
});
});
@ -359,9 +364,10 @@ void StickerSetBox::Inner::installDone(
_setFlags |= MTPDstickerSet::Flag::f_installed_date;
auto it = sets.find(_setId);
if (it == sets.cend()) {
it = sets.insert(
it = sets.emplace(
_setId,
Stickers::Set(
std::make_unique<Stickers::Set>(
&_controller->session().data(),
_setId,
_setAccess,
_setTitle,
@ -369,14 +375,15 @@ void StickerSetBox::Inner::installDone(
_setCount,
_setHash,
_setFlags,
_setInstallDate,
_setThumbnail));
_setInstallDate)).first;
} else {
it->flags = _setFlags;
it->installDate = _setInstallDate;
it->second->flags = _setFlags;
it->second->installDate = _setInstallDate;
}
it->stickers = _pack;
it->emoji = _emoji;
const auto set = it->second.get();
set->setThumbnail(_setThumbnail);
set->stickers = _pack;
set->emoji = _emoji;
auto &order = _controller->session().data().stickerSetsOrderRef();
int insertAtIndex = 0, currentIndex = order.indexOf(_setId);
@ -387,14 +394,15 @@ void StickerSetBox::Inner::installDone(
order.insert(insertAtIndex, _setId);
}
auto custom = sets.find(Stickers::CustomSetId);
if (custom != sets.cend()) {
for_const (auto sticker, _pack) {
const auto customIt = sets.find(Stickers::CustomSetId);
if (customIt != sets.cend()) {
const auto custom = customIt->second.get();
for (const auto sticker : std::as_const(_pack)) {
int removeIndex = custom->stickers.indexOf(sticker);
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
}
if (custom->stickers.isEmpty()) {
sets.erase(custom);
sets.erase(customIt);
}
}
@ -669,10 +677,11 @@ bool StickerSetBox::Inner::notInstalled() const {
if (!_loaded) {
return false;
}
const auto it = _controller->session().data().stickerSets().constFind(_setId);
if ((it == _controller->session().data().stickerSets().cend())
|| !(it->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->flags & MTPDstickerSet::Flag::f_archived)) {
const auto &sets = _controller->session().data().stickerSets();
const auto it = sets.find(_setId);
if ((it == sets.cend())
|| !(it->second->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->second->flags & MTPDstickerSet::Flag::f_archived)) {
return !_pack.empty();
}
return false;

View File

@ -374,17 +374,24 @@ void StickersBox::loadMoreArchived() {
}
uint64 lastId = 0;
for (auto setIt = _session->data().archivedStickerSetsOrder().cend(), e = _session->data().archivedStickerSetsOrder().cbegin(); setIt != e;) {
const auto &order = _session->data().archivedStickerSetsOrder();
const auto &sets = _session->data().stickerSets();
for (auto setIt = order.cend(), e = order.cbegin(); setIt != e;) {
--setIt;
auto it = _session->data().stickerSets().constFind(*setIt);
if (it != _session->data().stickerSets().cend()) {
if (it->flags & MTPDstickerSet::Flag::f_archived) {
lastId = it->id;
auto it = sets.find(*setIt);
if (it != sets.cend()) {
if (it->second->flags & MTPDstickerSet::Flag::f_archived) {
lastId = it->second->id;
break;
}
}
}
_archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_flags(0), MTP_long(lastId), MTP_int(kArchivedLimitPerPage)), rpcDone(&StickersBox::getArchivedDone, lastId));
_archivedRequestId = MTP::send(
MTPmessages_GetArchivedStickers(
MTP_flags(0),
MTP_long(lastId),
MTP_int(kArchivedLimitPerPage)),
rpcDone(&StickersBox::getArchivedDone, lastId));
}
void StickersBox::paintEvent(QPaintEvent *e) {
@ -497,6 +504,7 @@ void StickersBox::installSet(uint64 setId) {
return;
}
const auto set = it->second.get();
if (_localRemoved.contains(setId)) {
_localRemoved.removeOne(setId);
if (_installed.widget()) _installed.widget()->setRemovedSets(_localRemoved);
@ -504,11 +512,11 @@ void StickersBox::installSet(uint64 setId) {
if (_archived.widget()) _archived.widget()->setRemovedSets(_localRemoved);
if (_attached.widget()) _attached.widget()->setRemovedSets(_localRemoved);
}
if (!(it->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->flags & MTPDstickerSet::Flag::f_archived)) {
if (!(set->flags & MTPDstickerSet::Flag::f_installed_date)
|| (set->flags & MTPDstickerSet::Flag::f_archived)) {
MTP::send(
MTPmessages_InstallStickerSet(
Stickers::inputSetId(*it),
set->mtpInput(),
MTP_boolFalse()),
rpcDone(&StickersBox::installDone),
rpcFail(&StickersBox::installFail, setId));
@ -551,12 +559,14 @@ void StickersBox::requestArchivedSets() {
preloadArchivedSets();
}
auto &sets = _session->data().stickerSets();
for_const (auto setId, _session->data().archivedStickerSetsOrder()) {
auto it = sets.constFind(setId);
const auto &sets = _session->data().stickerSets();
const auto &order = _session->data().archivedStickerSetsOrder();
for (const auto setId : order) {
auto it = sets.find(setId);
if (it != sets.cend()) {
if (it->stickers.isEmpty() && (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(setId, it->access);
const auto set = it->second.get();
if (set->stickers.isEmpty() && (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(setId, set->access);
}
}
}
@ -658,6 +668,10 @@ StickersBox::Inner::Row::Row(
StickersBox::Inner::Row::~Row() = default;
bool StickersBox::Inner::Row::isRecentSet() const {
return (id == Stickers::CloudRecentSetId);
}
StickersBox::Inner::Inner(
QWidget *parent,
not_null<Main::Session*> session,
@ -1298,7 +1312,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
if (!row.isRecentSet()) {
auto it = sets.find(row.id);
if (it != sets.cend()) {
return &*it;
return it->second.get();
}
}
return nullptr;
@ -1309,7 +1323,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
Ui::show(
Box<StickerSetBox>(
App::wnd()->sessionController(),
Stickers::inputSetId(*set)),
set->mtpInput()),
Ui::LayerOption::KeepOther);
}
};
@ -1470,8 +1484,9 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() {
auto text = _megagroupSetField->getLastText().trimmed();
if (text.isEmpty()) {
if (_megagroupSelectedSet) {
auto it = _session->data().stickerSets().constFind(_megagroupSelectedSet->id);
if (it != _session->data().stickerSets().cend() && !it->shortName.isEmpty()) {
const auto &sets = _session->data().stickerSets();
const auto it = sets.find(_megagroupSelectedSet->id);
if (it != sets.cend() && !it->second->shortName.isEmpty()) {
setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
}
}
@ -1481,7 +1496,9 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() {
)).done([=](const MTPmessages_StickerSet &result) {
_megagroupSetRequestId = 0;
auto set = Stickers::FeedSetFull(result);
setMegagroupSelectedSet(MTP_inputStickerSetID(MTP_long(set->id), MTP_long(set->access)));
setMegagroupSelectedSet(MTP_inputStickerSetID(
MTP_long(set->id),
MTP_long(set->access)));
}).fail([=](const RPCError &error) {
_megagroupSetRequestId = 0;
setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
@ -1503,31 +1520,35 @@ void StickersBox::Inner::rebuildMegagroupSet() {
_megagroupSelectedShadow.destroy();
return;
}
auto &set = _megagroupSetInput.c_inputStickerSetID();
auto setId = set.vid().v;
auto &inputId = _megagroupSetInput.c_inputStickerSetID();
auto setId = inputId.vid().v;
auto &sets = _session->data().stickerSets();
auto it = sets.find(setId);
if (it == sets.cend() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(set.vid().v, set.vaccess_hash().v);
if (it == sets.cend()
|| (it->second->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(
inputId.vid().v,
inputId.vaccess_hash().v);
return;
}
const auto set = it->second.get();
auto maxNameWidth = countMaxNameWidth();
auto titleWidth = 0;
auto title = fillSetTitle(*it, maxNameWidth, &titleWidth);
auto count = fillSetCount(*it);
auto title = fillSetTitle(*set, maxNameWidth, &titleWidth);
auto count = fillSetCount(*set);
auto thumbnail = ImagePtr();
auto sticker = (DocumentData*)nullptr;
auto pixw = 0, pixh = 0;
fillSetCover(*it, &thumbnail, &sticker, &pixw, &pixh);
fillSetCover(*set, &thumbnail, &sticker, &pixw, &pixh);
auto installed = true, official = false, unread = false, archived = false, removed = false;
if (!_megagroupSelectedSet || _megagroupSelectedSet->id != it->id) {
_megagroupSetField->setText(it->shortName);
if (!_megagroupSelectedSet || _megagroupSelectedSet->id != set->id) {
_megagroupSetField->setText(set->shortName);
_megagroupSetField->finishAnimating();
}
_megagroupSelectedSet = std::make_unique<Row>(
it->id,
it->access,
set->id,
set->access,
thumbnail,
sticker,
count,
@ -1565,7 +1586,7 @@ void StickersBox::Inner::rebuild() {
auto maxNameWidth = countMaxNameWidth();
clear();
auto &order = ([&]() -> const Stickers::Order & {
const auto &order = ([&]() -> const Stickers::Order & {
if (_section == Section::Installed) {
auto &result = _session->data().stickerSetsOrder();
if (_megagroupSet && result.empty()) {
@ -1588,21 +1609,23 @@ void StickersBox::Inner::rebuild() {
: tr::lng_stickers_group_from_your(tr::now));
updateControlsGeometry();
} else if (_section == Section::Installed) {
auto cloudIt = sets.constFind(Stickers::CloudRecentSetId);
if (cloudIt != sets.cend() && !cloudIt->stickers.isEmpty()) {
rebuildAppendSet(cloudIt.value(), maxNameWidth);
auto cloudIt = sets.find(Stickers::CloudRecentSetId);
if (cloudIt != sets.cend() && !cloudIt->second->stickers.isEmpty()) {
rebuildAppendSet(*cloudIt->second, maxNameWidth);
}
}
for_const (auto setId, order) {
auto it = sets.constFind(setId);
for (const auto setId : order) {
auto it = sets.find(setId);
if (it == sets.cend()) {
continue;
}
rebuildAppendSet(it.value(), maxNameWidth);
const auto set = it->second.get();
rebuildAppendSet(*set, maxNameWidth);
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(it->id, it->access);
if (set->stickers.isEmpty()
|| (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(set->id, set->access);
}
}
_session->api().requestStickerSets();
@ -1632,16 +1655,16 @@ void StickersBox::Inner::updateRows() {
int maxNameWidth = countMaxNameWidth();
auto &sets = _session->data().stickerSets();
for (const auto &row : _rows) {
const auto it = sets.constFind(row->id);
const auto it = sets.find(row->id);
if (it == sets.cend()) {
continue;
}
const auto &set = it.value();
const auto set = it->second.get();
if (!row->sticker) {
auto thumbnail = ImagePtr();
auto sticker = (DocumentData*)nullptr;
auto pixw = 0, pixh = 0;
fillSetCover(set, &thumbnail, &sticker, &pixw, &pixh);
fillSetCover(*set, &thumbnail, &sticker, &pixw, &pixh);
if (sticker) {
if ((row->thumbnail.get() != thumbnail.get())
|| (!thumbnail && row->sticker != sticker)) {
@ -1659,7 +1682,7 @@ void StickersBox::Inner::updateRows() {
if (!row->isRecentSet()) {
auto wasInstalled = row->installed;
auto wasArchived = row->archived;
fillSetFlags(set, &row->installed, &row->official, &row->unread, &row->archived);
fillSetFlags(*set, &row->installed, &row->official, &row->unread, &row->archived);
if (_section == Section::Installed) {
row->archived = false;
}
@ -1667,8 +1690,8 @@ void StickersBox::Inner::updateRows() {
row->ripple.reset();
}
}
row->title = fillSetTitle(set, maxNameWidth, &row->titleWidth);
row->count = fillSetCount(set);
row->title = fillSetTitle(*set, maxNameWidth, &row->titleWidth);
row->count = fillSetCount(*set);
}
update();
}
@ -1739,7 +1762,7 @@ void StickersBox::Inner::rebuildAppendSet(const Stickers::Set &set, int maxNameW
}
void StickersBox::Inner::fillSetCover(const Stickers::Set &set, ImagePtr *thumbnail, DocumentData **outSticker, int *outWidth, int *outHeight) const {
*thumbnail = set.thumbnail;
//*thumbnail = set.thumbnail; // #TODO optimize stickers
if (set.stickers.isEmpty()) {
*outSticker = nullptr;
*outWidth = *outHeight = 0;
@ -1747,8 +1770,10 @@ void StickersBox::Inner::fillSetCover(const Stickers::Set &set, ImagePtr *thumbn
}
auto sticker = *outSticker = set.stickers.front();
const auto size = set.thumbnail
? set.thumbnail->size()
const auto size = set.hasThumbnail()
? QSize(
set.thumbnailLocation().width(),
set.thumbnailLocation().height())
: sticker->hasThumbnail()
? QSize(
sticker->thumbnailLocation().width(),
@ -1775,11 +1800,13 @@ void StickersBox::Inner::fillSetCover(const Stickers::Set &set, ImagePtr *thumbn
int StickersBox::Inner::fillSetCount(const Stickers::Set &set) const {
int result = set.stickers.isEmpty() ? set.count : set.stickers.size(), added = 0;
if (set.id == Stickers::CloudRecentSetId) {
auto customIt = _session->data().stickerSets().constFind(Stickers::CustomSetId);
if (customIt != _session->data().stickerSets().cend()) {
added = customIt->stickers.size();
for_const (auto &sticker, Stickers::GetRecentPack()) {
if (customIt->stickers.indexOf(sticker.first) < 0) {
const auto &sets = _session->data().stickerSets();
auto customIt = sets.find(Stickers::CustomSetId);
if (customIt != sets.cend()) {
added = customIt->second->stickers.size();
const auto &recent = Stickers::GetRecentPack();
for (const auto &sticker : recent) {
if (customIt->second->stickers.indexOf(sticker.first) < 0) {
++added;
}
}

View File

@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
#include "base/timer.h"
#include "mtproto/sender.h"
#include "chat_helpers/stickers.h"
#include "chat_helpers/stickers_set.h"
#include "ui/effects/animations.h"
#include "ui/special_fields.h"
@ -33,6 +33,14 @@ namespace Main {
class Session;
} // namespace Main
namespace Data {
class DocumentMedia;
} // namespace Data
namespace Lottie {
class SinglePlayer;
} // namespace Lottie
class StickersBox final
: public Ui::BoxContent
, public RPCSender
@ -235,9 +243,7 @@ private:
int32 pixh);
~Row();
bool isRecentSet() const {
return (id == Stickers::CloudRecentSetId);
}
bool isRecentSet() const;
uint64 id = 0;
uint64 accessHash = 0;

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "mtproto/facade.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"

View File

@ -5,12 +5,13 @@ 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 "stickers.h"
#include "chat_helpers/stickers.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "chat_helpers/stickers_set.h"
#include "boxes/stickers_box.h"
#include "boxes/confirm_box.h"
#include "lang/lang_keys.h"
@ -21,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h"
#include "ui/toast/toast.h"
#include "ui/emoji_config.h"
#include "ui/image/image_location_factory.h"
#include "base/unixtime.h"
#include "lottie/lottie_single_player.h"
#include "lottie/lottie_multi_player.h"
@ -41,7 +43,7 @@ void ApplyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
Order archived;
archived.reserve(v.size());
QMap<uint64, uint64> setsToRequest;
for_const (auto &stickerSet, v) {
for (const auto &stickerSet : v) {
const MTPDstickerSet *setData = nullptr;
switch (stickerSet.type()) {
case mtpc_stickerSetCovered: {
@ -91,21 +93,22 @@ void ApplyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
// For testing: Just apply random subset or your sticker sets as archived.
bool ApplyArchivedResultFake() {
auto sets = QVector<MTPStickerSetCovered>();
for (auto &set : Auth().data().stickerSetsRef()) {
if ((set.flags & MTPDstickerSet::Flag::f_installed_date)
&& !(set.flags & MTPDstickerSet_ClientFlag::f_special)) {
for (const auto &[id, set] : Auth().data().stickerSetsRef()) {
const auto raw = set.get();
if ((raw->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(raw->flags & MTPDstickerSet_ClientFlag::f_special)) {
if (rand_value<uint32>() % 128 < 64) {
const auto data = MTP_stickerSet(
MTP_flags(set.flags | MTPDstickerSet::Flag::f_archived),
MTP_int(set.installDate),
MTP_long(set.id),
MTP_long(set.access),
MTP_string(set.title),
MTP_string(set.shortName),
MTP_flags(raw->flags | MTPDstickerSet::Flag::f_archived),
MTP_int(raw->installDate),
MTP_long(raw->id),
MTP_long(raw->access),
MTP_string(raw->title),
MTP_string(raw->shortName),
MTP_photoSizeEmpty(MTP_string()),
MTP_int(0),
MTP_int(set.count),
MTP_int(set.hash));
MTP_int(raw->count),
MTP_int(raw->hash));
sets.push_back(MTP_stickerSetCovered(
data,
MTP_documentEmpty(MTP_long(0))));
@ -128,11 +131,12 @@ void InstallLocally(uint64 setId) {
return;
}
auto flags = it->flags;
it->flags &= ~(MTPDstickerSet::Flag::f_archived | MTPDstickerSet_ClientFlag::f_unread);
it->flags |= MTPDstickerSet::Flag::f_installed_date;
it->installDate = base::unixtime::now();
auto changedFlags = flags ^ it->flags;
const auto set = it->second.get();
auto flags = set->flags;
set->flags &= ~(MTPDstickerSet::Flag::f_archived | MTPDstickerSet_ClientFlag::f_unread);
set->flags |= MTPDstickerSet::Flag::f_installed_date;
set->installDate = base::unixtime::now();
auto changedFlags = flags ^ set->flags;
auto &order = Auth().data().stickerSetsOrderRef();
int insertAtIndex = 0, currentIndex = order.indexOf(setId);
@ -143,14 +147,15 @@ void InstallLocally(uint64 setId) {
order.insert(insertAtIndex, setId);
}
auto custom = sets.find(CustomSetId);
if (custom != sets.cend()) {
for_const (auto sticker, it->stickers) {
auto customIt = sets.find(CustomSetId);
if (customIt != sets.cend()) {
const auto custom = customIt->second.get();
for (const auto sticker : std::as_const(set->stickers)) {
int removeIndex = custom->stickers.indexOf(sticker);
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
}
if (custom->stickers.isEmpty()) {
sets.erase(custom);
sets.erase(customIt);
}
}
Local::writeInstalledStickers();
@ -174,8 +179,9 @@ void UndoInstallLocally(uint64 setId) {
return;
}
it->flags &= ~MTPDstickerSet::Flag::f_installed_date;
it->installDate = TimeId(0);
const auto set = it->second.get();
set->flags &= ~MTPDstickerSet::Flag::f_installed_date;
set->installDate = TimeId(0);
auto &order = Auth().data().stickerSetsOrderRef();
int currentIndex = order.indexOf(setId);
@ -192,11 +198,12 @@ void UndoInstallLocally(uint64 setId) {
}
bool IsFaved(not_null<const DocumentData*> document) {
const auto it = Auth().data().stickerSets().constFind(FavedSetId);
if (it == Auth().data().stickerSets().cend()) {
const auto &sets = Auth().data().stickerSets();
const auto it = sets.find(FavedSetId);
if (it == sets.cend()) {
return false;
}
for (const auto sticker : it->stickers) {
for (const auto sticker : it->second->stickers) {
if (sticker == document) {
return true;
}
@ -254,11 +261,14 @@ void MoveFavedToFront(Set &set, int index) {
void RequestSetToPushFaved(not_null<DocumentData*> document);
void SetIsFaved(not_null<DocumentData*> document, std::optional<std::vector<not_null<EmojiPtr>>> emojiList = std::nullopt) {
auto &sets = Auth().data().stickerSetsRef();
void SetIsFaved(
not_null<DocumentData*> document,
std::optional<std::vector<not_null<EmojiPtr>>> emojiList = std::nullopt) {
auto &sets = document->owner().stickerSetsRef();
auto it = sets.find(FavedSetId);
if (it == sets.end()) {
it = sets.insert(FavedSetId, Set(
it = sets.emplace(FavedSetId, std::make_unique<Set>(
&document->owner(),
FavedSetId,
uint64(0),
Lang::Hard::FavedSetTitle(),
@ -266,19 +276,19 @@ void SetIsFaved(not_null<DocumentData*> document, std::optional<std::vector<not_
0, // count
0, // hash
MTPDstickerSet_ClientFlag::f_special | 0,
TimeId(0),
ImagePtr()));
TimeId(0))).first;
}
auto index = it->stickers.indexOf(document);
const auto set = it->second.get();
auto index = set->stickers.indexOf(document);
if (index == 0) {
return;
}
if (index > 0) {
MoveFavedToFront(*it, index);
MoveFavedToFront(*set, index);
} else if (emojiList) {
PushFavedToFront(*it, document, *emojiList);
PushFavedToFront(*set, document, *emojiList);
} else if (auto list = GetEmojiListFromSet(document)) {
PushFavedToFront(*it, document, *list);
PushFavedToFront(*set, document, *list);
} else {
RequestSetToPushFaved(document);
return;
@ -304,9 +314,9 @@ void RequestSetToPushFaved(not_null<DocumentData*> document) {
auto list = std::vector<not_null<EmojiPtr>>();
auto &d = result.c_messages_stickerSet();
list.reserve(d.vpacks().v.size());
for_const (auto &mtpPack, d.vpacks().v) {
for (const auto &mtpPack : d.vpacks().v) {
auto &pack = mtpPack.c_stickerPack();
for_const (auto &documentId, pack.vdocuments().v) {
for (const auto &documentId : pack.vdocuments().v) {
if (documentId.v == document->id) {
if (const auto emoji = Ui::Emoji::Find(qs(mtpPack.c_stickerPack().vemoticon()))) {
list.emplace_back(emoji);
@ -332,23 +342,24 @@ void SetIsNotFaved(not_null<DocumentData*> document) {
if (it == sets.end()) {
return;
}
auto index = it->stickers.indexOf(document);
const auto set = it->second.get();
auto index = set->stickers.indexOf(document);
if (index < 0) {
return;
}
it->stickers.removeAt(index);
for (auto i = it->emoji.begin(); i != it->emoji.end();) {
set->stickers.removeAt(index);
for (auto i = set->emoji.begin(); i != set->emoji.end();) {
auto index = i->indexOf(document);
if (index >= 0) {
i->removeAt(index);
if (i->empty()) {
i = it->emoji.erase(i);
i = set->emoji.erase(i);
continue;
}
}
++i;
}
if (it->stickers.empty()) {
if (set->stickers.empty()) {
sets.erase(it);
}
Local::writeFavedStickers();
@ -369,14 +380,14 @@ void SetsReceived(const QVector<MTPStickerSet> &data, int32 hash) {
auto &sets = Auth().data().stickerSetsRef();
QMap<uint64, uint64> setsToRequest;
for (auto &set : sets) {
if (!(set.flags & MTPDstickerSet::Flag::f_archived)) {
for (auto &[id, set] : sets) {
if (!(set->flags & MTPDstickerSet::Flag::f_archived)) {
// Mark for removing.
set.flags &= ~MTPDstickerSet::Flag::f_installed_date;
set.installDate = 0;
set->flags &= ~MTPDstickerSet::Flag::f_installed_date;
set->installDate = 0;
}
}
for_const (auto &setData, data) {
for (const auto &setData : data) {
if (setData.type() == mtpc_stickerSet) {
auto set = FeedSet(setData.c_stickerSet());
if (!(set->flags & MTPDstickerSet::Flag::f_archived) || (set->flags & MTPDstickerSet::Flag::f_official)) {
@ -390,13 +401,14 @@ void SetsReceived(const QVector<MTPStickerSet> &data, int32 hash) {
auto writeRecent = false;
auto &recent = GetRecentPack();
for (auto it = sets.begin(), e = sets.end(); it != e;) {
bool installed = (it->flags & MTPDstickerSet::Flag::f_installed_date);
bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special);
bool archived = (it->flags & MTPDstickerSet::Flag::f_archived);
const auto set = it->second.get();
bool installed = (set->flags & MTPDstickerSet::Flag::f_installed_date);
bool featured = (set->flags & MTPDstickerSet_ClientFlag::f_featured);
bool special = (set->flags & MTPDstickerSet_ClientFlag::f_special);
bool archived = (set->flags & MTPDstickerSet::Flag::f_archived);
if (!installed) { // remove not mine sets from recent stickers
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) {
if (set->stickers.indexOf(i->first) >= 0) {
i = recent.erase(i);
writeRecent = true;
} else {
@ -437,7 +449,7 @@ void SetPackAndEmoji(
set.stickers = std::move(pack);
set.dates = std::move(dates);
set.emoji.clear();
for_const (auto &mtpPack, packs) {
for (const auto &mtpPack : packs) {
Assert(mtpPack.type() == mtpc_stickerPack);
auto &pack = mtpPack.c_stickerPack();
if (auto emoji = Ui::Emoji::Find(qs(pack.vemoticon()))) {
@ -473,7 +485,8 @@ void SpecialSetReceived(
}
} else {
if (it == sets.cend()) {
it = sets.insert(setId, Set(
it = sets.emplace(setId, std::make_unique<Set>(
&Auth().data(),
setId,
uint64(0),
setTitle,
@ -481,19 +494,19 @@ void SpecialSetReceived(
0, // count
0, // hash
MTPDstickerSet_ClientFlag::f_special | 0,
TimeId(0),
ImagePtr()));
TimeId(0))).first;
} else {
it->title = setTitle;
it->second->title = setTitle;
}
it->hash = hash;
const auto set = it->second.get();
set->hash = hash;
auto dates = std::vector<TimeId>();
auto dateIndex = 0;
auto datesAvailable = (items.size() == usageDates.size())
&& (setId == CloudRecentSetId);
auto custom = sets.find(CustomSetId);
auto customIt = sets.find(CustomSetId);
auto pack = Pack();
pack.reserve(items.size());
for (const auto &item : items) {
@ -507,22 +520,24 @@ void SpecialSetReceived(
if (datesAvailable) {
dates.push_back(TimeId(usageDates[dateIndex - 1].v));
}
if (custom != sets.cend()) {
if (customIt != sets.cend()) {
const auto custom = customIt->second.get();
auto index = custom->stickers.indexOf(document);
if (index >= 0) {
custom->stickers.removeAt(index);
}
}
}
if (custom != sets.cend() && custom->stickers.isEmpty()) {
sets.erase(custom);
custom = sets.end();
if (customIt != sets.cend()
&& customIt->second->stickers.isEmpty()) {
sets.erase(customIt);
customIt = sets.end();
}
auto writeRecent = false;
auto &recent = GetRecentPack();
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0 && pack.indexOf(i->first) < 0) {
if (set->stickers.indexOf(i->first) >= 0 && pack.indexOf(i->first) < 0) {
i = recent.erase(i);
writeRecent = true;
} else {
@ -533,7 +548,7 @@ void SpecialSetReceived(
if (pack.isEmpty()) {
sets.erase(it);
} else {
SetPackAndEmoji(*it, std::move(pack), std::move(dates), packs);
SetPackAndEmoji(*set, std::move(pack), std::move(dates), packs);
}
if (writeRecent) {
@ -561,7 +576,7 @@ void SpecialSetReceived(
}
void FeaturedSetsReceived(
const QVector<MTPStickerSetCovered> &data,
const QVector<MTPStickerSetCovered> &list,
const QVector<MTPlong> &unread,
int32 hash) {
auto &&unreadIds = ranges::view::all(
@ -579,87 +594,76 @@ void FeaturedSetsReceived(
auto &sets = Auth().data().stickerSetsRef();
auto setsToRequest = base::flat_map<uint64, uint64>();
for (auto &set : sets) {
for (auto &[id, set] : sets) {
// Mark for removing.
set.flags &= ~MTPDstickerSet_ClientFlag::f_featured;
set->flags &= ~MTPDstickerSet_ClientFlag::f_featured;
}
for (int i = 0, l = data.size(); i != l; ++i) {
auto &setData = data[i];
const MTPDstickerSet *set = nullptr;
switch (setData.type()) {
case mtpc_stickerSetCovered: {
auto &d = setData.c_stickerSetCovered();
if (d.vset().type() == mtpc_stickerSet) {
set = &d.vset().c_stickerSet();
for (const auto &entry : list) {
const auto data = entry.match([&](const auto &data) {
return data.vset().match([&](const MTPDstickerSet &data) {
return &data;
});
});
auto it = sets.find(data->vid().v);
const auto title = GetSetTitle(*data);
const auto installDate = data->vinstalled_date().value_or_empty();
const auto thumb = data->vthumb();
if (it == sets.cend()) {
auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured
| MTPDstickerSet_ClientFlag::f_not_loaded;
if (unreadMap.contains(data->vid().v)) {
setClientFlags |= MTPDstickerSet_ClientFlag::f_unread;
}
} break;
case mtpc_stickerSetMultiCovered: {
auto &d = setData.c_stickerSetMultiCovered();
if (d.vset().type() == mtpc_stickerSet) {
set = &d.vset().c_stickerSet();
}
} break;
}
if (set) {
auto it = sets.find(set->vid().v);
const auto title = GetSetTitle(*set);
const auto installDate = set->vinstalled_date().value_or_empty();
const auto thumb = set->vthumb();
const auto thumbnail = thumb
? Images::Create(*set, *thumb)
: ImagePtr();
if (it == sets.cend()) {
auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured
| MTPDstickerSet_ClientFlag::f_not_loaded;
if (unreadMap.contains(set->vid().v)) {
setClientFlags |= MTPDstickerSet_ClientFlag::f_unread;
}
it = sets.insert(set->vid().v, Set(
set->vid().v,
set->vaccess_hash().v,
title,
qs(set->vshort_name()),
set->vcount().v,
set->vhash().v,
set->vflags().v | setClientFlags,
installDate,
thumbnail));
it = sets.emplace(data->vid().v, std::make_unique<Set>(
&Auth().data(),
data->vid().v,
data->vaccess_hash().v,
title,
qs(data->vshort_name()),
data->vcount().v,
data->vhash().v,
data->vflags().v | setClientFlags,
installDate)).first;
it->second->setThumbnail(
Images::FromPhotoSize(&Auth(), *data, *thumb));
} else {
const auto set = it->second.get();
set->access = data->vaccess_hash().v;
set->title = title;
set->shortName = qs(data->vshort_name());
auto clientFlags = set->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_special);
set->flags = data->vflags().v | clientFlags;
set->flags |= MTPDstickerSet_ClientFlag::f_featured;
set->installDate = installDate;
set->setThumbnail(
Images::FromPhotoSize(&Auth(), *data, *thumb));
if (unreadMap.contains(set->id)) {
set->flags |= MTPDstickerSet_ClientFlag::f_unread;
} else {
it->access = set->vaccess_hash().v;
it->title = title;
it->shortName = qs(set->vshort_name());
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_special);
it->flags = set->vflags().v | clientFlags;
it->flags |= MTPDstickerSet_ClientFlag::f_featured;
it->installDate = installDate;
it->thumbnail = thumbnail;
if (unreadMap.contains(it->id)) {
it->flags |= MTPDstickerSet_ClientFlag::f_unread;
} else {
it->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
}
if (it->count != set->vcount().v || it->hash != set->vhash().v || it->emoji.isEmpty()) {
it->count = set->vcount().v;
it->hash = set->vhash().v;
it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; // need to request this set
}
set->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
}
setsOrder.push_back(set->vid().v);
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
setsToRequest.emplace(set->vid().v, set->vaccess_hash().v);
if (set->count != data->vcount().v || set->hash != data->vhash().v || set->emoji.isEmpty()) {
set->count = data->vcount().v;
set->hash = data->vhash().v;
set->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; // need to request this set
}
}
setsOrder.push_back(data->vid().v);
if (it->second->stickers.isEmpty()
|| (it->second->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
setsToRequest.emplace(data->vid().v, data->vaccess_hash().v);
}
}
auto unreadCount = 0;
for (auto it = sets.begin(), e = sets.end(); it != e;) {
bool installed = (it->flags & MTPDstickerSet::Flag::f_installed_date);
bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special);
bool archived = (it->flags & MTPDstickerSet::Flag::f_archived);
const auto set = it->second.get();
bool installed = (set->flags & MTPDstickerSet::Flag::f_installed_date);
bool featured = (set->flags & MTPDstickerSet_ClientFlag::f_featured);
bool special = (set->flags & MTPDstickerSet_ClientFlag::f_special);
bool archived = (set->flags & MTPDstickerSet::Flag::f_archived);
if (installed || featured || special || archived) {
if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
if (featured && (set->flags & MTPDstickerSet_ClientFlag::f_unread)) {
++unreadCount;
}
++it;
@ -773,7 +777,7 @@ std::vector<not_null<DocumentData*>> GetListByEmoji(
const auto setId = sticker->set.c_inputStickerSetID().vid().v;
const auto setIt = sets.find(setId);
if (setIt != sets.end()) {
return InstallDateAdjusted(setIt->installDate, document);
return InstallDateAdjusted(setIt->second->installDate, document);
}
}
return TimeId(0);
@ -781,20 +785,21 @@ std::vector<not_null<DocumentData*>> GetListByEmoji(
auto recentIt = sets.find(Stickers::CloudRecentSetId);
if (recentIt != sets.cend()) {
auto i = recentIt->emoji.constFind(original);
if (i != recentIt->emoji.cend()) {
const auto recent = recentIt->second.get();
auto i = recent->emoji.constFind(original);
if (i != recent->emoji.cend()) {
result.reserve(i->size());
for (const auto document : *i) {
const auto usageDate = [&] {
if (recentIt->dates.empty()) {
if (recent->dates.empty()) {
return TimeId(0);
}
const auto index = recentIt->stickers.indexOf(document);
const auto index = recent->stickers.indexOf(document);
if (index < 0) {
return TimeId(0);
}
Assert(index < recentIt->dates.size());
return recentIt->dates[index];
Assert(index < recent->dates.size());
return recent->dates[index];
}();
const auto date = usageDate
? usageDate
@ -808,22 +813,23 @@ std::vector<not_null<DocumentData*>> GetListByEmoji(
const auto addList = [&](const Order &order, MTPDstickerSet::Flag skip) {
for (const auto setId : order) {
auto it = sets.find(setId);
if (it == sets.cend() || (it->flags & skip)) {
if (it == sets.cend() || (it->second->flags & skip)) {
continue;
}
if (it->emoji.isEmpty()) {
setsToRequest.emplace(it->id, it->access);
it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded;
const auto set = it->second.get();
if (set->emoji.isEmpty()) {
setsToRequest.emplace(set->id, set->access);
set->flags |= MTPDstickerSet_ClientFlag::f_not_loaded;
continue;
}
auto i = it->emoji.constFind(original);
if (i == it->emoji.cend()) {
auto i = set->emoji.constFind(original);
if (i == set->emoji.cend()) {
continue;
}
const auto my = (it->flags & MTPDstickerSet::Flag::f_installed_date);
const auto my = (set->flags & MTPDstickerSet::Flag::f_installed_date);
result.reserve(result.size() + i->size());
for (const auto document : *i) {
const auto installDate = my ? it->installDate : TimeId(0);
const auto installDate = my ? set->installDate : TimeId(0);
const auto date = (installDate > 1)
? InstallDateAdjusted(installDate, document)
: my
@ -879,12 +885,13 @@ std::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet(
return std::nullopt;
}
auto &sets = Auth().data().stickerSets();
auto it = sets.constFind(inputSet.c_inputStickerSetID().vid().v);
auto it = sets.find(inputSet.c_inputStickerSetID().vid().v);
if (it == sets.cend()) {
return std::nullopt;
}
const auto set = it->second.get();
auto result = std::vector<not_null<EmojiPtr>>();
for (auto i = it->emoji.cbegin(), e = it->emoji.cend(); i != e; ++i) {
for (auto i = set->emoji.cbegin(), e = set->emoji.cend(); i != e; ++i) {
if (i->contains(document)) {
result.emplace_back(i.key());
}
@ -897,61 +904,65 @@ std::optional<std::vector<not_null<EmojiPtr>>> GetEmojiListFromSet(
return std::nullopt;
}
Set *FeedSet(const MTPDstickerSet &set) {
Set *FeedSet(const MTPDstickerSet &data) {
auto &sets = Auth().data().stickerSetsRef();
auto it = sets.find(set.vid().v);
auto title = GetSetTitle(set);
auto it = sets.find(data.vid().v);
auto title = GetSetTitle(data);
auto flags = MTPDstickerSet::Flags(0);
const auto thumb = set.vthumb();
const auto thumbnail = thumb ? Images::Create(set, *thumb) : ImagePtr();
const auto thumb = data.vthumb();
if (it == sets.cend()) {
it = sets.insert(set.vid().v, Stickers::Set(
set.vid().v,
set.vaccess_hash().v,
it = sets.emplace(data.vid().v, std::make_unique<Set>(
&Auth().data(),
data.vid().v,
data.vaccess_hash().v,
title,
qs(set.vshort_name()),
set.vcount().v,
set.vhash().v,
set.vflags().v | MTPDstickerSet_ClientFlag::f_not_loaded,
set.vinstalled_date().value_or_empty(),
thumbnail));
qs(data.vshort_name()),
data.vcount().v,
data.vhash().v,
data.vflags().v | MTPDstickerSet_ClientFlag::f_not_loaded,
data.vinstalled_date().value_or_empty())).first;
it->second->setThumbnail(
Images::FromPhotoSize(&Auth(), data, *thumb));
} else {
it->access = set.vaccess_hash().v;
it->title = title;
it->shortName = qs(set.vshort_name());
flags = it->flags;
auto clientFlags = it->flags
const auto set = it->second.get();
set->access = data.vaccess_hash().v;
set->title = title;
set->shortName = qs(data.vshort_name());
flags = set->flags;
auto clientFlags = set->flags
& (MTPDstickerSet_ClientFlag::f_featured
| MTPDstickerSet_ClientFlag::f_unread
| MTPDstickerSet_ClientFlag::f_not_loaded
| MTPDstickerSet_ClientFlag::f_special);
it->flags = set.vflags().v | clientFlags;
const auto installDate = set.vinstalled_date();
it->installDate = installDate
set->flags = data.vflags().v | clientFlags;
const auto installDate = data.vinstalled_date();
set->installDate = installDate
? (installDate->v ? installDate->v : base::unixtime::now())
: TimeId(0);
it->thumbnail = thumbnail;
if (it->count != set.vcount().v
|| it->hash != set.vhash().v
|| it->emoji.isEmpty()) {
// Need to request this set.
it->count = set.vcount().v;
it->hash = set.vhash().v;
it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded;
it->second->setThumbnail(
Images::FromPhotoSize(&Auth(), data, *thumb));
if (set->count != data.vcount().v
|| set->hash != data.vhash().v
|| set->emoji.isEmpty()) {
// Need to request this data.
set->count = data.vcount().v;
set->hash = data.vhash().v;
set->flags |= MTPDstickerSet_ClientFlag::f_not_loaded;
}
}
auto changedFlags = (flags ^ it->flags);
const auto set = it->second.get();
auto changedFlags = (flags ^ set->flags);
if (changedFlags & MTPDstickerSet::Flag::f_archived) {
auto index = Auth().data().archivedStickerSetsOrder().indexOf(it->id);
if (it->flags & MTPDstickerSet::Flag::f_archived) {
auto index = Auth().data().archivedStickerSetsOrder().indexOf(set->id);
if (set->flags & MTPDstickerSet::Flag::f_archived) {
if (index < 0) {
Auth().data().archivedStickerSetsOrderRef().push_front(it->id);
Auth().data().archivedStickerSetsOrderRef().push_front(set->id);
}
} else if (index >= 0) {
Auth().data().archivedStickerSetsOrderRef().removeAt(index);
}
}
return &it.value();
return it->second.get();
}
Set *FeedSetFull(const MTPmessages_StickerSet &data) {
@ -963,14 +974,14 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data) {
auto &sets = Auth().data().stickerSetsRef();
auto it = sets.find(s.vid().v);
const auto wasArchived = (it->flags & MTPDstickerSet::Flag::f_archived);
const auto wasArchived = (it->second->flags & MTPDstickerSet::Flag::f_archived);
auto set = FeedSet(s);
set->flags &= ~MTPDstickerSet_ClientFlag::f_not_loaded;
auto &d_docs = d.vdocuments().v;
auto custom = sets.find(Stickers::CustomSetId);
auto customIt = sets.find(Stickers::CustomSetId);
auto inputSet = MTP_inputStickerSetID(
MTP_long(set->id),
MTP_long(set->access));
@ -985,16 +996,17 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data) {
if (document->sticker()->set.type() != mtpc_inputStickerSetID) {
document->sticker()->set = inputSet;
}
if (custom != sets.cend()) {
if (customIt != sets.cend()) {
const auto custom = customIt->second.get();
const auto index = custom->stickers.indexOf(document);
if (index >= 0) {
custom->stickers.removeAt(index);
}
}
}
if (custom != sets.cend() && custom->stickers.isEmpty()) {
sets.erase(custom);
custom = sets.end();
if (customIt != sets.cend() && customIt->second->stickers.isEmpty()) {
sets.erase(customIt);
customIt = sets.end();
}
auto writeRecent = false;
@ -1276,31 +1288,4 @@ std::unique_ptr<Lottie::SinglePlayer> LottieThumbnail(
box);
}
ThumbnailSource::ThumbnailSource(
const StorageImageLocation &location,
int size)
: StorageSource(location, size) {
}
QImage ThumbnailSource::takeLoaded() {
const auto loader = currentLoader();
if (_bytesForAnimated.isEmpty()
&& loader
&& loader->finished()
&& !loader->cancelled()) {
_bytesForAnimated = loader->bytes();
}
auto result = StorageSource::takeLoaded();
if (!_bytesForAnimated.isEmpty()
&& !result.isNull()
&& result.size() != Image::Empty()->original().size()) {
_bytesForAnimated = QByteArray();
}
return result;
}
QByteArray ThumbnailSource::bytesForCache() {
return _bytesForAnimated;
}
} // namespace Stickers

View File

@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "mtproto/sender.h"
#include "ui/image/image_source.h"
class DocumentData;
@ -46,53 +45,7 @@ constexpr auto FeaturedSetId = 0xFFFFFFFFFFFFFFFBULL; // for emoji/stickers pane
constexpr auto FavedSetId = 0xFFFFFFFFFFFFFFFAULL; // for cloud-stored faved stickers
constexpr auto MegagroupSetId = 0xFFFFFFFFFFFFFFEFULL; // for setting up megagroup sticker set
using Order = QList<uint64>;
using SavedGifs = QVector<DocumentData*>;
using Pack = QVector<DocumentData*>;
using ByEmojiMap = QMap<EmojiPtr, Pack>;
struct Set {
Set(
uint64 id,
uint64 access,
const QString &title,
const QString &shortName,
int count,
int32 hash,
MTPDstickerSet::Flags flags,
TimeId installDate,
ImagePtr thumbnail)
: id(id)
, access(access)
, title(title)
, shortName(shortName)
, count(count)
, hash(hash)
, flags(flags)
, installDate(installDate)
, thumbnail(thumbnail) {
}
uint64 id = 0;
uint64 access = 0;
QString title, shortName;
int count = 0;
int32 hash = 0;
MTPDstickerSet::Flags flags;
TimeId installDate = 0;
ImagePtr thumbnail;
Pack stickers;
std::vector<TimeId> dates;
Pack covers;
ByEmojiMap emoji;
};
using Sets = QMap<uint64, Set>;
inline MTPInputStickerSet inputSetId(const Set &set) {
if (set.id && set.access) {
return MTP_inputStickerSetID(MTP_long(set.id), MTP_long(set.access));
}
return MTP_inputStickerSetShortName(MTP_string(set.shortName));
}
class Set;
void ApplyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d);
bool ApplyArchivedResultFake(); // For testing.
@ -110,7 +63,7 @@ void SpecialSetReceived(
const QVector<MTPStickerPack> &packs = QVector<MTPStickerPack>(),
const QVector<MTPint> &usageDates = QVector<MTPint>());
void FeaturedSetsReceived(
const QVector<MTPStickerSetCovered> &data,
const QVector<MTPStickerSetCovered> &list,
const QVector<MTPlong> &unread,
int32 hash);
void GifsReceived(const QVector<MTPDocument> &items, int32 hash);
@ -168,19 +121,4 @@ enum class LottieSize : uchar {
QSize box,
std::shared_ptr<Lottie::FrameRenderer> renderer = nullptr);
class ThumbnailSource : public Images::StorageSource {
public:
ThumbnailSource(
const StorageImageLocation &location,
int size);
QImage takeLoaded() override;
QByteArray bytesForCache() override;
private:
QByteArray _bytesForAnimated;
};
} // namespace Stickers

View File

@ -184,7 +184,8 @@ private:
};
auto StickersListWidget::PrepareStickers(const Stickers::Pack &pack)
auto StickersListWidget::PrepareStickers(
const QVector<DocumentData*> &pack)
-> std::vector<Sticker> {
return ranges::view::all(
pack
@ -1288,7 +1289,7 @@ void StickersListWidget::fillLocalSearchRows(const QString &query) {
for (const auto &[setId, titleWords] : _searchIndex) {
if (allSearchWordsInTitle(titleWords)) {
if (const auto it = sets.find(setId); it != sets.end()) {
addSearchRow(&*it);
addSearchRow(it->second.get());
}
}
}
@ -1299,7 +1300,7 @@ void StickersListWidget::fillCloudSearchRows(
const auto &sets = session().data().stickerSets();
for (const auto setId : cloudSets) {
if (const auto it = sets.find(setId); it != sets.end()) {
addSearchRow(&*it);
addSearchRow(it->second.get());
}
}
}
@ -1310,7 +1311,7 @@ void StickersListWidget::addSearchRow(not_null<const Stickers::Set*> set) {
set->flags,
set->title,
set->shortName,
set->thumbnail,
ImagePtr(),// set->thumbnail, #TODO optimize stickers
set->count,
!SetInMyList(set->flags),
PrepareStickers(set->stickers.empty()
@ -2123,10 +2124,11 @@ void StickersListWidget::removeRecentSticker(int section, int index) {
auto &sets = session().data().stickerSetsRef();
auto it = sets.find(Stickers::CustomSetId);
if (it != sets.cend()) {
for (int i = 0, l = it->stickers.size(); i < l; ++i) {
if (it->stickers.at(i) == document) {
it->stickers.removeAt(i);
if (it->stickers.isEmpty()) {
const auto set = it->second.get();
for (int i = 0, l = set->stickers.size(); i < l; ++i) {
if (set->stickers.at(i) == document) {
set->stickers.removeAt(i);
if (set->stickers.isEmpty()) {
sets.erase(it);
}
Local::writeInstalledStickers();
@ -2295,14 +2297,14 @@ void StickersListWidget::refreshFeaturedSets() {
const auto till = end(wereOfficial);
for (auto i = from; i != till; ++i) {
auto &set = *i;
auto it = sets.constFind(set.id);
auto it = sets.find(set.id);
if (it == sets.cend()
|| ((it->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(it->flags & MTPDstickerSet::Flag::f_archived)
|| ((it->second->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(it->second->flags & MTPDstickerSet::Flag::f_archived)
&& !_installedLocallySets.contains(set.id))) {
continue;
}
set.flags = it->flags;
set.flags = it->second->flags;
_officialSets.push_back(std::move(set));
}
}
@ -2312,16 +2314,17 @@ void StickersListWidget::refreshSearchSets() {
refreshSearchIndex();
const auto &sets = session().data().stickerSets();
for (auto &set : _searchSets) {
if (const auto it = sets.find(set.id); it != sets.end()) {
set.flags = it->flags;
if (!it->stickers.empty()) {
set.lottiePlayer = nullptr;
set.stickers = PrepareStickers(it->stickers);
for (auto &entry : _searchSets) {
if (const auto it = sets.find(entry.id); it != sets.end()) {
const auto set = it->second.get();
entry.flags = set->flags;
if (!set->stickers.empty()) {
entry.lottiePlayer = nullptr;
entry.stickers = PrepareStickers(set->stickers);
}
if (!SetInMyList(set.flags)) {
_installedLocallySets.remove(set.id);
set.externalLayout = true;
if (!SetInMyList(entry.flags)) {
_installedLocallySets.remove(entry.id);
entry.externalLayout = true;
}
}
}
@ -2373,32 +2376,34 @@ bool StickersListWidget::appendSet(
bool externalLayout,
AppendSkip skip) {
auto &sets = session().data().stickerSets();
auto it = sets.constFind(setId);
if (it == sets.cend() || (!externalLayout && it->stickers.isEmpty())) {
auto it = sets.find(setId);
if (it == sets.cend()
|| (!externalLayout && it->second->stickers.isEmpty())) {
return false;
}
const auto set = it->second.get();
if ((skip == AppendSkip::Archived)
&& (it->flags & MTPDstickerSet::Flag::f_archived)) {
&& (set->flags & MTPDstickerSet::Flag::f_archived)) {
return false;
}
if ((skip == AppendSkip::Installed)
&& (it->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(it->flags & MTPDstickerSet::Flag::f_archived)) {
&& (set->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(set->flags & MTPDstickerSet::Flag::f_archived)) {
if (!_installedLocallySets.contains(setId)) {
return false;
}
}
to.emplace_back(
it->id,
it->flags,
it->title,
it->shortName,
it->thumbnail,
it->count,
set->id,
set->flags,
set->title,
set->shortName,
ImagePtr(), // set->thumbnail, #TODO optimize stickers
set->count,
externalLayout,
PrepareStickers((it->stickers.empty() && externalLayout)
? it->covers
: it->stickers));
PrepareStickers((set->stickers.empty() && externalLayout)
? set->covers
: set->stickers));
return true;
}
@ -2417,13 +2422,13 @@ auto StickersListWidget::collectRecentStickers() -> std::vector<Sticker> {
const auto &sets = session().data().stickerSets();
const auto &recent = Stickers::GetRecentPack();
const auto customIt = sets.constFind(Stickers::CustomSetId);
const auto cloudIt = sets.constFind(Stickers::CloudRecentSetId);
const auto customIt = sets.find(Stickers::CustomSetId);
const auto cloudIt = sets.find(Stickers::CloudRecentSetId);
const auto customCount = (customIt != sets.cend())
? customIt->stickers.size()
? customIt->second->stickers.size()
: 0;
const auto cloudCount = (cloudIt != sets.cend())
? cloudIt->stickers.size()
? cloudIt->second->stickers.size()
: 0;
result.reserve(cloudCount + recent.size() + customCount);
_custom.reserve(cloudCount + recent.size() + customCount);
@ -2448,7 +2453,7 @@ auto StickersListWidget::collectRecentStickers() -> std::vector<Sticker> {
};
if (cloudCount > 0) {
for (const auto document : cloudIt->stickers) {
for (const auto document : cloudIt->second->stickers) {
add(document, false);
}
}
@ -2456,7 +2461,7 @@ auto StickersListWidget::collectRecentStickers() -> std::vector<Sticker> {
add(recentSticker.first, false);
}
if (customCount > 0) {
for (const auto document : customIt->stickers) {
for (const auto document : customIt->second->stickers) {
add(document, true);
}
}
@ -2502,11 +2507,12 @@ void StickersListWidget::refreshRecentStickers(bool performResize) {
void StickersListWidget::refreshFavedStickers() {
clearSelection();
auto &sets = session().data().stickerSets();
auto it = sets.constFind(Stickers::FavedSetId);
if (it == sets.cend() || it->stickers.isEmpty()) {
const auto &sets = session().data().stickerSets();
const auto it = sets.find(Stickers::FavedSetId);
if (it == sets.cend() || it->second->stickers.isEmpty()) {
return;
}
const auto set = it->second.get();
const auto externalLayout = false;
const auto shortName = QString();
const auto thumbnail = ImagePtr();
@ -2517,12 +2523,12 @@ void StickersListWidget::refreshFavedStickers() {
Lang::Hard::FavedSetTitle(),
shortName,
thumbnail,
it->count,
set->count,
externalLayout,
PrepareStickers(it->stickers));
PrepareStickers(set->stickers));
_favedStickersMap = base::flat_set<not_null<DocumentData*>> {
it->stickers.begin(),
it->stickers.end()
set->stickers.begin(),
set->stickers.end()
};
}
@ -2569,11 +2575,12 @@ void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) {
return;
}
auto &set = _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID();
auto &sets = session().data().stickerSets();
auto it = sets.constFind(set.vid().v);
const auto &sets = session().data().stickerSets();
const auto it = sets.find(set.vid().v);
if (it != sets.cend()) {
auto isInstalled = (it->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(it->flags & MTPDstickerSet::Flag::f_archived);
const auto set = it->second.get();
auto isInstalled = (set->flags & MTPDstickerSet::Flag::f_installed_date)
&& !(set->flags & MTPDstickerSet::Flag::f_archived);
if (isInstalled && !canEdit) {
removeHiddenForGroup();
} else if (isShownHere(hidden)) {
@ -2586,9 +2593,9 @@ void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) {
tr::lng_group_stickers(tr::now),
shortName,
thumbnail,
it->count,
set->count,
externalLayout,
PrepareStickers(it->stickers));
PrepareStickers(set->stickers));
}
return;
} else if (!isShownHere(hidden)
@ -2909,11 +2916,11 @@ void StickersListWidget::displaySet(uint64 setId) {
}
}
auto &sets = session().data().stickerSets();
auto it = sets.constFind(setId);
auto it = sets.find(setId);
if (it != sets.cend()) {
_displayingSet = true;
checkHideWithBox(Ui::show(
Box<StickerSetBox>(controller(), Stickers::inputSetId(*it)),
Box<StickerSetBox>(controller(), it->second->mtpInput()),
Ui::LayerOption::KeepOther).data());
}
}
@ -2929,12 +2936,13 @@ void StickersListWidget::checkHideWithBox(QPointer<Ui::BoxContent> box) {
}
void StickersListWidget::installSet(uint64 setId) {
auto &sets = session().data().stickerSets();
auto it = sets.constFind(setId);
const auto &sets = session().data().stickerSets();
const auto it = sets.find(setId);
if (it != sets.cend()) {
const auto input = Stickers::inputSetId(*it);
if ((it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)
|| it->stickers.empty()) {
const auto set = it->second.get();
const auto input = set->mtpInput();
if ((set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)
|| set->stickers.empty()) {
_api.request(MTPmessages_GetStickerSet(
input
)).done([=](const MTPmessages_StickerSet &result) {
@ -2990,38 +2998,40 @@ void StickersListWidget::removeMegagroupSet(bool locally) {
}
void StickersListWidget::removeSet(uint64 setId) {
auto &sets = session().data().stickerSets();
auto it = sets.constFind(setId);
const auto &sets = session().data().stickerSets();
const auto it = sets.find(setId);
if (it != sets.cend()) {
_removingSetId = it->id;
auto text = tr::lng_stickers_remove_pack(tr::now, lt_sticker_pack, it->title);
const auto set = it->second.get();
_removingSetId = set->id;
auto text = tr::lng_stickers_remove_pack(tr::now, lt_sticker_pack, set->title);
Ui::show(Box<ConfirmBox>(text, tr::lng_stickers_remove_pack_confirm(tr::now), crl::guard(this, [=] {
Ui::hideLayer();
auto &sets = session().data().stickerSetsRef();
auto it = sets.find(_removingSetId);
const auto &sets = session().data().stickerSetsRef();
const auto it = sets.find(_removingSetId);
if (it != sets.cend()) {
if (it->id && it->access) {
_api.request(MTPmessages_UninstallStickerSet(MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)))).send();
} else if (!it->shortName.isEmpty()) {
_api.request(MTPmessages_UninstallStickerSet(MTP_inputStickerSetShortName(MTP_string(it->shortName)))).send();
const auto set = it->second.get();
if (set->id && set->access) {
_api.request(MTPmessages_UninstallStickerSet(MTP_inputStickerSetID(MTP_long(set->id), MTP_long(set->access)))).send();
} else if (!set->shortName.isEmpty()) {
_api.request(MTPmessages_UninstallStickerSet(MTP_inputStickerSetShortName(MTP_string(set->shortName)))).send();
}
auto writeRecent = false;
auto &recent = Stickers::GetRecentPack();
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) {
if (set->stickers.indexOf(i->first) >= 0) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
it->flags &= ~MTPDstickerSet::Flag::f_installed_date;
it->installDate = TimeId(0);
set->flags &= ~MTPDstickerSet::Flag::f_installed_date;
set->installDate = TimeId(0);
//
// Set can be in search results.
//
//if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)
// && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) {
//if (!(set->flags & MTPDstickerSet_ClientFlag::f_featured)
// && !(set->flags & MTPDstickerSet_ClientFlag::f_special)) {
// sets.erase(it);
//}
int removeIndex = session().data().stickerSetsOrder().indexOf(_removingSetId);

View File

@ -196,7 +196,8 @@ private:
std::vector<Sticker> stickers;
};
static std::vector<Sticker> PrepareStickers(const Stickers::Pack &pack);
static std::vector<Sticker> PrepareStickers(
const QVector<DocumentData*> &pack);
void preloadMoreOfficial();
QSize boundingBoxSize() const;

View File

@ -0,0 +1,134 @@
/*
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 "chat_helpers/stickers_set.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "storage/file_download.h"
#include "ui/image/image_source.h"
#include "app.h"
namespace Stickers {
void SetThumbnailView::set(
not_null<Main::Session*> session,
QByteArray content) {
auto image = App::readImage(content, nullptr, false);
if (image.isNull()) {
_content = std::move(content);
} else {
_image = std::make_unique<Image>(
std::make_unique<Images::ImageSource>(std::move(image), "PNG"));
}
session->downloaderTaskFinished().notify();
}
Image *SetThumbnailView::image() const {
return _image.get();
}
QByteArray SetThumbnailView::content() const {
return _content;
}
Set::Set(
not_null<Data::Session*> owner,
uint64 id,
uint64 access,
const QString &title,
const QString &shortName,
int count,
int32 hash,
MTPDstickerSet::Flags flags,
TimeId installDate)
: id(id)
, access(access)
, title(title)
, shortName(shortName)
, count(count)
, hash(hash)
, flags(flags)
, installDate(installDate)
, _owner(owner) {
}
MTPInputStickerSet Set::mtpInput() const {
return (id && access)
? MTP_inputStickerSetID(MTP_long(id), MTP_long(access))
: MTP_inputStickerSetShortName(MTP_string(shortName));
}
void Set::setThumbnail(const ImageWithLocation &data) {
Data::UpdateCloudFile(
_thumbnail,
data,
_owner->cache(),
Data::kImageCacheTag,
[=](Data::FileOrigin origin) { loadThumbnail(origin); });
if (!data.bytes.isEmpty()) {
if (_thumbnail.loader) {
_thumbnail.loader->cancel();
}
if (const auto view = activeThumbnailView()) {
view->set(&_owner->session(), data.bytes);
}
}
}
bool Set::hasThumbnail() const {
return _thumbnail.location.valid();
}
bool Set::thumbnailLoading() const {
return (_thumbnail.loader != nullptr);
}
bool Set::thumbnailFailed() const {
return (_thumbnail.flags & Data::CloudFile::Flag::Failed);
}
void Set::loadThumbnail(Data::FileOrigin origin) {
auto &file = _thumbnail;
const auto fromCloud = LoadFromCloudOrLocal;
const auto cacheTag = Data::kImageCacheTag;
const auto autoLoading = false;
Data::LoadCloudFile(file, origin, fromCloud, autoLoading, cacheTag, [=] {
if (const auto active = activeThumbnailView()) {
return !active->image() && active->content().isEmpty();
}
return true;
}, [=](QByteArray result) {
if (const auto active = activeThumbnailView()) {
active->set(&_owner->session(), std::move(result));
}
});
}
const ImageLocation &Set::thumbnailLocation() const {
return _thumbnail.location;
}
int Set::thumbnailByteSize() const {
return _thumbnail.byteSize;
}
std::shared_ptr<SetThumbnailView> Set::createThumbnailView() {
if (auto active = activeThumbnailView()) {
return active;
}
auto view = std::make_shared<SetThumbnailView>();
_thumbnailView = view;
return view;
}
std::shared_ptr<SetThumbnailView> Set::activeThumbnailView() {
return _thumbnailView.lock();
}
} // namespace Stickers

View File

@ -0,0 +1,92 @@
/*
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
#include "data/data_cloud_file.h"
class DocumentData;
namespace Data {
class Session;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
namespace Stickers {
using Order = QList<uint64>;
using SavedGifs = QVector<DocumentData*>;
using Pack = QVector<DocumentData*>;
using ByEmojiMap = QMap<EmojiPtr, Pack>;
class Set;
using Sets = base::flat_map<uint64, std::unique_ptr<Set>>;
class SetThumbnailView final {
public:
void set(not_null<Main::Session*> session, QByteArray content);
[[nodiscard]] Image *image() const;
[[nodiscard]] QByteArray content() const;
private:
std::unique_ptr<Image> _image;
QByteArray _content;
};
class Set final {
public:
Set(
not_null<Data::Session*> owner,
uint64 id,
uint64 access,
const QString &title,
const QString &shortName,
int count,
int32 hash,
MTPDstickerSet::Flags flags,
TimeId installDate);
[[nodiscard]] MTPInputStickerSet mtpInput() const;
void setThumbnail(const ImageWithLocation &data);
[[nodiscard]] bool hasThumbnail() const;
[[nodiscard]] bool thumbnailLoading() const;
[[nodiscard]] bool thumbnailFailed() const;
void loadThumbnail(Data::FileOrigin origin);
[[nodiscard]] const ImageLocation &thumbnailLocation() const;
[[nodiscard]] int thumbnailByteSize() const;
[[nodiscard]] std::shared_ptr<SetThumbnailView> createThumbnailView();
[[nodiscard]] std::shared_ptr<SetThumbnailView> activeThumbnailView();
uint64 id = 0;
uint64 access = 0;
QString title, shortName;
int count = 0;
int32 hash = 0;
MTPDstickerSet::Flags flags;
TimeId installDate = 0;
Pack stickers;
std::vector<TimeId> dates;
Pack covers;
ByEmojiMap emoji;
private:
const not_null<Data::Session*> _owner;
Data::CloudFile _thumbnail;
std::weak_ptr<SetThumbnailView> _thumbnailView;
};
} // namespace Stickers

View File

@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "storage/cache/storage_cache_database.h"
#include "storage/file_download.h"
#include "ui/image/image.h"
#include "ui/image/image_source.h"
#include "main/main_session.h"
#include <compare>
@ -74,7 +74,6 @@ void CloudImage::load(FileOrigin origin) {
active->set(_session, std::move(result));
}
});
}
const ImageLocation &CloudImage::location() const {

View File

@ -18,6 +18,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/file_utilities.h"
#include "core/media_active_cache.h"
#include "core/mime_type.h"
#include "chat_helpers/stickers.h"
#include "chat_helpers/stickers_set.h"
#include "media/audio/media_audio.h"
#include "media/player/media_player_instance.h"
#include "media/streaming/media_streaming_loader_mtproto.h"
@ -1182,16 +1184,16 @@ bool DocumentData::isStickerSetInstalled() const {
const auto &sets = _owner->stickerSets();
return sticker()->set.match([&](const MTPDinputStickerSetID &data) {
const auto i = sets.constFind(data.vid().v);
const auto i = sets.find(data.vid().v);
return (i != sets.cend())
&& !(i->flags & MTPDstickerSet::Flag::f_archived)
&& (i->flags & MTPDstickerSet::Flag::f_installed_date);
&& !(i->second->flags & MTPDstickerSet::Flag::f_archived)
&& (i->second->flags & MTPDstickerSet::Flag::f_installed_date);
}, [&](const MTPDinputStickerSetShortName &data) {
const auto name = qs(data.vshort_name()).toLower();
for (const auto &set : sets) {
if (set.shortName.toLower() == name) {
return !(set.flags & MTPDstickerSet::Flag::f_archived)
&& (set.flags & MTPDstickerSet::Flag::f_installed_date);
for (const auto &[id, set] : sets) {
if (set->shortName.toLower() == name) {
return !(set->flags & MTPDstickerSet::Flag::f_archived)
&& (set->flags & MTPDstickerSet::Flag::f_installed_date);
}
}
return false;

View File

@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "window/themes/window_theme_preview.h"
#include "storage/file_download.h"
#include "ui/image/image.h"
#include "ui/image/image_source.h"
#include "facades.h"
#include "app.h"

View File

@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "history/history.h"
#include "storage/file_download.h"
#include "ui/image/image.h"
#include "ui/image/image_source.h"
namespace Data {

View File

@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "storage/storage_databases.h"
#include "chat_helpers/stickers.h"
#include "chat_helpers/stickers_set.h"
#include "dialogs/dialogs_key.h"
#include "dialogs/dialogs_indexed_list.h"
#include "dialogs/dialogs_main_list.h"

View File

@ -362,17 +362,6 @@ struct Data {
HiddenPinnedMessagesMap HiddenPinnedMessages;
Stickers::Sets StickerSets;
Stickers::Order StickerSetsOrder;
crl::time LastStickersUpdate = 0;
crl::time LastRecentStickersUpdate = 0;
crl::time LastFavedStickersUpdate = 0;
Stickers::Order FeaturedStickerSetsOrder;
int FeaturedStickerSetsUnreadCount = 0;
base::Observable<void> FeaturedStickerSetsUnreadCountChanged;
crl::time LastFeaturedStickersUpdate = 0;
Stickers::Order ArchivedStickerSetsOrder;
bool AskDownloadPath = false;
QString DownloadPath;
QByteArray DownloadPathBookmark;
@ -491,17 +480,6 @@ DefineRefVar(Global, base::Observable<void>, PhoneCallsEnabledChanged);
DefineVar(Global, HiddenPinnedMessagesMap, HiddenPinnedMessages);
DefineVar(Global, Stickers::Sets, StickerSets);
DefineVar(Global, Stickers::Order, StickerSetsOrder);
DefineVar(Global, crl::time, LastStickersUpdate);
DefineVar(Global, crl::time, LastRecentStickersUpdate);
DefineVar(Global, crl::time, LastFavedStickersUpdate);
DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder);
DefineVar(Global, int, FeaturedStickerSetsUnreadCount);
DefineRefVar(Global, base::Observable<void>, FeaturedStickerSetsUnreadCountChanged);
DefineVar(Global, crl::time, LastFeaturedStickersUpdate);
DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder);
DefineVar(Global, bool, AskDownloadPath);
DefineVar(Global, QString, DownloadPath);
DefineVar(Global, QByteArray, DownloadPathBookmark);

View File

@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/media/history_view_media_common.h"
#include "window/window_session_controller.h"
#include "core/application.h" // Application::showDocument.
#include "ui/image/image.h"
#include "ui/image/image_source.h"
#include "ui/grouped_layout.h"
#include "data/data_session.h"
#include "data/data_streaming.h"

View File

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h"
#include "history/view/history_view_cursor_state.h"
#include "storage/localstorage.h"
#include "chat_helpers/stickers.h"
#include "ui/image/image.h"
#include "main/main_session.h"
#include "apiwrap.h"

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "window/window_controller.h"
#include "media/audio/media_audio.h"
#include "ui/image/image.h"
#include "mainwidget.h"
#include "observer_peer.h"
#include "main/main_app_config.h"

View File

@ -3360,7 +3360,8 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
auto it = sets.find(Stickers::CloudRecentSetId);
if (it == sets.cend()) {
if (it == sets.cend()) {
it = sets.insert(Stickers::CloudRecentSetId, Stickers::Set(
it = sets.emplace(Stickers::CloudRecentSetId, std::make_unique<Stickers::Set>(
&session().data(),
Stickers::CloudRecentSetId,
uint64(0),
tr::lng_recent_stickers(tr::now),
@ -3368,28 +3369,28 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
0, // count
0, // hash
MTPDstickerSet_ClientFlag::f_special | 0,
TimeId(0),
ImagePtr()));
TimeId(0))).first;
} else {
it->title = tr::lng_recent_stickers(tr::now);
it->second->title = tr::lng_recent_stickers(tr::now);
}
}
const auto set = it->second.get();
auto removedFromEmoji = std::vector<not_null<EmojiPtr>>();
auto index = it->stickers.indexOf(sticker);
auto index = set->stickers.indexOf(sticker);
if (index > 0) {
if (it->dates.empty()) {
if (set->dates.empty()) {
session().api().requestRecentStickersForce();
} else {
Assert(it->dates.size() == it->stickers.size());
it->dates.erase(it->dates.begin() + index);
Assert(set->dates.size() == set->stickers.size());
set->dates.erase(set->dates.begin() + index);
}
it->stickers.removeAt(index);
for (auto i = it->emoji.begin(); i != it->emoji.end();) {
set->stickers.removeAt(index);
for (auto i = set->emoji.begin(); i != set->emoji.end();) {
if (const auto index = i->indexOf(sticker); index >= 0) {
removedFromEmoji.emplace_back(i.key());
i->removeAt(index);
if (i->isEmpty()) {
i = it->emoji.erase(i);
i = set->emoji.erase(i);
continue;
}
}
@ -3397,17 +3398,17 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
}
}
if (index) {
if (it->dates.size() == it->stickers.size()) {
it->dates.insert(it->dates.begin(), base::unixtime::now());
if (set->dates.size() == set->stickers.size()) {
set->dates.insert(set->dates.begin(), base::unixtime::now());
}
it->stickers.push_front(sticker);
set->stickers.push_front(sticker);
if (const auto emojiList = Stickers::GetEmojiListFromSet(sticker)) {
for (const auto emoji : *emojiList) {
it->emoji[emoji].push_front(sticker);
set->emoji[emoji].push_front(sticker);
}
} else if (!removedFromEmoji.empty()) {
for (const auto emoji : removedFromEmoji) {
it->emoji[emoji].push_front(sticker);
set->emoji[emoji].push_front(sticker);
}
} else {
session().api().requestRecentStickersForce();
@ -3426,7 +3427,7 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
break;
}
}
while (!recent.isEmpty() && it->stickers.size() + recent.size() > Global::StickersRecentLimit()) {
while (!recent.isEmpty() && set->stickers.size() + recent.size() > Global::StickersRecentLimit()) {
writeOldRecent = true;
recent.pop_back();
}
@ -3437,13 +3438,14 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
// Remove that sticker from custom stickers, now it is in cloud recent stickers.
bool writeInstalledStickers = false;
auto custom = sets.find(Stickers::CustomSetId);
if (custom != sets.cend()) {
auto customIt = sets.find(Stickers::CustomSetId);
if (customIt != sets.cend()) {
const auto custom = customIt->second.get();
int removeIndex = custom->stickers.indexOf(sticker);
if (removeIndex >= 0) {
custom->stickers.removeAt(removeIndex);
if (custom->stickers.isEmpty()) {
sets.erase(custom);
sets.erase(customIt);
}
writeInstalledStickers = true;
}
@ -4520,12 +4522,13 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
auto &sets = session().data().stickerSets();
Stickers::Order result;
for (const auto &item : order) {
if (sets.constFind(item.v) == sets.cend()) {
if (sets.find(item.v) == sets.cend()) {
break;
}
result.push_back(item.v);
}
if (result.size() != session().data().stickerSetsOrder().size() || result.size() != order.size()) {
if (result.size() != session().data().stickerSetsOrder().size()
|| result.size() != order.size()) {
session().data().setLastStickersUpdate(0);
session().api().updateStickers();
} else {

View File

@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localstorage.h"
#include "data/data_session.h"
#include "main/main_session.h"
#include "mtproto/facade.h"
#include "layout.h"
#include "facades.h"
#include "app.h"

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "media/audio/media_audio.h"
#include "media/clip/media_clip_reader.h"
#include "mtproto/facade.h"
#include "lottie/lottie_animation.h"
#include "history/history_item.h"
#include "boxes/send_files_box.h"

View File

@ -3438,9 +3438,7 @@ void _writeStickerSet(QDataStream &stream, const Stickers::Set &set) {
<< qint32(set.hash)
<< qint32(set.flags)
<< qint32(set.installDate);
Serialize::writeStorageImageLocation(
stream,
set.thumbnail ? set.thumbnail->location() : StorageImageLocation());
Serialize::writeImageLocation(stream, set.thumbnailLocation());
};
if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) {
writeInfo(-set.count);
@ -3483,7 +3481,7 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
if (!_working()) return;
const auto &sets = Auth().data().stickerSets();
if (sets.isEmpty()) {
if (sets.empty()) {
if (stickersKey) {
ClearKey(stickersKey);
stickersKey = 0;
@ -3497,8 +3495,9 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
quint32 size = sizeof(quint32) + sizeof(qint32) + sizeof(qint32);
int32 setsCount = 0;
for (const auto &set : sets) {
auto result = checkSet(set);
for (const auto &[id, set] : sets) {
const auto raw = set.get();
auto result = checkSet(*raw);
if (result == StickerSetCheckResult::Abort) {
return;
} else if (result == StickerSetCheckResult::Skip) {
@ -3507,28 +3506,26 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
// id + access + title + shortName + stickersCount + hash + flags + installDate
size += sizeof(quint64) * 2
+ Serialize::stringSize(set.title)
+ Serialize::stringSize(set.shortName)
+ Serialize::stringSize(raw->title)
+ Serialize::stringSize(raw->shortName)
+ sizeof(qint32) * 4
+ Serialize::storageImageLocationSize(set.thumbnail
? set.thumbnail->location()
: StorageImageLocation());
if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) {
+ Serialize::imageLocationSize(raw->thumbnailLocation());
if (raw->flags & MTPDstickerSet_ClientFlag::f_not_loaded) {
continue;
}
for (const auto sticker : set.stickers) {
for (const auto sticker : raw->stickers) {
size += Serialize::Document::sizeInStream(sticker);
}
size += sizeof(qint32); // datesCount
if (!set.dates.empty()) {
Assert(set.stickers.size() == set.dates.size());
size += set.dates.size() * sizeof(qint32);
if (!raw->dates.empty()) {
Assert(raw->stickers.size() == raw->dates.size());
size += raw->dates.size() * sizeof(qint32);
}
size += sizeof(qint32); // emojiCount
for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) {
for (auto j = raw->emoji.cbegin(), e = raw->emoji.cend(); j != e; ++j) {
size += Serialize::stringSize(j.key()->id()) + sizeof(qint32) + (j->size() * sizeof(quint64));
}
@ -3555,14 +3552,14 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
<< quint32(kStickersVersionTag)
<< qint32(kStickersSerializeVersion)
<< qint32(setsCount);
for (const auto &set : sets) {
auto result = checkSet(set);
for (const auto &[id, set] : sets) {
auto result = checkSet(*set);
if (result == StickerSetCheckResult::Abort) {
return;
} else if (result == StickerSetCheckResult::Skip) {
continue;
}
_writeStickerSet(data.stream, set);
_writeStickerSet(data.stream, *set);
}
data.stream << order;
@ -3612,7 +3609,7 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
qint32 setHash = 0;
MTPDstickerSet::Flags setFlags = 0;
qint32 setFlagsValue = 0;
StorageImageLocation setThumbnail;
ImageLocation setThumbnail;
stickers.stream
>> setId
@ -3623,13 +3620,12 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
>> setHash
>> setFlagsValue
>> setInstallDate;
const auto thumbnail = Serialize::readStorageImageLocation(
const auto thumbnail = Serialize::readImageLocation(
stickers.version,
stickers.stream);
if (!thumbnail || !_checkStreamStatus(stickers.stream)) {
return failed();
} else if (thumbnail->valid()
&& thumbnail->type() == LocationType::Legacy) {
} else if (thumbnail->valid() && thumbnail->isLegacy()) {
setThumbnail = thumbnail->convertToModern(
LocationType::StickerSetThumb,
setId,
@ -3659,7 +3655,8 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
if (it == sets.cend()) {
// We will set this flags from order lists when reading those stickers.
setFlags &= ~(MTPDstickerSet::Flag::f_installed_date | MTPDstickerSet_ClientFlag::f_featured);
it = sets.insert(setId, Stickers::Set(
it = sets.emplace(setId, std::make_unique<Stickers::Set>(
&Auth().data(),
setId,
setAccess,
setTitle,
@ -3667,23 +3664,24 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
0,
setHash,
MTPDstickerSet::Flags(setFlags),
setInstallDate,
Images::CreateStickerSetThumbnail(setThumbnail)));
setInstallDate)).first;
it->second->setThumbnail(
ImageWithLocation{ .location = setThumbnail });
}
auto &set = it.value();
auto inputSet = MTP_inputStickerSetID(MTP_long(set.id), MTP_long(set.access));
const auto fillStickers = set.stickers.isEmpty();
const auto set = it->second.get();
auto inputSet = MTP_inputStickerSetID(MTP_long(set->id), MTP_long(set->access));
const auto fillStickers = set->stickers.isEmpty();
if (scnt < 0) { // disabled not loaded set
if (!set.count || fillStickers) {
set.count = -scnt;
if (!set->count || fillStickers) {
set->count = -scnt;
}
continue;
}
if (fillStickers) {
set.stickers.reserve(scnt);
set.count = 0;
set->stickers.reserve(scnt);
set->count = 0;
}
Serialize::Document::StickerSetInfo info(setId, setAccess, setShortName);
@ -3699,13 +3697,13 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
}
read.emplace(document->id);
if (fillStickers) {
set.stickers.push_back(document);
if (!(set.flags & MTPDstickerSet_ClientFlag::f_special)) {
set->stickers.push_back(document);
if (!(set->flags & MTPDstickerSet_ClientFlag::f_special)) {
if (document->sticker()->set.type() != mtpc_inputStickerSetID) {
document->sticker()->set = inputSet;
}
}
++set.count;
++set->count;
}
}
@ -3715,17 +3713,17 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
if (datesCount != scnt) {
return failed();
}
const auto fillDates = (set.id == Stickers::CloudRecentSetId)
&& (set.stickers.size() == datesCount);
const auto fillDates = (set->id == Stickers::CloudRecentSetId)
&& (set->stickers.size() == datesCount);
if (fillDates) {
set.dates.clear();
set.dates.reserve(datesCount);
set->dates.clear();
set->dates.reserve(datesCount);
}
for (auto i = 0; i != datesCount; ++i) {
qint32 date = 0;
stickers.stream >> date;
if (fillDates) {
set.dates.push_back(TimeId(date));
set->dates.push_back(TimeId(date));
}
}
}
@ -3752,7 +3750,7 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
if (fillStickers) {
if (auto emoji = Ui::Emoji::Find(emojiString)) {
emoji = emoji->original();
set.emoji.insert(emoji, pack);
set->emoji.insert(emoji, pack);
}
}
}
@ -3785,10 +3783,11 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
for (const auto setId : std::as_const(*outOrder)) {
auto it = sets.find(setId);
if (it != sets.cend()) {
it->flags |= readingFlags;
const auto set = it->second.get();
set->flags |= readingFlags;
if ((readingFlags == MTPDstickerSet::Flag::f_installed_date)
&& !it->installDate) {
it->installDate = kDefaultStickerInstallDate;
&& !set->installDate) {
set->installDate = kDefaultStickerInstallDate;
}
}
}
@ -3888,7 +3887,8 @@ void importOldRecentStickers() {
auto &recent = cRefRecentStickers();
recent.clear();
auto &def = sets.insert(Stickers::DefaultSetId, Stickers::Set(
const auto def = sets.emplace(Stickers::DefaultSetId, std::make_unique<Stickers::Set>(
&Auth().data(),
Stickers::DefaultSetId,
uint64(0),
tr::lng_stickers_default_set(tr::now),
@ -3898,9 +3898,9 @@ void importOldRecentStickers() {
(MTPDstickerSet::Flag::f_official
| MTPDstickerSet::Flag::f_installed_date
| MTPDstickerSet_ClientFlag::f_special),
kDefaultStickerInstallDate,
ImagePtr())).value();
auto &custom = sets.insert(Stickers::CustomSetId, Stickers::Set(
kDefaultStickerInstallDate)).first->second.get();
const auto custom = sets.emplace(Stickers::CustomSetId, std::make_unique<Stickers::Set>(
&Auth().data(),
Stickers::CustomSetId,
uint64(0),
qsl("Custom stickers"),
@ -3909,8 +3909,7 @@ void importOldRecentStickers() {
0, // hash
(MTPDstickerSet::Flag::f_installed_date
| MTPDstickerSet_ClientFlag::f_special),
kDefaultStickerInstallDate,
ImagePtr())).value();
kDefaultStickerInstallDate)).first->second.get();
QMap<uint64, bool> read;
while (!stickers.stream.atEnd()) {
@ -3953,22 +3952,24 @@ void importOldRecentStickers() {
}
if (value > 0) {
def.stickers.push_back(doc);
++def.count;
def->stickers.push_back(doc);
++def->count;
} else {
custom.stickers.push_back(doc);
++custom.count;
custom->stickers.push_back(doc);
++custom->count;
}
if (recent.size() < Global::StickersRecentLimit() && qAbs(value) > 1) {
recent.push_back(qMakePair(doc, qAbs(value)));
}
}
if (def.stickers.isEmpty()) {
if (def->stickers.isEmpty()) {
sets.remove(Stickers::DefaultSetId);
} else {
order.push_front(Stickers::DefaultSetId);
}
if (custom.stickers.isEmpty()) sets.remove(Stickers::CustomSetId);
if (custom->stickers.isEmpty()) {
sets.remove(Stickers::CustomSetId);
}
writeInstalledStickers();
writeUserSettings();
@ -3996,11 +3997,13 @@ void readFeaturedStickers() {
&Auth().data().featuredStickerSetsOrderRef(),
MTPDstickerSet::Flags() | MTPDstickerSet_ClientFlag::f_featured);
auto &sets = Auth().data().stickerSets();
const auto &sets = Auth().data().stickerSets();
const auto &order = Auth().data().featuredStickerSetsOrder();
int unreadCount = 0;
for_const (auto setId, Auth().data().featuredStickerSetsOrder()) {
auto it = sets.constFind(setId);
if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
for (const auto setId : order) {
auto it = sets.find(setId);
if (it != sets.cend()
&& (it->second->flags & MTPDstickerSet_ClientFlag::f_unread)) {
++unreadCount;
}
}
@ -4033,9 +4036,9 @@ int32 countDocumentVectorHash(const QVector<DocumentData*> vector) {
int32 countSpecialStickerSetHash(uint64 setId) {
auto &sets = Auth().data().stickerSets();
auto it = sets.constFind(setId);
auto it = sets.find(setId);
if (it != sets.cend()) {
return countDocumentVectorHash(it->stickers);
return countDocumentVectorHash(it->second->stickers);
}
return 0;
}
@ -4043,16 +4046,17 @@ int32 countSpecialStickerSetHash(uint64 setId) {
int32 countStickersHash(bool checkOutdatedInfo) {
auto result = Api::HashInit();
bool foundOutdated = false;
auto &sets = Auth().data().stickerSets();
auto &order = Auth().data().stickerSetsOrder();
const auto &sets = Auth().data().stickerSets();
const auto &order = Auth().data().stickerSetsOrder();
for (auto i = order.cbegin(), e = order.cend(); i != e; ++i) {
auto j = sets.constFind(*i);
if (j != sets.cend()) {
if (j->id == Stickers::DefaultSetId) {
auto it = sets.find(*i);
if (it != sets.cend()) {
const auto set = it->second.get();
if (set->id == Stickers::DefaultSetId) {
foundOutdated = true;
} else if (!(j->flags & MTPDstickerSet_ClientFlag::f_special)
&& !(j->flags & MTPDstickerSet::Flag::f_archived)) {
Api::HashUpdate(result, j->hash);
} else if (!(set->flags & MTPDstickerSet_ClientFlag::f_special)
&& !(set->flags & MTPDstickerSet::Flag::f_archived)) {
Api::HashUpdate(result, set->hash);
}
}
}
@ -4076,8 +4080,9 @@ int32 countFeaturedStickersHash() {
for (const auto setId : featured) {
Api::HashUpdate(result, setId);
auto it = sets.constFind(setId);
if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
const auto it = sets.find(setId);
if (it != sets.cend()
&& (it->second->flags & MTPDstickerSet_ClientFlag::f_unread)) {
Api::HashUpdate(result, 1);
}
}

View File

@ -175,74 +175,6 @@ ImagePtr Create(const StorageImageLocation &location, int size) {
return Create<StorageSource>(location, size, QByteArray());
}
struct CreateSetThumbnail {
using Source = Stickers::ThumbnailSource;
ImagePtr operator()(
const StorageImageLocation &location,
int size) {
return Create<Source>(location, size, QByteArray());
}
ImagePtr operator()(
const StorageImageLocation &location,
const QByteArray &bytes) {
return Create<Source>(location, bytes.size(), bytes);
}
};
template <typename CreateLocation, typename Method>
ImagePtr CreateFromPhotoSize(
CreateLocation &&createLocation,
const MTPPhotoSize &size,
Method method = Method()) {
return size.match([&](const MTPDphotoSize &data) {
const auto &location = data.vlocation().c_fileLocationToBeDeprecated();
return method(
StorageImageLocation(
createLocation(data.vtype(), location),
data.vw().v,
data.vh().v),
data.vsize().v);
}, [&](const MTPDphotoCachedSize &data) {
const auto bytes = qba(data.vbytes());
const auto &location = data.vlocation().c_fileLocationToBeDeprecated();
return method(
StorageImageLocation(
createLocation(data.vtype(), location),
data.vw().v,
data.vh().v),
bytes);
}, [&](const MTPDphotoStrippedSize &data) {
auto image = FromInlineBytes(qba(data.vbytes()));
return !image.isNull()
? Images::Create(std::move(image), "JPG")
: ImagePtr();
}, [&](const MTPDphotoSizeEmpty &) {
return ImagePtr();
});
}
ImagePtr Create(const MTPDstickerSet &set, const MTPPhotoSize &size) {
const auto thumbDcId = set.vthumb_dc_id();
const auto create = [&](
const MTPstring &thumbSize,
const MTPDfileLocationToBeDeprecated &location) {
return StorageFileLocation(
thumbDcId->v,
Auth().userId(),
MTP_inputStickerSetThumb(
MTP_inputStickerSetID(set.vid(), set.vaccess_hash()),
location.vvolume_id(),
location.vlocal_id()));
};
return thumbDcId
? CreateFromPhotoSize(create, size, CreateSetThumbnail())
: ImagePtr();
}
ImagePtr CreateStickerSetThumbnail(const StorageImageLocation &location) {
return CreateSetThumbnail()(location, 0);
}
QSize GetSizeForDocument(const QVector<MTPDocumentAttribute> &attributes) {
for (const auto &attribute : attributes) {
if (attribute.type() == mtpc_documentAttributeImageSize) {

View File

@ -378,6 +378,10 @@ bool StorageFileLocation::valid() const {
return false;
}
bool StorageFileLocation::isLegacy() const {
return (_type == Type::Legacy);
}
bool StorageFileLocation::isDocumentThumbnail() const {
return (_type == Type::Document) && (_sizeLetter != 0);
}
@ -810,6 +814,12 @@ bool DownloadLocation::valid() const {
});
}
bool DownloadLocation::isLegacy() const {
return data.is<StorageFileLocation>()
? data.get_unchecked<StorageFileLocation>().isLegacy()
: false;
}
QByteArray DownloadLocation::fileReference() const {
if (!data.is<StorageFileLocation>()) {
return QByteArray();

View File

@ -83,6 +83,7 @@ public:
[[nodiscard]] Type type() const;
[[nodiscard]] bool valid() const;
[[nodiscard]] bool isLegacy() const;
[[nodiscard]] Storage::Cache::Key cacheKey() const;
[[nodiscard]] Storage::Cache::Key bigFileBaseCacheKey() const;
@ -184,6 +185,9 @@ public:
[[nodiscard]] bool valid() const {
return _file.valid();
}
[[nodiscard]] bool isLegacy() const {
return _file.isLegacy();
}
[[nodiscard]] QByteArray fileReference() const {
return _file.fileReference();
}
@ -413,6 +417,7 @@ public:
[[nodiscard]] Storage::Cache::Key cacheKey() const;
[[nodiscard]] bool valid() const;
[[nodiscard]] bool isLegacy() const;
[[nodiscard]] QByteArray fileReference() const;
bool refreshFileReference(const QByteArray &data);
bool refreshFileReference(const Data::UpdatedFileReferences &updates);
@ -472,6 +477,9 @@ public:
[[nodiscard]] bool valid() const {
return _file.valid();
}
[[nodiscard]] bool isLegacy() const {
return _file.isLegacy();
}
[[nodiscard]] QByteArray fileReference() const {
return _file.fileReference();
}

View File

@ -136,6 +136,68 @@ ImageWithLocation FromPhotoSize(
});
}
ImageWithLocation FromPhotoSize(
not_null<Main::Session*> session,
const MTPDstickerSet &set,
const MTPPhotoSize &size) {
if (!set.vthumb_dc_id()) {
return ImageWithLocation();
}
return size.match([&](const MTPDphotoSize &data) {
const auto &location = data.vlocation().c_fileLocationToBeDeprecated();
return ImageWithLocation{
.location = ImageLocation(
DownloadLocation{ StorageFileLocation(
set.vthumb_dc_id()->v,
session->userId(),
MTP_inputStickerSetThumb(
MTP_inputStickerSetID(set.vid(), set.vaccess_hash()),
location.vvolume_id(),
location.vlocal_id())) },
data.vw().v,
data.vh().v),
.bytesCount = data.vsize().v
};
}, [&](const MTPDphotoCachedSize &data) {
const auto &location = data.vlocation().c_fileLocationToBeDeprecated();
const auto bytes = qba(data.vbytes());
return ImageWithLocation{
.location = ImageLocation(
DownloadLocation{ StorageFileLocation(
set.vthumb_dc_id()->v,
session->userId(),
MTP_inputStickerSetThumb(
MTP_inputStickerSetID(set.vid(), set.vaccess_hash()),
location.vvolume_id(),
location.vlocal_id())) },
data.vw().v,
data.vh().v),
.bytesCount = bytes.size(),
.bytes = bytes
};
}, [&](const MTPDphotoStrippedSize &data) {
return ImageWithLocation();
//const auto bytes = ExpandInlineBytes(qba(data.vbytes()));
//return ImageWithLocation{
// .location = ImageLocation(
// DownloadLocation{ StorageFileLocation(
// document.vdc_id().v,
// session->userId(),
// MTP_inputDocumentFileLocation(
// document.vid(),
// document.vaccess_hash(),
// document.vfile_reference(),
// data.vtype())) },
// width, // ???
// height), // ???
// .bytesCount = bytes.size(),
// .bytes = bytes
//};
}, [&](const MTPDphotoSizeEmpty &) {
return ImageWithLocation();
});
}
ImageWithLocation FromImageInMemory(
const QImage &image,
const char *format) {

View File

@ -23,6 +23,10 @@ namespace Images {
not_null<Main::Session*> session,
const MTPDdocument &document,
const MTPPhotoSize &size);
[[nodiscard]] ImageWithLocation FromPhotoSize(
not_null<Main::Session*> session,
const MTPDstickerSet &set,
const MTPPhotoSize &size);
[[nodiscard]] ImageWithLocation FromVideoSize(
not_null<Main::Session*> session,
const MTPDdocument &document,

View File

@ -445,7 +445,7 @@ void EditorBlock::enumerateRows(Callback callback) const {
}
}
} else {
for_const (auto &row, _data) {
for (const auto &row : _data) {
if (!callback(row)) {
break;
}