Manage faved stickers from sticker context menu.

This commit is contained in:
John Preston 2017-08-02 22:57:49 +02:00
parent 134bc13169
commit 070456882e
13 changed files with 485 additions and 391 deletions

View File

@ -885,6 +885,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_recent_stickers" = "Frequently used";
"lng_faved_stickers" = "Favorite stickers";
"lng_faved_stickers_add" = "Add to Favorites";
"lng_faved_stickers_remove" = "Remove from Favorites";
"lng_switch_stickers" = "Stickers";
"lng_switch_emoji" = "Emoji";
"lng_switch_gifs" = "GIFs";

View File

@ -34,6 +34,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "window/themes/window_theme.h"
#include "window/notifications_manager.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/stickers.h"
namespace {
@ -1537,370 +1538,141 @@ void ApiWrap::stickersSaveOrder() {
void ApiWrap::updateStickers() {
auto now = getms(true);
if (!Global::LastStickersUpdate() || now >= Global::LastStickersUpdate() + kStickersUpdateTimeout) {
if (!_stickersUpdateRequest) {
_stickersUpdateRequest = request(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true)))).done([this](const MTPmessages_AllStickers &result) {
stickersGot(result);
}).fail([this](const RPCError &error) {
LOG(("App Fail: Failed to get stickers!"));
Global::SetLastStickersUpdate(getms(true));
_stickersUpdateRequest = 0;
}).send();
}
}
if (!Global::LastRecentStickersUpdate() || now >= Global::LastRecentStickersUpdate() + kStickersUpdateTimeout) {
if (!_recentStickersUpdateRequest) {
_recentStickersUpdateRequest = request(MTPmessages_GetRecentStickers(MTP_flags(0), MTP_int(Local::countRecentStickersHash()))).done([this](const MTPmessages_RecentStickers &result) {
recentStickersGot(result);
}).fail([this](const RPCError &error) {
LOG(("App Fail: Failed to get recent stickers!"));
Global::SetLastRecentStickersUpdate(getms(true));
_recentStickersUpdateRequest = 0;
}).send();
}
}
if (!Global::LastFavedStickersUpdate() || now >= Global::LastFavedStickersUpdate() + kStickersUpdateTimeout) {
if (!_favedStickersUpdateRequest) {
_favedStickersUpdateRequest = request(MTPmessages_GetFavedStickers(MTP_int(Local::countFavedStickersHash()))).done([this](const MTPmessages_FavedStickers &result) {
favedStickersGot(result);
}).fail([this](const RPCError &error) {
LOG(("App Fail: Failed to get faved stickers!"));
Global::SetLastFavedStickersUpdate(getms(true));
_favedStickersUpdateRequest = 0;
}).send();
}
}
if (!Global::LastFeaturedStickersUpdate() || now >= Global::LastFeaturedStickersUpdate() + kStickersUpdateTimeout) {
if (!_featuredStickersUpdateRequest) {
_featuredStickersUpdateRequest = request(MTPmessages_GetFeaturedStickers(MTP_int(Local::countFeaturedStickersHash()))).done([this](const MTPmessages_FeaturedStickers &result) {
featuredStickersGot(result);
}).fail([this](const RPCError &error) {
LOG(("App Fail: Failed to get featured stickers!"));
Global::SetLastFeaturedStickersUpdate(getms(true));
_featuredStickersUpdateRequest = 0;
}).send();
}
}
if (!cLastSavedGifsUpdate() || now >= cLastSavedGifsUpdate() + kStickersUpdateTimeout) {
if (!_savedGifsUpdateRequest) {
_savedGifsUpdateRequest = request(MTPmessages_GetSavedGifs(MTP_int(Local::countSavedGifsHash()))).done([this](const MTPmessages_SavedGifs &result) {
savedGifsGot(result);
}).fail([this](const RPCError &error) {
LOG(("App Fail: Failed to get saved gifs!"));
cSetLastSavedGifsUpdate(getms(true));
_savedGifsUpdateRequest = 0;
}).send();
}
}
requestStickers(now);
requestRecentStickers(now);
requestFavedStickers(now);
requestFeaturedStickers(now);
requestSavedGifs(now);
}
void ApiWrap::stickersGot(const MTPmessages_AllStickers &stickers) {
Global::SetLastStickersUpdate(getms(true));
_stickersUpdateRequest = 0;
if (stickers.type() != mtpc_messages_allStickers) return;
auto &d = stickers.c_messages_allStickers();
auto &d_sets = d.vsets.v;
auto &setsOrder = Global::RefStickerSetsOrder();
setsOrder.clear();
auto &sets = Global::RefStickerSets();
QMap<uint64, uint64> setsToRequest;
for (auto &set : sets) {
if (!(set.flags & MTPDstickerSet::Flag::f_archived)) {
set.flags &= ~MTPDstickerSet::Flag::f_installed; // mark for removing
}
void ApiWrap::requestStickers(TimeId now) {
if (Global::LastStickersUpdate() != 0 && now < Global::LastStickersUpdate() + kStickersUpdateTimeout) {
return;
}
for_const (auto &setData, d_sets) {
if (setData.type() == mtpc_stickerSet) {
auto set = Stickers::feedSet(setData.c_stickerSet());
if (!(set->flags & MTPDstickerSet::Flag::f_archived) || (set->flags & MTPDstickerSet::Flag::f_official)) {
setsOrder.push_back(set->id);
if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
setsToRequest.insert(set->id, set->access);
}
}
}
if (_stickersUpdateRequest) {
return;
}
bool writeRecent = false;
RecentStickerPack &recent(cGetRecentStickers());
for (Stickers::Sets::iterator it = sets.begin(), e = sets.end(); it != e;) {
bool installed = (it->flags & MTPDstickerSet::Flag::f_installed);
bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special);
bool archived = (it->flags & MTPDstickerSet::Flag::f_archived);
if (!installed) { // remove not mine sets from recent stickers
for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
auto onDone = [this](const MTPmessages_AllStickers &result) {
Global::SetLastStickersUpdate(getms(true));
_stickersUpdateRequest = 0;
switch (result.type()) {
case mtpc_messages_allStickersNotModified: return;
case mtpc_messages_allStickers: {
auto &d = result.c_messages_allStickers();
Stickers::SetsReceived(d.vsets.v, d.vhash.v);
} return;
default: Unexpected("Type in ApiWrap::stickersDone()");
}
if (installed || featured || special || archived) {
++it;
} else {
it = sets.erase(it);
}
}
if (Local::countStickersHash() != d.vhash.v) {
LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countStickersHash()));
}
if (!setsToRequest.isEmpty() && App::api()) {
for (QMap<uint64, uint64>::const_iterator i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
App::api()->scheduleStickerSetRequest(i.key(), i.value());
}
App::api()->requestStickerSets();
}
Local::writeInstalledStickers();
if (writeRecent) Local::writeUserSettings();
if (App::main()) emit App::main()->stickersUpdated();
};
_stickersUpdateRequest = request(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true)))).done(onDone).fail([this, onDone](const RPCError &error) {
LOG(("App Fail: Failed to get stickers!"));
onDone(MTP_messages_allStickersNotModified());
}).send();
}
void ApiWrap::recentStickersGot(const MTPmessages_RecentStickers &stickers) {
Global::SetLastRecentStickersUpdate(getms(true));
_recentStickersUpdateRequest = 0;
if (stickers.type() != mtpc_messages_recentStickers) return;
auto &d = stickers.c_messages_recentStickers();
insertSpecialStickersSet(Stickers::CloudRecentSetId, lang(lng_recent_stickers), d.vstickers, d.vhash);
if (Local::countRecentStickersHash() != d.vhash.v) {
LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countRecentStickersHash()));
void ApiWrap::requestRecentStickers(TimeId now) {
if (Global::LastRecentStickersUpdate() != 0 && now < Global::LastRecentStickersUpdate() + kStickersUpdateTimeout) {
return;
}
if (_recentStickersUpdateRequest) {
return;
}
auto onDone = [this](const MTPmessages_RecentStickers &result) {
Global::SetLastRecentStickersUpdate(getms(true));
_recentStickersUpdateRequest = 0;
Local::writeRecentStickers();
if (App::main()) emit App::main()->stickersUpdated();
switch (result.type()) {
case mtpc_messages_recentStickersNotModified: return;
case mtpc_messages_recentStickers: {
auto &d = result.c_messages_recentStickers();
Stickers::SpecialSetReceived(Stickers::CloudRecentSetId, lang(lng_recent_stickers), d.vstickers.v, d.vhash.v);
} return;
default: Unexpected("Type in ApiWrap::recentStickersDone()");
}
};
_recentStickersUpdateRequest = request(MTPmessages_GetRecentStickers(MTP_flags(0), MTP_int(Local::countRecentStickersHash()))).done(onDone).fail([this, onDone](const RPCError &error) {
LOG(("App Fail: Failed to get recent stickers!"));
onDone(MTP_messages_recentStickersNotModified());
}).send();
}
void ApiWrap::favedStickersGot(const MTPmessages_FavedStickers &stickers) {
Global::SetLastFavedStickersUpdate(getms(true));
_favedStickersUpdateRequest = 0;
if (stickers.type() != mtpc_messages_favedStickers) return;
auto &d = stickers.c_messages_favedStickers();
insertSpecialStickersSet(Stickers::FavedSetId, lang(lng_faved_stickers), d.vstickers, d.vhash);
if (Local::countRecentStickersHash() != d.vhash.v) {
LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countRecentStickersHash()));
void ApiWrap::requestFavedStickers(TimeId now) {
if (Global::LastFavedStickersUpdate() != 0 && now < Global::LastFavedStickersUpdate() + kStickersUpdateTimeout) {
return;
}
if (_favedStickersUpdateRequest) {
return;
}
auto onDone = [this](const MTPmessages_FavedStickers &result) {
Global::SetLastFavedStickersUpdate(getms(true));
_favedStickersUpdateRequest = 0;
Local::writeRecentStickers();
if (App::main()) emit App::main()->stickersUpdated();
switch (result.type()) {
case mtpc_messages_favedStickersNotModified: return;
case mtpc_messages_favedStickers: {
auto &d = result.c_messages_favedStickers();
Stickers::SpecialSetReceived(Stickers::FavedSetId, lang(lng_faved_stickers), d.vstickers.v, d.vhash.v);
} return;
default: Unexpected("Type in ApiWrap::favedStickersDone()");
}
};
_favedStickersUpdateRequest = request(MTPmessages_GetFavedStickers(MTP_int(Local::countFavedStickersHash()))).done(onDone).fail([this, onDone](const RPCError &error) {
LOG(("App Fail: Failed to get faved stickers!"));
onDone(MTP_messages_favedStickersNotModified());
}).send();
}
void ApiWrap::insertSpecialStickersSet(uint64 setId, const QString &setTitle, const MTPVector<MTPDocument> &items, MTPint hash) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(setId);
auto &d_docs = items.v;
if (d_docs.isEmpty()) {
if (it != sets.cend()) {
sets.erase(it);
}
} else {
if (it == sets.cend()) {
it = sets.insert(setId, Stickers::Set(Stickers::FavedSetId, 0, setTitle, QString(), 0, 0, qFlags(MTPDstickerSet_ClientFlag::f_special)));
} else {
it->title = setTitle;
}
it->hash = hash.v;
auto custom = sets.find(Stickers::CustomSetId);
auto pack = StickerPack();
pack.reserve(d_docs.size());
for_const (auto &mtpDocument, d_docs) {
auto document = App::feedDocument(mtpDocument);
if (!document || !document->sticker()) continue;
pack.push_back(document);
if (custom != sets.cend()) {
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();
}
auto writeRecent = false;
auto &recent = cGetRecentStickers();
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0 && pack.indexOf(i->first) < 0) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
if (pack.isEmpty()) {
sets.erase(it);
} else {
it->stickers = pack;
it->emoji.clear();
}
if (writeRecent) {
Local::writeUserSettings();
}
void ApiWrap::requestFeaturedStickers(TimeId now) {
if (Global::LastFeaturedStickersUpdate() != 0 && now < Global::LastFeaturedStickersUpdate() + kStickersUpdateTimeout) {
return;
}
if (_featuredStickersUpdateRequest) {
return;
}
auto onDone = [this](const MTPmessages_FeaturedStickers &result) {
Global::SetLastFeaturedStickersUpdate(getms(true));
_featuredStickersUpdateRequest = 0;
switch (result.type()) {
case mtpc_messages_featuredStickersNotModified: return;
case mtpc_messages_featuredStickers: {
auto &d = result.c_messages_featuredStickers();
Stickers::FeaturedSetsReceived(d.vsets.v, d.vunread.v, d.vhash.v);
} return;
default: Unexpected("Type in ApiWrap::featuredStickersDone()");
}
};
_featuredStickersUpdateRequest = request(MTPmessages_GetFeaturedStickers(MTP_int(Local::countFeaturedStickersHash()))).done(onDone).fail([this, onDone](const RPCError &error) {
LOG(("App Fail: Failed to get featured stickers!"));
onDone(MTP_messages_featuredStickersNotModified());
}).send();
}
void ApiWrap::featuredStickersGot(const MTPmessages_FeaturedStickers &stickers) {
Global::SetLastFeaturedStickersUpdate(getms(true));
_featuredStickersUpdateRequest = 0;
if (stickers.type() != mtpc_messages_featuredStickers) return;
auto &d = stickers.c_messages_featuredStickers();
OrderedSet<uint64> unread;
for_const (auto &unreadSetId, d.vunread.v) {
unread.insert(unreadSetId.v);
void ApiWrap::requestSavedGifs(TimeId now) {
if (cLastSavedGifsUpdate() != 0 && now < cLastSavedGifsUpdate() + kStickersUpdateTimeout) {
return;
}
auto &d_sets = d.vsets.v;
auto &setsOrder = Global::RefFeaturedStickerSetsOrder();
setsOrder.clear();
auto &sets = Global::RefStickerSets();
QMap<uint64, uint64> setsToRequest;
for (auto &set : sets) {
set.flags &= ~MTPDstickerSet_ClientFlag::f_featured; // mark for removing
if (_savedGifsUpdateRequest) {
return;
}
for (int i = 0, l = d_sets.size(); i != l; ++i) {
auto &setData = d_sets[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();
}
} break;
case mtpc_stickerSetMultiCovered: {
auto &d = setData.c_stickerSetMultiCovered();
if (d.vset.type() == mtpc_stickerSet) {
set = &d.vset.c_stickerSet();
}
} break;
auto onDone = [this](const MTPmessages_SavedGifs &result) {
cSetLastSavedGifsUpdate(getms(true));
_savedGifsUpdateRequest = 0;
switch (result.type()) {
case mtpc_messages_savedGifsNotModified: return;
case mtpc_messages_savedGifs: {
auto &d = result.c_messages_savedGifs();
Stickers::GifsReceived(d.vgifs.v, d.vhash.v);
} return;
default: Unexpected("Type in ApiWrap::savedGifsDone()");
}
if (set) {
auto it = sets.find(set->vid.v);
auto title = stickerSetTitle(*set);
if (it == sets.cend()) {
auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded;
if (unread.contains(set->vid.v)) {
setClientFlags |= MTPDstickerSet_ClientFlag::f_unread;
}
it = sets.insert(set->vid.v, Stickers::Set(set->vid.v, set->vaccess_hash.v, title, qs(set->vshort_name), set->vcount.v, set->vhash.v, set->vflags.v | setClientFlags));
} 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;
if (unread.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
}
}
setsOrder.push_back(set->vid.v);
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
setsToRequest.insert(set->vid.v, set->vaccess_hash.v);
}
}
}
int unreadCount = 0;
for (auto it = sets.begin(), e = sets.end(); it != e;) {
bool installed = (it->flags & MTPDstickerSet::Flag::f_installed);
bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special);
bool archived = (it->flags & MTPDstickerSet::Flag::f_archived);
if (installed || featured || special || archived) {
if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
++unreadCount;
}
++it;
} else {
it = sets.erase(it);
}
}
if (Global::FeaturedStickerSetsUnreadCount() != unreadCount) {
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
}
if (Local::countFeaturedStickersHash() != d.vhash.v) {
LOG(("API Error: received featured stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countFeaturedStickersHash()));
}
if (!setsToRequest.isEmpty() && App::api()) {
for (QMap<uint64, uint64>::const_iterator i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
App::api()->scheduleStickerSetRequest(i.key(), i.value());
}
App::api()->requestStickerSets();
}
Local::writeFeaturedStickers();
if (App::main()) emit App::main()->stickersUpdated();
}
void ApiWrap::savedGifsGot(const MTPmessages_SavedGifs &gifs) {
cSetLastSavedGifsUpdate(getms(true));
_savedGifsUpdateRequest = 0;
if (gifs.type() != mtpc_messages_savedGifs) return;
auto &d = gifs.c_messages_savedGifs();
auto &gifsList = d.vgifs.v;
auto &saved = cRefSavedGifs();
saved.clear();
saved.reserve(gifsList.size());
for (auto &gif : gifsList) {
auto document = App::feedDocument(gif);
if (!document || !document->isGifv()) {
LOG(("API Error: bad document returned in HistoryWidget::savedGifsGot!"));
continue;
}
saved.push_back(document);
}
if (Local::countSavedGifsHash() != d.vhash.v) {
LOG(("API Error: received saved gifs hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countSavedGifsHash()));
}
Local::writeSavedGifs();
AuthSession::Current().data().savedGifsUpdated().notify();
};
_savedGifsUpdateRequest = request(MTPmessages_GetSavedGifs(MTP_int(Local::countSavedGifsHash()))).done(onDone).fail([this, onDone](const RPCError &error) {
LOG(("App Fail: Failed to get saved gifs!"));
onDone(MTP_messages_savedGifsNotModified());
}).send();
}
void ApiWrap::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {

View File

@ -132,12 +132,11 @@ private:
void stickerSetDisenabled(mtpRequestId requestId);
void stickersSaveOrder();
void stickersGot(const MTPmessages_AllStickers &stickers);
void recentStickersGot(const MTPmessages_RecentStickers &stickers);
void favedStickersGot(const MTPmessages_FavedStickers &stickers);
void featuredStickersGot(const MTPmessages_FeaturedStickers &stickers);
void savedGifsGot(const MTPmessages_SavedGifs &gifs);
void insertSpecialStickersSet(uint64 setId, const QString &setTitle, const MTPVector<MTPDocument> &items, MTPint hash);
void requestStickers(TimeId now);
void requestRecentStickers(TimeId now);
void requestFavedStickers(TimeId now);
void requestFeaturedStickers(TimeId now);
void requestSavedGifs(TimeId now);
gsl::not_null<AuthSession*> _session;
mtpRequestId _changelogSubscription = 0;

View File

@ -248,7 +248,7 @@ void StickerSetBox::Inner::installDone(const MTPmessages_StickerSetInstallResult
}
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
Stickers::ApplyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
} else {
if (wasArchived) {
Local::writeArchivedStickers();

View File

@ -191,7 +191,7 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti
}
if (!setData) continue;
if (auto set = Stickers::feedSet(*setData)) {
if (auto set = Stickers::FeedSet(*setData)) {
auto index = archived.indexOf(set->id);
if (archived.isEmpty() || index != archived.size() - 1) {
changedSets = true;
@ -452,13 +452,13 @@ void StickersBox::installSet(uint64 setId) {
if (!(it->flags & MTPDstickerSet::Flag::f_installed) || (it->flags & MTPDstickerSet::Flag::f_archived)) {
MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), rpcDone(&StickersBox::installDone), rpcFail(&StickersBox::installFail, setId));
Stickers::installLocally(setId);
Stickers::InstallLocally(setId);
}
}
void StickersBox::installDone(const MTPmessages_StickerSetInstallResult &result) {
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
Stickers::ApplyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
}
}
@ -472,7 +472,7 @@ bool StickersBox::installFail(uint64 setId, const RPCError &error) {
return true;
}
Stickers::undoInstallLocally(setId);
Stickers::UndoInstallLocally(setId);
return true;
}
@ -1350,7 +1350,7 @@ void StickersBox::Inner::readVisibleSets() {
continue;
}
if (!_rows[i]->sticker || _rows[i]->sticker->thumb->loaded() || _rows[i]->sticker->loaded()) {
Stickers::markFeaturedAsRead(_rows[i]->id);
Stickers::MarkFeaturedAsRead(_rows[i]->id);
}
}
}

View File

@ -38,10 +38,10 @@ QPointer<internal::FeaturedReader> FeaturedReaderInstance;
} // namespace
void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
void ApplyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
auto &v = d.vsets.v;
auto &order = Global::RefStickerSetsOrder();
Stickers::Order archived;
Order archived;
archived.reserve(v.size());
QMap<uint64, uint64> setsToRequest;
for_const (auto &stickerSet, v) {
@ -61,7 +61,7 @@ void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
} break;
}
if (setData) {
auto set = Stickers::feedSet(*setData);
auto set = FeedSet(*setData);
if (set->stickers.isEmpty()) {
setsToRequest.insert(set->id, set->access);
}
@ -92,7 +92,7 @@ void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
}
// For testing: Just apply random subset or your sticker sets as archived.
bool applyArchivedResultFake() {
bool ApplyArchivedResultFake() {
auto sets = QVector<MTPStickerSetCovered>();
for (auto &set : Global::RefStickerSets()) {
if ((set.flags & MTPDstickerSet::Flag::f_installed) && !(set.flags & MTPDstickerSet_ClientFlag::f_special)) {
@ -104,11 +104,11 @@ bool applyArchivedResultFake() {
}
if (sets.size() > 3) sets = sets.mid(0, 3);
auto fakeResult = MTP_messages_stickerSetInstallResultArchive(MTP_vector<MTPStickerSetCovered>(sets));
applyArchivedResult(fakeResult.c_messages_stickerSetInstallResultArchive());
ApplyArchivedResult(fakeResult.c_messages_stickerSetInstallResultArchive());
return true;
}
void installLocally(uint64 setId) {
void InstallLocally(uint64 setId) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(setId);
if (it == sets.end()) {
@ -129,7 +129,7 @@ void installLocally(uint64 setId) {
order.insert(insertAtIndex, setId);
}
auto custom = sets.find(Stickers::CustomSetId);
auto custom = sets.find(CustomSetId);
if (custom != sets.cend()) {
for_const (auto sticker, it->stickers) {
int removeIndex = custom->stickers.indexOf(sticker);
@ -151,7 +151,7 @@ void installLocally(uint64 setId) {
emit App::main()->stickersUpdated();
}
void undoInstallLocally(uint64 setId) {
void UndoInstallLocally(uint64 setId) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(setId);
if (it == sets.end()) {
@ -172,7 +172,7 @@ void undoInstallLocally(uint64 setId) {
Ui::show(Box<InformBox>(lang(lng_stickers_not_found)), KeepOtherLayers);
}
void markFeaturedAsRead(uint64 setId) {
void MarkFeaturedAsRead(uint64 setId) {
if (!FeaturedReaderInstance) {
if (auto main = App::main()) {
FeaturedReaderInstance = object_ptr<internal::FeaturedReader>(main);
@ -183,6 +183,315 @@ void markFeaturedAsRead(uint64 setId) {
FeaturedReaderInstance->scheduleRead(setId);
}
bool IsFaved(DocumentData *document) {
auto it = Global::StickerSets().constFind(FavedSetId);
return (it != Global::StickerSets().cend()) && it->stickers.contains(document);
}
void SetFaved(DocumentData *document, bool faved) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(FavedSetId);
if (faved) {
if (it == sets.end()) {
it = sets.insert(FavedSetId, Set(FavedSetId, 0, lang(lng_faved_stickers), QString(), 0, 0, qFlags(MTPDstickerSet_ClientFlag::f_special)));
}
auto index = it->stickers.indexOf(document);
if (index != 0) {
if (index > 0) {
// Push this sticker to the front.
while (index-- != 0) {
it->stickers[index + 1] = it->stickers[index];
}
it->stickers[0] = document;
} else {
it->stickers.push_front(document);
}
Local::writeFavedStickers();
emit App::main()->stickersUpdated();
App::main()->onStickersInstalled(FavedSetId);
}
} else if (it != sets.end()) {
auto index = it->stickers.indexOf(document);
if (index >= 0) {
it->stickers.removeAt(index);
if (it->stickers.empty()) {
sets.erase(it);
}
Local::writeFavedStickers();
emit App::main()->stickersUpdated();
}
}
}
void SetsReceived(const QVector<MTPStickerSet> &data, int32 hash) {
auto &setsOrder = Global::RefStickerSetsOrder();
setsOrder.clear();
auto &sets = Global::RefStickerSets();
QMap<uint64, uint64> setsToRequest;
for (auto &set : sets) {
if (!(set.flags & MTPDstickerSet::Flag::f_archived)) {
set.flags &= ~MTPDstickerSet::Flag::f_installed; // mark for removing
}
}
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)) {
setsOrder.push_back(set->id);
if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
setsToRequest.insert(set->id, set->access);
}
}
}
}
auto writeRecent = false;
auto &recent = cGetRecentStickers();
for (auto it = sets.begin(), e = sets.end(); it != e;) {
bool installed = (it->flags & MTPDstickerSet::Flag::f_installed);
bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special);
bool archived = (it->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) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
}
if (installed || featured || special || archived) {
++it;
} else {
it = sets.erase(it);
}
}
if (!setsToRequest.isEmpty()) {
auto &api = AuthSession::Current().api();
for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
api.scheduleStickerSetRequest(i.key(), i.value());
}
api.requestStickerSets();
}
Local::writeInstalledStickers();
if (writeRecent) Local::writeUserSettings();
if (Local::countStickersHash() != hash) {
LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(hash).arg(Local::countStickersHash()));
}
if (App::main()) emit App::main()->stickersUpdated();
}
void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVector<MTPDocument> &items, int32 hash) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(setId);
auto &d_docs = items;
if (d_docs.isEmpty()) {
if (it != sets.cend()) {
sets.erase(it);
}
} else {
if (it == sets.cend()) {
it = sets.insert(setId, Set(setId, 0, setTitle, QString(), 0, 0, qFlags(MTPDstickerSet_ClientFlag::f_special)));
} else {
it->title = setTitle;
}
it->hash = hash;
auto custom = sets.find(CustomSetId);
auto pack = StickerPack();
pack.reserve(d_docs.size());
for_const (auto &mtpDocument, d_docs) {
auto document = App::feedDocument(mtpDocument);
if (!document || !document->sticker()) continue;
pack.push_back(document);
if (custom != sets.cend()) {
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();
}
auto writeRecent = false;
auto &recent = cGetRecentStickers();
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0 && pack.indexOf(i->first) < 0) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
if (pack.isEmpty()) {
sets.erase(it);
} else {
it->stickers = pack;
it->emoji.clear();
}
if (writeRecent) {
Local::writeUserSettings();
}
}
switch (setId) {
case CloudRecentSetId: {
if (Local::countRecentStickersHash() != hash) {
LOG(("API Error: received recent stickers hash %1 while counted hash is %2").arg(hash).arg(Local::countRecentStickersHash()));
}
Local::writeRecentStickers();
} break;
case FavedSetId: {
if (Local::countFavedStickersHash() != hash) {
LOG(("API Error: received faved stickers hash %1 while counted hash is %2").arg(hash).arg(Local::countFavedStickersHash()));
}
Local::writeFavedStickers();
} break;
default: Unexpected("setId in SpecialSetReceived()");
}
if (App::main()) emit App::main()->stickersUpdated();
}
void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVector<MTPlong> &unread, int32 hash) {
OrderedSet<uint64> unreadMap;
for_const (auto &unreadSetId, unread) {
unreadMap.insert(unreadSetId.v);
}
auto &setsOrder = Global::RefFeaturedStickerSetsOrder();
setsOrder.clear();
auto &sets = Global::RefStickerSets();
QMap<uint64, uint64> setsToRequest;
for (auto &set : sets) {
set.flags &= ~MTPDstickerSet_ClientFlag::f_featured; // mark for removing
}
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();
}
} 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);
auto title = stickerSetTitle(*set);
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));
} 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;
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
}
}
setsOrder.push_back(set->vid.v);
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
setsToRequest.insert(set->vid.v, set->vaccess_hash.v);
}
}
}
auto unreadCount = 0;
for (auto it = sets.begin(), e = sets.end(); it != e;) {
bool installed = (it->flags & MTPDstickerSet::Flag::f_installed);
bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special);
bool archived = (it->flags & MTPDstickerSet::Flag::f_archived);
if (installed || featured || special || archived) {
if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
++unreadCount;
}
++it;
} else {
it = sets.erase(it);
}
}
if (Global::FeaturedStickerSetsUnreadCount() != unreadCount) {
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
}
if (Local::countFeaturedStickersHash() != hash) {
LOG(("API Error: received featured stickers hash %1 while counted hash is %2").arg(hash).arg(Local::countFeaturedStickersHash()));
}
if (!setsToRequest.isEmpty()) {
auto &api = AuthSession::Current().api();
for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) {
api.scheduleStickerSetRequest(i.key(), i.value());
}
api.requestStickerSets();
}
Local::writeFeaturedStickers();
if (App::main()) emit App::main()->stickersUpdated();
}
void GifsReceived(const QVector<MTPDocument> &items, int32 hash) {
auto &saved = cRefSavedGifs();
saved.clear();
saved.reserve(items.size());
for_const (auto &gif, items) {
auto document = App::feedDocument(gif);
if (!document || !document->isGifv()) {
LOG(("API Error: bad document returned in HistoryWidget::savedGifsGot!"));
continue;
}
saved.push_back(document);
}
if (Local::countSavedGifsHash() != hash) {
LOG(("API Error: received saved gifs hash %1 while counted hash is %2").arg(hash).arg(Local::countSavedGifsHash()));
}
Local::writeSavedGifs();
AuthSession::Current().data().savedGifsUpdated().notify();
}
namespace internal {
FeaturedReader::FeaturedReader(QObject *parent) : QObject(parent)

View File

@ -26,11 +26,18 @@ namespace Stickers {
constexpr auto kPanelPerRow = 5;
void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d);
bool applyArchivedResultFake(); // For testing.
void installLocally(uint64 setId);
void undoInstallLocally(uint64 setId);
void markFeaturedAsRead(uint64 setId);
void ApplyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d);
bool ApplyArchivedResultFake(); // For testing.
void InstallLocally(uint64 setId);
void UndoInstallLocally(uint64 setId);
void MarkFeaturedAsRead(uint64 setId);
bool IsFaved(DocumentData *document);
void SetFaved(DocumentData *document, bool faved);
void SetsReceived(const QVector<MTPStickerSet> &data, int32 hash);
void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVector<MTPDocument> &items, int32 hash);
void FeaturedSetsReceived(const QVector<MTPStickerSetCovered> &data, const QVector<MTPlong> &unread, int32 hash);
void GifsReceived(const QVector<MTPDocument> &items, int32 hash);
namespace internal {

View File

@ -487,7 +487,7 @@ void StickersListWidget::readVisibleSets() {
}
}
if (loaded == count) {
Stickers::markFeaturedAsRead(set.id);
Stickers::MarkFeaturedAsRead(set.id);
}
}
}
@ -504,7 +504,7 @@ bool StickersListWidget::enumerateSections(Callback callback) const {
info.section = i;
info.count = _mySets[i].pack.size();
info.rowsCount = (info.count / kStickersPanelPerRow) + ((info.count % kStickersPanelPerRow) ? 1 : 0);
info.rowsTop = info.top + ((_mySets[i].flags & MTPDstickerSet_ClientFlag::f_special) ? st::stickerPanPadding : st::emojiPanHeader);
info.rowsTop = info.top + ((_mySets[i].id == Stickers::RecentSetId) ? st::stickerPanPadding : st::emojiPanHeader);
info.rowsBottom = info.rowsTop + info.rowsCount * st::stickerPanSize.height();
if (!callback(info)) {
return false;
@ -717,7 +717,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
return false;
}
auto &set = _mySets[info.section];
if (!(set.flags & MTPDstickerSet_ClientFlag::f_special) && clip.top() < info.rowsTop) {
if (set.id != Stickers::RecentSetId && clip.top() < info.rowsTop) {
auto titleText = set.title;
auto titleWidth = st::stickersTrendingHeaderFont->width(titleText);
auto widthForTitle = stickersRight() - (st::emojiPanHeaderLeft - st::buttonRadius);
@ -1177,7 +1177,7 @@ void StickersListWidget::refreshRecentStickers(bool performResize) {
void StickersListWidget::refreshFavedStickers() {
clearSelection();
auto &sets = Global::StickerSets();
auto it = sets.constFind(Stickers::CloudRecentSetId);
auto it = sets.constFind(Stickers::FavedSetId);
if (it == sets.cend() || it->stickers.isEmpty()) {
return;
}
@ -1407,15 +1407,15 @@ void StickersListWidget::installSet(quint64 setId) {
if (it != sets.cend()) {
request(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_bool(false))).done([this](const MTPmessages_StickerSetInstallResult &result) {
if (result.type() == mtpc_messages_stickerSetInstallResultArchive) {
Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
Stickers::ApplyArchivedResult(result.c_messages_stickerSetInstallResultArchive());
}
}).fail([this, setId](const RPCError &error) {
notInstalledLocally(setId);
Stickers::undoInstallLocally(setId);
Stickers::UndoInstallLocally(setId);
}).send();
installedLocally(setId);
Stickers::installLocally(setId);
Stickers::InstallLocally(setId);
}
}

View File

@ -537,7 +537,7 @@ DefineVar(Sandbox, ProxyData, PreLaunchProxy);
namespace Stickers {
Set *feedSet(const MTPDstickerSet &set) {
Set *FeedSet(const MTPDstickerSet &set) {
MTPDstickerSet::Flags flags = 0;
auto &sets = Global::RefStickerSets();

View File

@ -278,7 +278,7 @@ inline MTPInputStickerSet inputSetId(const Set &set) {
return MTP_inputStickerSetShortName(MTP_string(set.shortName));
}
Set *feedSet(const MTPDstickerSet &set);
Set *FeedSet(const MTPDstickerSet &set);
} // namespace Stickers

View File

@ -28,6 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/popup_menu.h"
#include "window/window_controller.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/stickers.h"
#include "history/history_widget.h"
#include "mainwindow.h"
#include "mainwidget.h"
@ -1291,7 +1292,8 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (media->type() == MediaTypeSticker) {
if (auto document = media->getDocument()) {
if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) {
_menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [this] { showStickerPackInfo(); });
_menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [this, document] { showStickerPackInfo(document); });
_menu->addAction(lang(Stickers::IsFaved(document) ? lng_faved_stickers_remove : lng_faved_stickers_add), [this, document] { toggleFavedSticker(document); });
}
_menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
@ -1410,20 +1412,21 @@ void HistoryInner::copyContextImage(PhotoData *photo) {
QApplication::clipboard()->setPixmap(photo->full->pix());
}
void HistoryInner::showStickerPackInfo() {
if (!App::contextItem()) return;
if (auto media = App::contextItem()->getMedia()) {
if (auto doc = media->getDocument()) {
if (auto sticker = doc->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
App::main()->stickersBox(sticker->set);
}
}
void HistoryInner::showStickerPackInfo(DocumentData *document) {
if (auto sticker = document->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
App::main()->stickersBox(sticker->set);
}
}
}
void HistoryInner::toggleFavedSticker(DocumentData *document) {
auto unfave = Stickers::IsFaved(document);
MTP::send(MTPmessages_FaveSticker(document->mtpInput(), MTP_bool(unfave)), rpcDone([document, unfave](const MTPBool &result) {
Stickers::SetFaved(document, !unfave);
}));
}
void HistoryInner::cancelContextDownload() {
if (auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.data())) {
lnkDocument->document()->cancel();

View File

@ -145,7 +145,8 @@ private:
void savePhotoToFile(PhotoData *photo);
void saveDocumentToFile(DocumentData *document);
void copyContextImage(PhotoData *photo);
void showStickerPackInfo();
void showStickerPackInfo(DocumentData *document);
void toggleFavedSticker(DocumentData *document);
void touchResetSpeed();
void touchUpdateSpeed();

View File

@ -1374,7 +1374,7 @@ bool StickerData::setInstalled() const {
return (it != Global::StickerSets().cend()) && !(it->flags & MTPDstickerSet::Flag::f_archived) && (it->flags & MTPDstickerSet::Flag::f_installed);
} break;
case mtpc_inputStickerSetShortName: {
QString name = qs(set.c_inputStickerSetShortName().vshort_name).toLower();
auto name = qs(set.c_inputStickerSetShortName().vshort_name).toLower();
for (auto it = Global::StickerSets().cbegin(), e = Global::StickerSets().cend(); it != e; ++it) {
if (it->shortName.toLower() == name) {
return !(it->flags & MTPDstickerSet::Flag::f_archived) && (it->flags & MTPDstickerSet::Flag::f_installed);