From 991c6ddd99b4be84c62d1fc6f10e2fbf7924ecb9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 27 Jun 2016 19:25:21 +0300 Subject: [PATCH 01/13] Saving featured stickers for new 0.9.57 version in local storage. --- Telegram/Resources/winrc/Telegram.rc | 8 +- Telegram/Resources/winrc/Updater.rc | 8 +- Telegram/SourceFiles/apiwrap.cpp | 6 +- Telegram/SourceFiles/boxes/stickersetbox.cpp | 39 ++- Telegram/SourceFiles/boxes/stickersetbox.h | 16 +- Telegram/SourceFiles/core/version.h | 6 +- Telegram/SourceFiles/dropdown.cpp | 15 +- Telegram/SourceFiles/facades.cpp | 6 + Telegram/SourceFiles/facades.h | 13 +- Telegram/SourceFiles/history.cpp | 4 +- .../history/field_autocomplete.cpp | 4 +- Telegram/SourceFiles/historywidget.cpp | 124 ++++++++- Telegram/SourceFiles/historywidget.h | 4 + Telegram/SourceFiles/localstorage.cpp | 99 ++++++-- Telegram/SourceFiles/localstorage.h | 1 + Telegram/SourceFiles/mainwidget.cpp | 18 +- Telegram/SourceFiles/mtproto/core_types.h | 5 +- Telegram/SourceFiles/mtproto/scheme.tl | 12 +- Telegram/SourceFiles/mtproto/scheme_auto.cpp | 55 +++- Telegram/SourceFiles/mtproto/scheme_auto.h | 237 ++++++++++++++++-- Telegram/SourceFiles/structs.cpp | 4 +- Telegram/SourceFiles/ui/text/text.h | 2 +- Telegram/Telegram.xcodeproj/project.pbxproj | 4 +- Telegram/build/version | 8 +- 24 files changed, 578 insertions(+), 120 deletions(-) diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index b3f7cf3e28..a04176115f 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,56,0 - PRODUCTVERSION 0,9,56,0 + FILEVERSION 0,9,57,0 + PRODUCTVERSION 0,9,57,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.9.56.0" + VALUE "FileVersion", "0.9.57.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.56.0" + VALUE "ProductVersion", "0.9.57.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 1cdd13d516..edc6944fb6 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,56,0 - PRODUCTVERSION 0,9,56,0 + FILEVERSION 0,9,57,0 + PRODUCTVERSION 0,9,57,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,10 +43,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Updater" - VALUE "FileVersion", "0.9.56.0" + VALUE "FileVersion", "0.9.57.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.56.0" + VALUE "ProductVersion", "0.9.57.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 0a13d6be23..e0dc511359 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -929,7 +929,7 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) if (d.vset.type() != mtpc_stickerSet) return; const auto &s(d.vset.c_stickerSet()); - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); auto it = sets.find(setId); if (it == sets.cend()) return; @@ -937,7 +937,9 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) it->hash = s.vhash.v; it->shortName = qs(s.vshort_name); it->title = stickerSetTitle(s); - it->flags = s.vflags.v; + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded); + it->flags = s.vflags.v | clientFlags; + it->flags &= ~MTPDstickerSet_ClientFlag::f_not_loaded; const auto &d_docs(d.vdocuments.c_vector().v); auto custom = sets.find(Stickers::CustomSetId); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 10ad1a6ecf..0f23423d58 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -30,16 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget() -, _loaded(false) -, _setId(0) -, _setAccess(0) -, _setCount(0) -, _setHash(0) -, _setFlags(0) -, _bottom(0) -, _input(set) -, _installRequest(0) -, _previewShown(-1) { +, _input(set) { connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); switch (set.type()) { case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break; @@ -117,17 +108,20 @@ bool StickerSetInner::failedSet(const RPCError &error) { } void StickerSetInner::installDone(const MTPBool &result) { - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); _setFlags &= ~MTPDstickerSet::Flag::f_disabled; + _setFlags |= MTPDstickerSet::Flag::f_installed; auto it = sets.find(_setId); if (it == sets.cend()) { it = sets.insert(_setId, Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)); + } else { + it.value().flags = _setFlags; } it.value().stickers = _pack; it.value().emoji = _emoji; - Stickers::Order &order(Global::RefStickerSetsOrder()); + auto &order = Global::RefStickerSetsOrder(); int32 insertAtIndex = 0, currentIndex = order.indexOf(_setId); if (currentIndex != insertAtIndex) { if (currentIndex > 0) { @@ -257,7 +251,7 @@ bool StickerSetInner::loaded() const { int32 StickerSetInner::notInstalled() const { if (!_loaded) return 0; auto it = Global::StickerSets().constFind(_setId); - if (it == Global::StickerSets().cend() || (it->flags & MTPDstickerSet::Flag::f_disabled)) return _pack.size(); + if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_installed) || (it->flags & MTPDstickerSet::Flag::f_disabled)) return _pack.size(); return 0; } @@ -682,10 +676,10 @@ void StickersInner::rebuild() { int32 namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x() - qMax(qMax(_returnWidth, _removeWidth), _restoreWidth); clear(); - const Stickers::Order &order(Global::StickerSetsOrder()); + auto &order = Global::StickerSetsOrder(); _animStartTimes.reserve(order.size()); - const Stickers::Sets &sets(Global::StickerSets()); + auto &sets = Global::StickerSets(); for (int i = 0, l = order.size(); i < l; ++i) { auto it = sets.constFind(order.at(i)); if (it != sets.cend()) { @@ -913,7 +907,7 @@ void StickersBox::onSave() { bool writeRecent = false; RecentStickerPack &recent(cGetRecentStickers()); - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); QVector reorder = _inner.getOrder(), disabled = _inner.getDisabledSets(); for (int32 i = 0, l = disabled.size(); i < l; ++i) { @@ -936,7 +930,9 @@ void StickersBox::onSave() { _disenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); int removeIndex = Global::StickerSetsOrder().indexOf(it->id); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); - sets.erase(it); + if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)) { + sets.erase(it); + } } } } @@ -955,7 +951,10 @@ void StickersBox::onSave() { } } for (auto it = sets.begin(); it != sets.cend();) { - if (it->id == Stickers::CustomSetId || it->id == Stickers::RecentSetId || order.contains(it->id)) { + if (it->id == Stickers::CustomSetId + || it->id == Stickers::RecentSetId + || (it->flags & MTPDstickerSet_ClientFlag::f_featured) + || order.contains(it->id)) { ++it; } else { it = sets.erase(it); @@ -991,8 +990,8 @@ void StickersBox::showAll() { int32 stickerPacksCount(bool includeDisabledOfficial) { int32 result = 0; - const Stickers::Order &order(Global::StickerSetsOrder()); - const Stickers::Sets &sets(Global::StickerSets()); + auto &order = Global::StickerSetsOrder(); + auto &sets = Global::StickerSets(); for (int i = 0, l = order.size(); i < l; ++i) { auto it = sets.constFind(order.at(i)); if (it != sets.cend()) { diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index fc2c9a5138..9b6cd98918 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -67,19 +67,21 @@ private: StickerPack _pack; StickersByEmojiMap _emoji; - bool _loaded; - uint64 _setId, _setAccess; + bool _loaded = false; + uint64 _setId = 0; + uint64 _setAccess = 0; QString _title, _setTitle, _setShortName; - int32 _setCount, _setHash; - MTPDstickerSet::Flags _setFlags; + int32 _setCount = 0; + int32 _setHash = 0; + MTPDstickerSet::Flags _setFlags = 0; - int32 _bottom; + int32 _bottom = 0; MTPInputStickerSet _input; - mtpRequestId _installRequest; + mtpRequestId _installRequest = 0; QTimer _previewTimer; - int32 _previewShown; + int32 _previewShown = -1; }; class StickerSetBox : public ScrollableBox, public RPCSender { diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 68d7dbbd05..7e443e7811 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #define BETA_VERSION_MACRO (0ULL) -constexpr int AppVersion = 9056; -constexpr str_const AppVersionStr = "0.9.56"; -constexpr bool AppAlphaVersion = false; +constexpr int AppVersion = 9057; +constexpr str_const AppVersionStr = "0.9.57"; +constexpr bool AppAlphaVersion = true; constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index d862a660dc..d4db768d28 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -1508,7 +1508,7 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) { break; } } - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); auto it = sets.find(Stickers::CustomSetId); if (it != sets.cend()) { for (int32 i = 0, l = it->stickers.size(); i < l; ++i) { @@ -1628,8 +1628,8 @@ void StickerPanInner::hideFinish(bool completely) { void StickerPanInner::refreshStickers() { clearSelection(true); - const Stickers::Sets &sets(Global::StickerSets()); - _sets.clear(); _sets.reserve(sets.size() + 1); + _sets.clear(); + _sets.reserve(Global::StickerSetsOrder().size() + 1); refreshRecentStickers(false); for (auto i = Global::StickerSetsOrder().cbegin(), e = Global::StickerSetsOrder().cend(); i != e; ++i) { @@ -2085,7 +2085,7 @@ bool StickerPanInner::ui_isInlineItemBeingChosen() { } void StickerPanInner::appendSet(uint64 setId) { - const Stickers::Sets &sets(Global::StickerSets()); + auto &sets = Global::StickerSets(); auto it = sets.constFind(setId); if (it == sets.cend() || (it->flags & MTPDstickerSet::Flag::f_disabled) || it->stickers.isEmpty()) return; @@ -3584,7 +3584,7 @@ void EmojiPan::onSwitch() { } else { if (cShowingSavedGifs() && cSavedGifs().isEmpty()) { s_inner.showStickerSet(Stickers::DefaultSetId); - } else if (!cShowingSavedGifs() && !cSavedGifs().isEmpty() && Global::StickerSets().isEmpty()) { + } else if (!cShowingSavedGifs() && !cSavedGifs().isEmpty() && Global::StickerSetsOrder().isEmpty()) { s_inner.showStickerSet(Stickers::NoneSetId); } else { s_inner.updateShowingSavedGifs(); @@ -3652,7 +3652,10 @@ void EmojiPan::onRemoveSetSure() { ++i; } } - Global::RefStickerSets().erase(it); + it->flags &= ~MTPDstickerSet::Flag::f_installed; + if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)) { + Global::RefStickerSets().erase(it); + } int removeIndex = Global::StickerSetsOrder().indexOf(_removingSetId); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); refreshStickers(); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 4a3597d481..3e1a181430 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -560,6 +560,9 @@ struct Data { Stickers::Sets StickerSets; Stickers::Order StickerSetsOrder; uint64 LastStickersUpdate = 0; + Stickers::Order FeaturedStickerSetsOrder; + Stickers::UnreadMap FeaturedUnreadSets; + uint64 LastFeaturedStickersUpdate = 0; MTP::DcOptions DcOptions; @@ -626,6 +629,9 @@ DefineRefVar(Global, PendingItemsMap, PendingRepaintItems); DefineVar(Global, Stickers::Sets, StickerSets); DefineVar(Global, Stickers::Order, StickerSetsOrder); DefineVar(Global, uint64, LastStickersUpdate); +DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder); +DefineVar(Global, Stickers::UnreadMap, FeaturedUnreadSets); +DefineVar(Global, uint64, LastFeaturedStickersUpdate); DefineVar(Global, MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index ab621be037..f8831e798f 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -181,7 +181,14 @@ static const uint64 DefaultSetId = 0; // for backward compatibility static const uint64 CustomSetId = 0xFFFFFFFFFFFFFFFFULL, RecentSetId = 0xFFFFFFFFFFFFFFFEULL; static const uint64 NoneSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel struct Set { - Set(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, MTPDstickerSet::Flags flags) : id(id), access(access), title(title), shortName(shortName), count(count), hash(hash), flags(flags) { + Set(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, MTPDstickerSet::Flags flags) + : id(id) + , access(access) + , title(title) + , shortName(shortName) + , count(count) + , hash(hash) + , flags(flags) { } uint64 id, access; QString title, shortName; @@ -192,6 +199,7 @@ struct Set { }; using Sets = QMap; using Order = QList; +using UnreadMap = OrderedSet; } // namespace Stickers @@ -241,6 +249,9 @@ DeclareRefVar(PendingItemsMap, PendingRepaintItems); DeclareVar(Stickers::Sets, StickerSets); DeclareVar(Stickers::Order, StickerSetsOrder); DeclareVar(uint64, LastStickersUpdate); +DeclareVar(Stickers::Order, FeaturedStickerSetsOrder); +DeclareVar(Stickers::UnreadMap, FeaturedUnreadSets); +DeclareVar(uint64, LastFeaturedStickersUpdate); DeclareVar(MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 2665065c44..a29b920533 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2868,7 +2868,9 @@ bool HistoryItem::unread() const { if (id > 0) { if (id < history()->outboxReadBefore) return false; - if (auto channel = history()->peer->asChannel()) { + if (auto user = history()->peer->asUser()) { + if (user->botInfo) return false; + } else if (auto channel = history()->peer->asChannel()) { if (!channel->isMegagroup()) return false; } } diff --git a/Telegram/SourceFiles/history/field_autocomplete.cpp b/Telegram/SourceFiles/history/field_autocomplete.cpp index c62e7637e7..67995b523c 100644 --- a/Telegram/SourceFiles/history/field_autocomplete.cpp +++ b/Telegram/SourceFiles/history/field_autocomplete.cpp @@ -153,8 +153,8 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { StickerPack srows; if (_emoji) { QMap setsToRequest; - Stickers::Sets &sets(Global::RefStickerSets()); - const Stickers::Order &order(Global::StickerSetsOrder()); + auto &sets = Global::RefStickerSets(); + auto &order = Global::StickerSetsOrder(); for (int i = 0, l = order.size(); i < l; ++i) { auto it = sets.find(order.at(i)); if (it != sets.cend()) { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 9ef08f7d37..3bdd9da635 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -33,6 +33,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "data/data_drafts.h" #include "history/history_service_layout.h" #include "profile/profile_members_widget.h" +#include "core/click_handler_types.h" #include "lang.h" #include "application.h" #include "mainwidget.h" @@ -3519,12 +3520,18 @@ void HistoryWidget::onRecordUpdate(quint16 level, qint32 samples) { } void HistoryWidget::updateStickers() { - if (!Global::LastStickersUpdate() || getms(true) >= Global::LastStickersUpdate() + StickersUpdateTimeout) { + auto now = getms(true); + if (!Global::LastStickersUpdate() || now >= Global::LastStickersUpdate() + StickersUpdateTimeout) { if (!_stickersUpdateRequest) { _stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true))), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed)); } } - if (!cLastSavedGifsUpdate() || getms(true) >= cLastSavedGifsUpdate() + StickersUpdateTimeout) { + if (!Global::LastFeaturedStickersUpdate() || now >= Global::LastFeaturedStickersUpdate() + StickersUpdateTimeout) { + if (!_featuredStickersUpdateRequest) { + _featuredStickersUpdateRequest = MTP::send(MTPmessages_GetFeaturedStickers(MTP_int(Local::countFeaturedStickersHash())), rpcDone(&HistoryWidget::featuredStickersGot), rpcFail(&HistoryWidget::featuredStickersFailed)); + } + } + if (!cLastSavedGifsUpdate() || now >= cLastSavedGifsUpdate() + StickersUpdateTimeout) { if (!_savedGifsUpdateRequest) { _savedGifsUpdateRequest = MTP::send(MTPmessages_GetSavedGifs(MTP_int(Local::countSavedGifsHash())), rpcDone(&HistoryWidget::savedGifsGot), rpcFail(&HistoryWidget::savedGifsFailed)); } @@ -3641,17 +3648,17 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { const auto &d_sets(d.vsets.c_vector().v); - Stickers::Order &setsOrder(Global::RefStickerSetsOrder()); + auto &setsOrder = Global::RefStickerSetsOrder(); setsOrder.clear(); - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); QMap setsToRequest; - for (auto i = sets.begin(), e = sets.end(); i != e; ++i) { - i->access = 0; // mark for removing + for (auto &set : sets) { + set.flags &= ~MTPDstickerSet::Flag::f_installed; // mark for removing } - for (int i = 0, l = d_sets.size(); i != l; ++i) { - if (d_sets.at(i).type() == mtpc_stickerSet) { - const auto &set(d_sets.at(i).c_stickerSet()); + for_const (auto &setData, d_sets) { + if (setData.type() == mtpc_stickerSet) { + const auto &set(setData.c_stickerSet()); auto it = sets.find(set.vid.v); QString title = stickerSetTitle(set); if (it == sets.cend()) { @@ -3660,7 +3667,8 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { it->access = set.vaccess_hash.v; it->title = title; it->shortName = qs(set.vshort_name); - it->flags = set.vflags.v; + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded); + it->flags = set.vflags.v | clientFlags; if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) { it->count = set.vcount.v; it->hash = set.vhash.v; @@ -3678,9 +3686,9 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { bool writeRecent = false; RecentStickerPack &recent(cGetRecentStickers()); for (Stickers::Sets::iterator it = sets.begin(), e = sets.end(); it != e;) { - if (it->id == Stickers::CustomSetId || it->access != 0) { - ++it; - } else { + bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); + bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured); + 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); @@ -3689,6 +3697,10 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { ++i; } } + } + if (installed || featured) { + ++it; + } else { it = sets.erase(it); } } @@ -3720,6 +3732,90 @@ bool HistoryWidget::stickersFailed(const RPCError &error) { return true; } +void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stickers) { + Global::SetLastFeaturedStickersUpdate(getms(true)); + _featuredStickersUpdateRequest = 0; + + if (stickers.type() != mtpc_messages_featuredStickers) return; + auto &d(stickers.c_messages_featuredStickers()); + + auto &d_sets(d.vsets.c_vector().v); + + auto &setsOrder = Global::RefFeaturedStickerSetsOrder(); + setsOrder.clear(); + + auto &sets = Global::RefStickerSets(); + QMap setsToRequest; + for (auto &set : sets) { + set.flags &= ~MTPDstickerSet_ClientFlag::f_featured; // mark for removing + } + for (int i = 0, l = d_sets.size(); i != l; ++i) { + if (d_sets.at(i).type() == mtpc_stickerSet) { + const auto &set(d_sets.at(i).c_stickerSet()); + auto it = sets.find(set.vid.v); + QString title = stickerSetTitle(set); + if (it == sets.cend()) { + 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 | MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded)); + } 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_not_loaded); + it->flags = set.vflags.v | clientFlags | MTPDstickerSet_ClientFlag::f_featured; + 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); + } + } + } + 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); + if (installed || featured) { + ++it; + } else { + it = sets.erase(it); + } + } + + auto &unreadFeatured = Global::RefFeaturedUnreadSets(); + unreadFeatured.clear(); + for_const (auto &unreadSetId, d.vunread.c_vector().v) { + unreadFeatured.insert(unreadSetId.v); + } + + 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::const_iterator i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) { + App::api()->scheduleStickerSetRequest(i.key(), i.value()); + } + App::api()->requestStickerSets(); + } + + Local::writeStickers(); + + if (App::main()) emit App::main()->stickersUpdated(); +} + +bool HistoryWidget::featuredStickersFailed(const RPCError &error) { + if (MTP::isDefaultHandledError(error)) return false; + + LOG(("App Fail: Failed to get featured stickers!")); + + Global::SetLastFeaturedStickersUpdate(getms(true)); + _featuredStickersUpdateRequest = 0; + return true; +} + void HistoryWidget::savedGifsGot(const MTPmessages_SavedGifs &gifs) { cSetLastSavedGifsUpdate(getms(true)); _savedGifsUpdateRequest = 0; @@ -5592,6 +5688,8 @@ void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotC toast.text = qs(answerData.vmessage); Ui::Toast::Show(App::wnd(), toast); } + } else if (answerData.has_url()) { + UrlClickHandler::doOpen(qs(answerData.vurl)); } } } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index c2474c014d..ff68e4e3eb 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -1005,6 +1005,10 @@ private: void stickersGot(const MTPmessages_AllStickers &stickers); bool stickersFailed(const RPCError &error); + mtpRequestId _featuredStickersUpdateRequest = 0; + void featuredStickersGot(const MTPmessages_FeaturedStickers &stickers); + bool featuredStickersFailed(const RPCError &error); + mtpRequestId _savedGifsUpdateRequest = 0; void savedGifsGot(const MTPmessages_SavedGifs &gifs); bool savedGifsFailed(const RPCError &error); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 6ab0612b8b..3c2ab76d48 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3038,7 +3038,7 @@ namespace Local { void writeStickers() { if (!_working()) return; - const Stickers::Sets &sets(Global::StickerSets()); + auto &sets = Global::StickerSets(); if (sets.isEmpty()) { if (_stickersKey) { clearKey(_stickersKey); @@ -3050,31 +3050,36 @@ namespace Local { int32 setsCount = 0; QByteArray hashToWrite; quint32 size = sizeof(quint32) + Serialize::bytearraySize(hashToWrite); - for (auto i = sets.cbegin(); i != sets.cend(); ++i) { - bool notLoaded = (i->flags & MTPDstickerSet_ClientFlag::f_not_loaded); + for_const (auto &set, sets) { + bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded); if (notLoaded) { - if (!(i->flags & MTPDstickerSet::Flag::f_disabled) || (i->flags & MTPDstickerSet::Flag::f_official)) { // waiting to receive + if (!(set.flags & MTPDstickerSet::Flag::f_disabled) + || (set.flags & MTPDstickerSet::Flag::f_official) + || (set.flags & MTPDstickerSet_ClientFlag::f_featured)) { // waiting to receive return; } } else { - if (i->stickers.isEmpty()) continue; + if (set.stickers.isEmpty()) continue; } // id + access + title + shortName + stickersCount + hash + flags - size += sizeof(quint64) * 2 + Serialize::stringSize(i->title) + Serialize::stringSize(i->shortName) + sizeof(quint32) + sizeof(qint32) * 2; - for (StickerPack::const_iterator j = i->stickers.cbegin(), e = i->stickers.cend(); j != e; ++j) { - size += Serialize::Document::sizeInStream(*j); + size += sizeof(quint64) * 2 + Serialize::stringSize(set.title) + Serialize::stringSize(set.shortName) + sizeof(quint32) + sizeof(qint32) * 2; + for_const (auto &sticker, set.stickers) { + size += Serialize::Document::sizeInStream(sticker); } if (AppVersion > 9018) { size += sizeof(qint32); // emojiCount - for (StickersByEmojiMap::const_iterator j = i->emoji.cbegin(), e = i->emoji.cend(); j != e; ++j) { + for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) { size += Serialize::stringSize(emojiString(j.key())) + sizeof(qint32) + (j->size() * sizeof(quint64)); } } ++setsCount; } + size += sizeof(qint32) + (Global::StickerSetsOrder().size() * sizeof(quint64)); + size += sizeof(qint32) + (Global::FeaturedStickerSetsOrder().size() * sizeof(quint64)); + size += sizeof(qint32) + (Global::FeaturedUnreadSets().size() * sizeof(quint64)); if (!_stickersKey) { _stickersKey = genKey(); @@ -3083,10 +3088,17 @@ namespace Local { } EncryptedDescriptor data(size); data.stream << quint32(setsCount) << hashToWrite; - _writeStickerSet(data.stream, Stickers::CustomSetId); - for (auto i = Global::StickerSetsOrder().cbegin(), e = Global::StickerSetsOrder().cend(); i != e; ++i) { - _writeStickerSet(data.stream, *i); + for_const (auto &set, sets) { + _writeStickerSet(data.stream, set.id); } + data.stream << Global::StickerSetsOrder(); + data.stream << Global::FeaturedStickerSetsOrder(); + + data.stream << qint32(Global::FeaturedUnreadSets().size()); + for_const (auto setId, Global::FeaturedUnreadSets()) { + data.stream << quint64(setId); + } + FileWriteDescriptor file(_stickersKey); file.writeEncrypted(data); } @@ -3103,17 +3115,17 @@ namespace Local { return; } - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); sets.clear(); - Stickers::Order &order(Global::RefStickerSetsOrder()); + auto &order = Global::RefStickerSetsOrder(); order.clear(); - RecentStickerPack &recent(cRefRecentStickers()); + auto &recent = cRefRecentStickers(); recent.clear(); - Stickers::Set &def(sets.insert(Stickers::DefaultSetId, Stickers::Set(Stickers::DefaultSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet::Flag::f_official)).value()); - Stickers::Set &custom(sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, 0)).value()); + auto &def = sets.insert(Stickers::DefaultSetId, Stickers::Set(Stickers::DefaultSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet::Flag::f_official | MTPDstickerSet::Flag::f_installed)).value(); + auto &custom = sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, MTPDstickerSet::Flag::f_installed)).value(); QMap read; while (!stickers.stream.atEnd()) { @@ -3179,12 +3191,18 @@ namespace Local { return; } - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); sets.clear(); - Stickers::Order &order(Global::RefStickerSetsOrder()); + auto &order = Global::RefStickerSetsOrder(); order.clear(); + auto &featuredOrder = Global::RefFeaturedStickerSetsOrder(); + featuredOrder.clear(); + + auto &unreadFeatured = Global::RefFeaturedUnreadSets(); + unreadFeatured.clear(); + quint32 cnt; QByteArray hash; stickers.stream >> cnt >> hash; // ignore hash, it is counted @@ -3205,19 +3223,27 @@ namespace Local { setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_not_loaded); } } + if (stickers.version < 9057) { + setFlags |= qFlags(MTPDstickerSet::Flag::f_installed); + } if (setId == Stickers::DefaultSetId) { setTitle = lang(lng_stickers_default_set); setFlags |= qFlags(MTPDstickerSet::Flag::f_official); - order.push_front(setId); + if (stickers.version < 9057) { + order.push_front(setId); + } } else if (setId == Stickers::CustomSetId) { setTitle = lang(lng_custom_stickers); } else if (setId) { - order.push_back(setId); + if (stickers.version < 9057) { + order.push_back(setId); + } } else { continue; } - Stickers::Set &set(sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))).value()); + + auto &set = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))).value(); if (scnt < 0) { // disabled not loaded set set.count = -scnt; continue; @@ -3261,6 +3287,22 @@ namespace Local { } } } + + // Read orders of installed and featured stickers. + if (stickers.version >= 9057) { + stickers.stream >> order; + stickers.stream >> featuredOrder; + + qint32 unreadCount = 0; + stickers.stream >> unreadCount; + for (int i = 0; i < unreadCount; ++i) { + quint64 setId = 0; + stickers.stream >> setId; + if (setId) { + unreadFeatured.insert(setId); + } + } + } } int32 countStickersHash(bool checkOfficial) { @@ -3284,6 +3326,19 @@ namespace Local { return (!checkOfficial || (!foundBad && foundOfficial)) ? int32(acc & 0x7FFFFFFF) : 0; } + int32 countFeaturedStickersHash() { + uint32 acc = 0; + auto &featured(Global::FeaturedStickerSetsOrder()); + for_const (auto setId, featured) { + acc = (acc * 20261) + uint32(setId >> 32); + acc = (acc * 20261) + uint32(setId & 0xFFFFFFFF); + if (Global::FeaturedUnreadSets().contains(setId)) { + acc = (acc * 20261) + 1U; + } + } + return int32(acc & 0x7FFFFFFF); + } + int32 countSavedGifsHash() { uint32 acc = 0; const SavedGifs &saved(cSavedGifs()); diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index 0f9a0fd11c..204ac320ad 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -156,6 +156,7 @@ namespace Local { void writeStickers(); void readStickers(); int32 countStickersHash(bool checkOfficial = false); + int32 countFeaturedStickersHash(); void writeSavedGifs(); void readSavedGifs(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index fab6779307..6cb95b58cd 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3700,7 +3700,7 @@ void MainWidget::incrementSticker(DocumentData *sticker) { if (!found) { Stickers::Sets::iterator it = sets.find(Stickers::CustomSetId); if (it == sets.cend()) { - it = sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, 0)); + it = sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, MTPDstickerSet::Flag::f_installed)); } it->stickers.push_back(sticker); ++it->count; @@ -4646,7 +4646,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { Stickers::Sets &sets(Global::RefStickerSets()); auto it = sets.find(s.vid.v); if (it == sets.cend()) { - it = sets.insert(s.vid.v, Stickers::Set(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v)); + it = sets.insert(s.vid.v, Stickers::Set(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v | MTPDstickerSet::Flag::f_installed)); + } else { + it->flags |= MTPDstickerSet::Flag::f_installed; } const auto &v(set.vdocuments.c_vector().v); @@ -4703,9 +4705,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateStickerSetsOrder: { - const auto &d(update.c_updateStickerSetsOrder()); - const auto &order(d.vorder.c_vector().v); - const auto &sets(Global::StickerSets()); + auto &d = update.c_updateStickerSetsOrder(); + auto &order = d.vorder.c_vector().v; + auto &sets = Global::StickerSets(); Stickers::Order result; for (int32 i = 0, l = order.size(); i < l; ++i) { if (sets.constFind(order.at(i).v) == sets.cend()) { @@ -4728,6 +4730,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { App::main()->updateStickers(); } break; + case mtpc_updateReadFeaturedStickers: { + Global::RefFeaturedUnreadSets().clear(); + Local::writeStickers(); + emit stickersUpdated(); + } break; + ////// Cloud saved GIFs case mtpc_updateSavedGifs: { cSetLastSavedGifsUpdate(0); diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index 0fed750d13..96eebe2c3b 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -1060,8 +1060,11 @@ enum class MTPDstickerSet_ClientFlag : int32 { // sticker set is not yet loaded f_not_loaded = (1 << 30), + // sticker set is one of featured (should be saved locally) + f_featured = (1 << 29), + // update this when adding new client side flags - MIN_FIELD = (1 << 30), + MIN_FIELD = (1 << 29), }; DEFINE_MTP_CLIENT_FLAGS(MTPDstickerSet) diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index aac8a23bf8..777de9b153 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -392,6 +392,7 @@ updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#2cbd95af query_id:long user_id:int msg_id:InputBotInlineMessageID data:bytes = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; +updateReadFeaturedStickers#571d2742 = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -670,7 +671,7 @@ auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -messages.botCallbackAnswer#1264f1c6 flags:# alert:flags.1?true message:flags.0?string = messages.BotCallbackAnswer; +messages.botCallbackAnswer#31fde6e4 flags:# alert:flags.1?true allow_pip:flags.2?true message:flags.0?string url:flags.3?string = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; @@ -696,6 +697,9 @@ contacts.topPeers#70b772a8 categories:Vector chats:Vector< draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; +messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; +messages.featuredStickers#ed6392b7 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -826,10 +830,12 @@ messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEdi messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#a6e94f04 peer:InputPeer msg_id:int data:bytes = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#481c591a flags:# alert:flags.1?true query_id:long message:flags.0?string = Bool; +messages.setBotCallbackAnswer#70dc0fa3 flags:# alert:flags.1?true allow_pip:flags.2?true query_id:long message:flags.0?string url:flags.3?string = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; +messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; +messages.readFeaturedStickers#e21cbb = Bool; updates.getState#edd4882a = updates.State; updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; @@ -880,4 +886,4 @@ channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessag channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; -// LAYER 53 +// LAYER 54 diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp index 1e14155744..f22248eaa7 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp +++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp @@ -3012,6 +3012,10 @@ void _serialize_updateDraftMessage(MTPStringLogger &to, int32 stage, int32 lev, } } +void _serialize_updateReadFeaturedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + to.add("{ updateReadFeaturedStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); +} + void _serialize_updates_state(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -5586,7 +5590,9 @@ void _serialize_messages_botCallbackAnswer(MTPStringLogger &to, int32 stage, int switch (stage) { case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 1: to.add(" alert: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_alert) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; - case 2: to.add(" message: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; + case 2: to.add(" allow_pip: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_allow_pip) { to.add("YES [ BY BIT 2 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; + case 3: to.add(" message: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; + case 4: to.add(" url: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -5745,6 +5751,25 @@ void _serialize_draftMessage(MTPStringLogger &to, int32 stage, int32 lev, Types } } +void _serialize_messages_featuredStickersNotModified(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + to.add("{ messages_featuredStickersNotModified }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); +} + +void _serialize_messages_featuredStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_featuredStickers"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" sets: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" unread: "); ++stages.back(); types.push_back(0); vtypes.push_back(mtpc_long+0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -6335,8 +6360,10 @@ void _serialize_messages_setBotCallbackAnswer(MTPStringLogger &to, int32 stage, switch (stage) { case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 1: to.add(" alert: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_alert) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; - case 2: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 3: to.add(" message: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; + case 2: to.add(" allow_pip: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_allow_pip) { to.add("YES [ BY BIT 2 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; + case 3: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 4: to.add(" message: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; + case 5: to.add(" url: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -6361,6 +6388,10 @@ void _serialize_messages_saveDraft(MTPStringLogger &to, int32 stage, int32 lev, } } +void _serialize_messages_readFeaturedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + to.add("{ messages_readFeaturedStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); +} + void _serialize_upload_saveFilePart(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -8027,6 +8058,19 @@ void _serialize_messages_getPeerDialogs(MTPStringLogger &to, int32 stage, int32 } } +void _serialize_messages_getFeaturedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_getFeaturedStickers"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_updates_getState(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ updates_getState }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -8484,6 +8528,7 @@ namespace { _serializers.insert(mtpc_updateInlineBotCallbackQuery, _serialize_updateInlineBotCallbackQuery); _serializers.insert(mtpc_updateReadChannelOutbox, _serialize_updateReadChannelOutbox); _serializers.insert(mtpc_updateDraftMessage, _serialize_updateDraftMessage); + _serializers.insert(mtpc_updateReadFeaturedStickers, _serialize_updateReadFeaturedStickers); _serializers.insert(mtpc_updates_state, _serialize_updates_state); _serializers.insert(mtpc_updates_differenceEmpty, _serialize_updates_differenceEmpty); _serializers.insert(mtpc_updates_difference, _serialize_updates_difference); @@ -8697,6 +8742,8 @@ namespace { _serializers.insert(mtpc_contacts_topPeers, _serialize_contacts_topPeers); _serializers.insert(mtpc_draftMessageEmpty, _serialize_draftMessageEmpty); _serializers.insert(mtpc_draftMessage, _serialize_draftMessage); + _serializers.insert(mtpc_messages_featuredStickersNotModified, _serialize_messages_featuredStickersNotModified); + _serializers.insert(mtpc_messages_featuredStickers, _serialize_messages_featuredStickers); _serializers.insert(mtpc_req_pq, _serialize_req_pq); _serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params); @@ -8743,6 +8790,7 @@ namespace { _serializers.insert(mtpc_messages_editInlineBotMessage, _serialize_messages_editInlineBotMessage); _serializers.insert(mtpc_messages_setBotCallbackAnswer, _serialize_messages_setBotCallbackAnswer); _serializers.insert(mtpc_messages_saveDraft, _serialize_messages_saveDraft); + _serializers.insert(mtpc_messages_readFeaturedStickers, _serialize_messages_readFeaturedStickers); _serializers.insert(mtpc_upload_saveFilePart, _serialize_upload_saveFilePart); _serializers.insert(mtpc_upload_saveBigFilePart, _serialize_upload_saveBigFilePart); _serializers.insert(mtpc_help_saveAppLog, _serialize_help_saveAppLog); @@ -8861,6 +8909,7 @@ namespace { _serializers.insert(mtpc_messages_getMessageEditData, _serialize_messages_getMessageEditData); _serializers.insert(mtpc_messages_getBotCallbackAnswer, _serialize_messages_getBotCallbackAnswer); _serializers.insert(mtpc_messages_getPeerDialogs, _serialize_messages_getPeerDialogs); + _serializers.insert(mtpc_messages_getFeaturedStickers, _serialize_messages_getFeaturedStickers); _serializers.insert(mtpc_updates_getState, _serialize_updates_getState); _serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference); _serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference); diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h index 90eff1aa93..15b3d4942f 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.h +++ b/Telegram/SourceFiles/mtproto/scheme_auto.h @@ -30,7 +30,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org namespace MTP { namespace internal { -static constexpr mtpPrime CurrentLayer = 53; +static constexpr mtpPrime CurrentLayer = 54; class TypeCreator; @@ -288,6 +288,7 @@ enum { mtpc_updateInlineBotCallbackQuery = 0x2cbd95af, mtpc_updateReadChannelOutbox = 0x25d6c9c7, mtpc_updateDraftMessage = 0xee2bb969, + mtpc_updateReadFeaturedStickers = 0x571d2742, mtpc_updates_state = 0xa56c2a3e, mtpc_updates_differenceEmpty = 0x5d75a138, mtpc_updates_difference = 0xf49ca0, @@ -485,7 +486,7 @@ enum { mtpc_auth_sentCodeTypeSms = 0xc000bba2, mtpc_auth_sentCodeTypeCall = 0x5353e5a7, mtpc_auth_sentCodeTypeFlashCall = 0xab03c6d9, - mtpc_messages_botCallbackAnswer = 0x1264f1c6, + mtpc_messages_botCallbackAnswer = 0x31fde6e4, mtpc_messages_messageEditData = 0x26b5dde6, mtpc_inputBotInlineMessageID = 0x890c3d89, mtpc_inlineBotSwitchPM = 0x3c20629f, @@ -501,6 +502,8 @@ enum { mtpc_contacts_topPeers = 0x70b772a8, mtpc_draftMessageEmpty = 0xba4baec5, mtpc_draftMessage = 0xfd8e711f, + mtpc_messages_featuredStickersNotModified = 0x4ede3cf, + mtpc_messages_featuredStickers = 0xed6392b7, mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsgs = 0x3dc4b4f0, mtpc_initConnection = 0x69796de9, @@ -624,10 +627,12 @@ enum { mtpc_messages_editMessage = 0xce91e4ca, mtpc_messages_editInlineBotMessage = 0x130c2c85, mtpc_messages_getBotCallbackAnswer = 0xa6e94f04, - mtpc_messages_setBotCallbackAnswer = 0x481c591a, + mtpc_messages_setBotCallbackAnswer = 0x70dc0fa3, mtpc_messages_getPeerDialogs = 0x2d9776b9, mtpc_messages_saveDraft = 0xbc39e14b, mtpc_messages_getAllDrafts = 0x6a3f8d65, + mtpc_messages_getFeaturedStickers = 0x2dacca4f, + mtpc_messages_readFeaturedStickers = 0xe21cbb, mtpc_updates_getState = 0xedd4882a, mtpc_updates_getDifference = 0xa041495, mtpc_updates_getChannelDifference = 0xbb32d7c0, @@ -1353,6 +1358,9 @@ class MTPDcontacts_topPeers; class MTPdraftMessage; class MTPDdraftMessage; +class MTPmessages_featuredStickers; +class MTPDmessages_featuredStickers; + // Boxed types definitions typedef MTPBoxed MTPResPQ; @@ -1527,6 +1535,7 @@ typedef MTPBoxed MTPTopPeerCategory; typedef MTPBoxed MTPTopPeerCategoryPeers; typedef MTPBoxed MTPcontacts_TopPeers; typedef MTPBoxed MTPDraftMessage; +typedef MTPBoxed MTPmessages_FeaturedStickers; // Type classes definitions @@ -9532,6 +9541,43 @@ private: }; typedef MTPBoxed MTPDraftMessage; +class MTPmessages_featuredStickers : private mtpDataOwner { +public: + MTPmessages_featuredStickers() : mtpDataOwner(0), _type(0) { + } + MTPmessages_featuredStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_featuredStickers &_messages_featuredStickers() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_featuredStickers) throw mtpErrorWrongTypeId(_type, mtpc_messages_featuredStickers); + split(); + return *(MTPDmessages_featuredStickers*)data; + } + const MTPDmessages_featuredStickers &c_messages_featuredStickers() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_featuredStickers) throw mtpErrorWrongTypeId(_type, mtpc_messages_featuredStickers); + return *(const MTPDmessages_featuredStickers*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_featuredStickers(mtpTypeId type); + explicit MTPmessages_featuredStickers(MTPDmessages_featuredStickers *_data); + + friend class MTP::internal::TypeCreator; + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_FeaturedStickers; + // Type constructors with data class MTPDresPQ : public mtpDataImpl { @@ -14274,23 +14320,28 @@ class MTPDmessages_botCallbackAnswer : public mtpDataImpl(v)); } bool is_alert() const { return vflags.v & Flag::f_alert; } + bool is_allow_pip() const { return vflags.v & Flag::f_allow_pip; } bool has_message() const { return vflags.v & Flag::f_message; } + bool has_url() const { return vflags.v & Flag::f_url; } MTPDmessages_botCallbackAnswer() { } - MTPDmessages_botCallbackAnswer(const MTPflags &_flags, const MTPstring &_message) : vflags(_flags), vmessage(_message) { + MTPDmessages_botCallbackAnswer(const MTPflags &_flags, const MTPstring &_message, const MTPstring &_url) : vflags(_flags), vmessage(_message), vurl(_url) { } MTPflags vflags; MTPstring vmessage; + MTPstring vurl; }; class MTPDmessages_messageEditData : public mtpDataImpl { @@ -14412,6 +14463,18 @@ public: MTPint vdate; }; +class MTPDmessages_featuredStickers : public mtpDataImpl { +public: + MTPDmessages_featuredStickers() { + } + MTPDmessages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) : vhash(_hash), vsets(_sets), vunread(_unread) { + } + + MTPint vhash; + MTPVector vsets; + MTPVector vunread; +}; + // RPC methods class MTPreq_pq { // RPC method 'req_pq' @@ -20204,30 +20267,35 @@ class MTPmessages_setBotCallbackAnswer { // RPC method 'messages.setBotCallbackA public: enum class Flag : int32 { f_alert = (1 << 1), + f_allow_pip = (1 << 2), f_message = (1 << 0), + f_url = (1 << 3), - MAX_FIELD = (1 << 1), + MAX_FIELD = (1 << 3), }; Q_DECLARE_FLAGS(Flags, Flag); friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } bool is_alert() const { return vflags.v & Flag::f_alert; } + bool is_allow_pip() const { return vflags.v & Flag::f_allow_pip; } bool has_message() const { return vflags.v & Flag::f_message; } + bool has_url() const { return vflags.v & Flag::f_url; } MTPflags vflags; MTPlong vquery_id; MTPstring vmessage; + MTPstring vurl; MTPmessages_setBotCallbackAnswer() { } MTPmessages_setBotCallbackAnswer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setBotCallbackAnswer) { read(from, end, cons); } - MTPmessages_setBotCallbackAnswer(const MTPflags &_flags, const MTPlong &_query_id, const MTPstring &_message) : vflags(_flags), vquery_id(_query_id), vmessage(_message) { + MTPmessages_setBotCallbackAnswer(const MTPflags &_flags, const MTPlong &_query_id, const MTPstring &_message, const MTPstring &_url) : vflags(_flags), vquery_id(_query_id), vmessage(_message), vurl(_url) { } uint32 innerLength() const { - return vflags.innerLength() + vquery_id.innerLength() + (has_message() ? vmessage.innerLength() : 0); + return vflags.innerLength() + vquery_id.innerLength() + (has_message() ? vmessage.innerLength() : 0) + (has_url() ? vurl.innerLength() : 0); } mtpTypeId type() const { return mtpc_messages_setBotCallbackAnswer; @@ -20236,11 +20304,13 @@ public: vflags.read(from, end); vquery_id.read(from, end); if (has_message()) { vmessage.read(from, end); } else { vmessage = MTPstring(); } + if (has_url()) { vurl.read(from, end); } else { vurl = MTPstring(); } } void write(mtpBuffer &to) const { vflags.write(to); vquery_id.write(to); if (has_message()) vmessage.write(to); + if (has_url()) vurl.write(to); } typedef MTPBool ResponseType; @@ -20255,7 +20325,7 @@ public: } MTPmessages_SetBotCallbackAnswer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { } - MTPmessages_SetBotCallbackAnswer(const MTPflags &_flags, const MTPlong &_query_id, const MTPstring &_message) : MTPBoxed(MTPmessages_setBotCallbackAnswer(_flags, _query_id, _message)) { + MTPmessages_SetBotCallbackAnswer(const MTPflags &_flags, const MTPlong &_query_id, const MTPstring &_message, const MTPstring &_url) : MTPBoxed(MTPmessages_setBotCallbackAnswer(_flags, _query_id, _message, _url)) { } }; @@ -20396,6 +20466,76 @@ public: } }; +class MTPmessages_getFeaturedStickers { // RPC method 'messages.getFeaturedStickers' +public: + MTPint vhash; + + MTPmessages_getFeaturedStickers() { + } + MTPmessages_getFeaturedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getFeaturedStickers) { + read(from, end, cons); + } + MTPmessages_getFeaturedStickers(MTPint _hash) : vhash(_hash) { + } + + uint32 innerLength() const { + return vhash.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_getFeaturedStickers; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getFeaturedStickers) { + vhash.read(from, end); + } + void write(mtpBuffer &to) const { + vhash.write(to); + } + + typedef MTPmessages_FeaturedStickers ResponseType; +}; +class MTPmessages_GetFeaturedStickers : public MTPBoxed { +public: + MTPmessages_GetFeaturedStickers() { + } + MTPmessages_GetFeaturedStickers(const MTPmessages_getFeaturedStickers &v) : MTPBoxed(v) { + } + MTPmessages_GetFeaturedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetFeaturedStickers(MTPint _hash) : MTPBoxed(MTPmessages_getFeaturedStickers(_hash)) { + } +}; + +class MTPmessages_readFeaturedStickers { // RPC method 'messages.readFeaturedStickers' +public: + MTPmessages_readFeaturedStickers() { + } + MTPmessages_readFeaturedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_readFeaturedStickers) { + read(from, end, cons); + } + + uint32 innerLength() const { + return 0; + } + mtpTypeId type() const { + return mtpc_messages_readFeaturedStickers; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_readFeaturedStickers) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPBool ResponseType; +}; +class MTPmessages_ReadFeaturedStickers : public MTPBoxed { +public: + MTPmessages_ReadFeaturedStickers() { + } + MTPmessages_ReadFeaturedStickers(const MTPmessages_readFeaturedStickers &v) : MTPBoxed(v) { + } + MTPmessages_ReadFeaturedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + class MTPupdates_getState { // RPC method 'updates.getState' public: MTPupdates_getState() { @@ -22937,6 +23077,9 @@ public: inline static MTPupdate new_updateDraftMessage(const MTPPeer &_peer, const MTPDraftMessage &_draft) { return MTPupdate(new MTPDupdateDraftMessage(_peer, _draft)); } + inline static MTPupdate new_updateReadFeaturedStickers() { + return MTPupdate(mtpc_updateReadFeaturedStickers); + } inline static MTPupdates_state new_updates_state(MTPint _pts, MTPint _qts, MTPint _date, MTPint _seq, MTPint _unread_count) { return MTPupdates_state(new MTPDupdates_state(_pts, _qts, _date, _seq, _unread_count)); } @@ -23528,8 +23671,8 @@ public: inline static MTPauth_sentCodeType new_auth_sentCodeTypeFlashCall(const MTPstring &_pattern) { return MTPauth_sentCodeType(new MTPDauth_sentCodeTypeFlashCall(_pattern)); } - inline static MTPmessages_botCallbackAnswer new_messages_botCallbackAnswer(const MTPflags &_flags, const MTPstring &_message) { - return MTPmessages_botCallbackAnswer(new MTPDmessages_botCallbackAnswer(_flags, _message)); + inline static MTPmessages_botCallbackAnswer new_messages_botCallbackAnswer(const MTPflags &_flags, const MTPstring &_message, const MTPstring &_url) { + return MTPmessages_botCallbackAnswer(new MTPDmessages_botCallbackAnswer(_flags, _message, _url)); } inline static MTPmessages_messageEditData new_messages_messageEditData(const MTPflags &_flags) { return MTPmessages_messageEditData(new MTPDmessages_messageEditData(_flags)); @@ -23576,6 +23719,12 @@ public: inline static MTPdraftMessage new_draftMessage(const MTPflags &_flags, MTPint _reply_to_msg_id, const MTPstring &_message, const MTPVector &_entities, MTPint _date) { return MTPdraftMessage(new MTPDdraftMessage(_flags, _reply_to_msg_id, _message, _entities, _date)); } + inline static MTPmessages_featuredStickers new_messages_featuredStickersNotModified() { + return MTPmessages_featuredStickers(mtpc_messages_featuredStickersNotModified); + } + inline static MTPmessages_featuredStickers new_messages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) { + return MTPmessages_featuredStickers(new MTPDmessages_featuredStickers(_hash, _sets, _unread)); + } }; } // namespace internal @@ -28793,6 +28942,7 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI v.vpeer.read(from, end); v.vdraft.read(from, end); } break; + case mtpc_updateReadFeaturedStickers: _type = cons; break; default: throw mtpErrorUnexpected(cons, "MTPupdate"); } } @@ -29126,6 +29276,7 @@ inline MTPupdate::MTPupdate(mtpTypeId type) : mtpDataOwner(0), _type(type) { case mtpc_updateInlineBotCallbackQuery: setData(new MTPDupdateInlineBotCallbackQuery()); break; case mtpc_updateReadChannelOutbox: setData(new MTPDupdateReadChannelOutbox()); break; case mtpc_updateDraftMessage: setData(new MTPDupdateDraftMessage()); break; + case mtpc_updateReadFeaturedStickers: break; default: throw mtpErrorBadTypeId(type, "MTPupdate"); } } @@ -29373,6 +29524,9 @@ inline MTPupdate MTP_updateReadChannelOutbox(MTPint _channel_id, MTPint _max_id) inline MTPupdate MTP_updateDraftMessage(const MTPPeer &_peer, const MTPDraftMessage &_draft) { return MTP::internal::TypeCreator::new_updateDraftMessage(_peer, _draft); } +inline MTPupdate MTP_updateReadFeaturedStickers() { + return MTP::internal::TypeCreator::new_updateReadFeaturedStickers(); +} inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) { } @@ -34533,7 +34687,7 @@ inline MTPmessages_botCallbackAnswer::MTPmessages_botCallbackAnswer() : mtpDataO inline uint32 MTPmessages_botCallbackAnswer::innerLength() const { const MTPDmessages_botCallbackAnswer &v(c_messages_botCallbackAnswer()); - return v.vflags.innerLength() + (v.has_message() ? v.vmessage.innerLength() : 0); + return v.vflags.innerLength() + (v.has_message() ? v.vmessage.innerLength() : 0) + (v.has_url() ? v.vurl.innerLength() : 0); } inline mtpTypeId MTPmessages_botCallbackAnswer::type() const { return mtpc_messages_botCallbackAnswer; @@ -34545,17 +34699,19 @@ inline void MTPmessages_botCallbackAnswer::read(const mtpPrime *&from, const mtp MTPDmessages_botCallbackAnswer &v(_messages_botCallbackAnswer()); v.vflags.read(from, end); if (v.has_message()) { v.vmessage.read(from, end); } else { v.vmessage = MTPstring(); } + if (v.has_url()) { v.vurl.read(from, end); } else { v.vurl = MTPstring(); } } inline void MTPmessages_botCallbackAnswer::write(mtpBuffer &to) const { const MTPDmessages_botCallbackAnswer &v(c_messages_botCallbackAnswer()); v.vflags.write(to); if (v.has_message()) v.vmessage.write(to); + if (v.has_url()) v.vurl.write(to); } inline MTPmessages_botCallbackAnswer::MTPmessages_botCallbackAnswer(MTPDmessages_botCallbackAnswer *_data) : mtpDataOwner(_data) { } Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDmessages_botCallbackAnswer::Flags) -inline MTPmessages_botCallbackAnswer MTP_messages_botCallbackAnswer(const MTPflags &_flags, const MTPstring &_message) { - return MTP::internal::TypeCreator::new_messages_botCallbackAnswer(_flags, _message); +inline MTPmessages_botCallbackAnswer MTP_messages_botCallbackAnswer(const MTPflags &_flags, const MTPstring &_message, const MTPstring &_url) { + return MTP::internal::TypeCreator::new_messages_botCallbackAnswer(_flags, _message, _url); } inline MTPmessages_messageEditData::MTPmessages_messageEditData() : mtpDataOwner(new MTPDmessages_messageEditData()) { @@ -34896,6 +35052,59 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDdraftMessage::Flags) inline MTPdraftMessage MTP_draftMessage(const MTPflags &_flags, MTPint _reply_to_msg_id, const MTPstring &_message, const MTPVector &_entities, MTPint _date) { return MTP::internal::TypeCreator::new_draftMessage(_flags, _reply_to_msg_id, _message, _entities, _date); } + +inline uint32 MTPmessages_featuredStickers::innerLength() const { + switch (_type) { + case mtpc_messages_featuredStickers: { + const MTPDmessages_featuredStickers &v(c_messages_featuredStickers()); + return v.vhash.innerLength() + v.vsets.innerLength() + v.vunread.innerLength(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_featuredStickers::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_featuredStickers::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_featuredStickersNotModified: _type = cons; break; + case mtpc_messages_featuredStickers: _type = cons; { + if (!data) setData(new MTPDmessages_featuredStickers()); + MTPDmessages_featuredStickers &v(_messages_featuredStickers()); + v.vhash.read(from, end); + v.vsets.read(from, end); + v.vunread.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_featuredStickers"); + } +} +inline void MTPmessages_featuredStickers::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_featuredStickers: { + const MTPDmessages_featuredStickers &v(c_messages_featuredStickers()); + v.vhash.write(to); + v.vsets.write(to); + v.vunread.write(to); + } break; + } +} +inline MTPmessages_featuredStickers::MTPmessages_featuredStickers(mtpTypeId type) : mtpDataOwner(0), _type(type) { + switch (type) { + case mtpc_messages_featuredStickersNotModified: break; + case mtpc_messages_featuredStickers: setData(new MTPDmessages_featuredStickers()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_featuredStickers"); + } +} +inline MTPmessages_featuredStickers::MTPmessages_featuredStickers(MTPDmessages_featuredStickers *_data) : mtpDataOwner(_data), _type(mtpc_messages_featuredStickers) { +} +inline MTPmessages_featuredStickers MTP_messages_featuredStickersNotModified() { + return MTP::internal::TypeCreator::new_messages_featuredStickersNotModified(); +} +inline MTPmessages_featuredStickers MTP_messages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) { + return MTP::internal::TypeCreator::new_messages_featuredStickers(_hash, _sets, _unread); +} inline MTPDmessage::Flags mtpCastFlags(MTPDmessageService::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } inline MTPDmessage::Flags mtpCastFlags(MTPflags flags) { return mtpCastFlags(flags.v); } inline MTPDmessage::Flags mtpCastFlags(MTPDupdateShortMessage::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 4b3e006d7d..5d62a05385 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -890,13 +890,13 @@ bool StickerData::setInstalled() const { switch (set.type()) { case mtpc_inputStickerSetID: { auto it = Global::StickerSets().constFind(set.c_inputStickerSetID().vid.v); - return (it != Global::StickerSets().cend()) && !(it->flags & MTPDstickerSet::Flag::f_disabled); + return (it != Global::StickerSets().cend()) && !(it->flags & MTPDstickerSet::Flag::f_disabled) && (it->flags & MTPDstickerSet::Flag::f_installed); } break; case mtpc_inputStickerSetShortName: { QString 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_disabled); + return !(it->flags & MTPDstickerSet::Flag::f_disabled) && (it->flags & MTPDstickerSet::Flag::f_installed); } } } break; diff --git a/Telegram/SourceFiles/ui/text/text.h b/Telegram/SourceFiles/ui/text/text.h index e407b4fc26..02df179579 100644 --- a/Telegram/SourceFiles/ui/text/text.h +++ b/Telegram/SourceFiles/ui/text/text.h @@ -291,7 +291,7 @@ inline bool chIsSpace(QChar ch, bool rich = false) { return ch.isSpace() || (ch < 32 && !(rich && ch == TextCommand)) || (ch == QChar::ParagraphSeparator) || (ch == QChar::LineSeparator) || (ch == QChar::ObjectReplacementCharacter) || (ch == QChar::CarriageReturn) || (ch == QChar::Tabulation); } inline bool chIsDiac(QChar ch) { // diac and variation selectors - return (ch.category() == QChar::Mark_NonSpacing) || (ch.unicode() == 1652); + return (ch.category() == QChar::Mark_NonSpacing) || (ch == 1652) || (ch >= 64606 && ch <= 64611); } inline bool chIsBad(QChar ch) { return (ch == 0) || (ch >= 8232 && ch < 8237) || (ch >= 65024 && ch < 65040 && ch != 65039) || (ch >= 127 && ch < 160 && ch != 156) || (cPlatform() == dbipMac && ch >= 0x0B00 && ch <= 0x0B7F && chIsDiac(ch) && cIsElCapitan()); // tmp hack see https://bugreports.qt.io/browse/QTBUG-48910 diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index 449edf2cf1..a50bf242c1 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -2375,7 +2375,7 @@ SDKROOT = macosx; SYMROOT = ./../Mac; TDESKTOP_MAJOR_VERSION = 0.9; - TDESKTOP_VERSION = 0.9.56; + TDESKTOP_VERSION = 0.9.57; }; name = Release; }; @@ -2516,7 +2516,7 @@ SDKROOT = macosx; SYMROOT = ./../Mac; TDESKTOP_MAJOR_VERSION = 0.9; - TDESKTOP_VERSION = 0.9.56; + TDESKTOP_VERSION = 0.9.57; }; name = Debug; }; diff --git a/Telegram/build/version b/Telegram/build/version index 25a0b65be7..4a048eef7e 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,6 +1,6 @@ -AppVersion 9056 +AppVersion 9057 AppVersionStrMajor 0.9 -AppVersionStrSmall 0.9.56 -AppVersionStr 0.9.56 -AlphaChannel 0 +AppVersionStrSmall 0.9.57 +AppVersionStr 0.9.57 +AlphaChannel 1 BetaVersion 0 From cd696ade4ee785b9ad39093e22b31e431a3fb394 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 28 Jun 2016 21:05:38 +0300 Subject: [PATCH 02/13] Featured stickers fully supported (unread badges, box, adding, etc). --- Telegram/Resources/art/sprite.png | Bin 180708 -> 180375 bytes Telegram/Resources/art/sprite_200x.png | Bin 244667 -> 244010 bytes Telegram/Resources/basic.style | 21 +- .../Resources/icons/mediaview_save_check.png | Bin 0 -> 454 bytes .../icons/mediaview_save_check@2x.png | Bin 0 -> 882 bytes Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/apiwrap.cpp | 6 +- Telegram/SourceFiles/app.cpp | 3 + Telegram/SourceFiles/boxes/stickersetbox.cpp | 548 +++++++++++++----- Telegram/SourceFiles/boxes/stickersetbox.h | 227 +++++--- Telegram/SourceFiles/dialogs/dialogs.style | 1 - .../SourceFiles/dialogs/dialogs_layout.cpp | 6 +- Telegram/SourceFiles/dialogs/dialogs_layout.h | 2 + Telegram/SourceFiles/dropdown.cpp | 18 +- Telegram/SourceFiles/dropdown.h | 1 + Telegram/SourceFiles/facades.cpp | 4 +- Telegram/SourceFiles/facades.h | 10 +- .../history/field_autocomplete.cpp | 4 +- Telegram/SourceFiles/history/history.style | 4 +- Telegram/SourceFiles/historywidget.cpp | 37 +- Telegram/SourceFiles/localstorage.cpp | 45 +- Telegram/SourceFiles/mainwidget.cpp | 14 +- Telegram/SourceFiles/mediaview.cpp | 2 +- Telegram/SourceFiles/mtproto/core_types.h | 5 +- 24 files changed, 656 insertions(+), 304 deletions(-) create mode 100644 Telegram/Resources/icons/mediaview_save_check.png create mode 100644 Telegram/Resources/icons/mediaview_save_check@2x.png diff --git a/Telegram/Resources/art/sprite.png b/Telegram/Resources/art/sprite.png index 809d0201ac72064ec1d74fc61dcf930bcdc1cee1..932c1d9903fca15bd7022f818909ed8c20104a1b 100644 GIT binary patch delta 14271 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 L=v>ZMvkd)zRWe*1 delta 35306 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 T*y;!c_|ds!pi!)D7xDi9hL$$8 diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index 36cd767e9c..ca5150dfd4 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -1838,6 +1838,20 @@ stickersReorderFg: #777; stickersRowDisabledOpacity: 0.4; stickersRowDuration: 200; +stickersFeaturedHeight: 32px; +stickersFeaturedFont: contactsNameFont; +stickersFeaturedPosition: point(16px, 6px); +stickersFeaturedBadgeFont: semiboldFont; +stickersFeaturedBadgeSize: 21px; +stickersFeaturedPen: contactsNewItemFg; +stickersFeaturedUnreadBg: msgFileInBg; +stickersFeaturedUnreadSize: 5px; +stickersFeaturedUnreadSkip: 5px; +stickersFeaturedUnreadTop: 7px; +stickersFeaturedInstalled: icon { + { "mediaview_save_check", #40ace3 } +}; + emojiScroll: flatScroll(solidScroll) { deltat: 48px; } @@ -1861,6 +1875,9 @@ stickersSettings: sprite(140px, 124px, 21px, 22px); savedGifsOver: sprite(329px, 286px, 21px, 22px); savedGifsActive: sprite(350px, 286px, 21px, 22px); +stickersSettingsUnreadSize: 17px; +stickersSettingsUnreadPosition: point(4px, 5px); + emojiPanCategories: #f7f7f7; rbEmoji: flatCheckbox { @@ -2133,7 +2150,9 @@ mvCaptionRadius: 2px; mvCaptionBg: #11111180; mvCaptionFont: font(fsize); -medviewSaveMsgCheck: sprite(311px, 309px, 22px, 18px); +medviewSaveMsgCheck: icon { + { "mediaview_save_check", #ffffff } +}; medviewSaveMsgFont: font(16px); medviewSaveMsgPadding: margins(55px, 19px, 29px, 20px); medviewSaveMsgCheckPos: point(23px, 21px); diff --git a/Telegram/Resources/icons/mediaview_save_check.png b/Telegram/Resources/icons/mediaview_save_check.png new file mode 100644 index 0000000000000000000000000000000000000000..33be1af78102c3ad88a4e4164246cd3eaaa749e8 GIT binary patch literal 454 zcmV;%0XhDOP)rAFtUpcX-^5JYpj>#o}7636C# z3Ng>&z2`8=COf;|e%Z{9ZPFDixegCz5WrTSOv}TgJPzR4T!?ZIbTy zdqktrdyXL#3ZYmmz9h}(^RO(7q=sQ29*;k=vMgh@T7h$pbUOW~G?U4Ib52szG?7ZB zp7V>vfZ*ba5#+hdQEFW2vn=pSG(sj z@%#N4kH;iA9*@}Vc9c7g165VMwB=7CNfI`j4W322-S*n=?uA4m;d*@l=yW=sKhcBu w`m?Svo6X*lJ{L2_FdPmsolfEN`Q8$r0XFKIpfQA|kpKVy07*qoM6N<$g7Z4j9smFU literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/mediaview_save_check@2x.png b/Telegram/Resources/icons/mediaview_save_check@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d9d3bd85b711e17f3b232dc4d10a9b7402559f86 GIT binary patch literal 882 zcmV-&1C9KNP)*^y^>arqb|)9ySjwHa)pEgV zMJbBnLWnfdNu6@+?R;GH>9p9- zwZFe#Jm9ghF&Kuy#opcBp|Y~FIKch={a}o7vGI5uRaI4=*B2Js-Q5jc*ST0#RZ&-0 z_r0cYSVd8wX&M)+X&RcEnts<62HV)!h}YLwE>_odw6(RRtF<5N_xthk^1{V3#t;Yu zc=h&TeLf!^A0N3`!!R&3G$hKf59{@MaeI5q#R5Pu7|fJo57y)H;PUcPh@G9CHIw!8 zg_4qzoMYW?H%?Dah1kW#MYDNdPZUML`T032Dk^e@Eh{TSEEW@DS5{W6WF{Z<^z`8E z?F|4Bi^bq{I_V(a#IIQQdudj1M8Dr?`>ar9lNfK69SB2PUGzyo? z^|xQo;c(#a@Q@p>sw!$~YD@<%FE0zRCnqOxyWQCwx8yzY=H`a`Ay-#d@OV5K!{+AZ zgxHIV3sX56!9;}G+FD`f6p2KHXKrF*LWsS-zJ}N9%@+FwCL#m^0b$qAyI+osj0o%Q z@9*LB`Er5%2__=U&(90LsqyjgAJ_Nx_6nzkr>7_Q{r+5GQ^ArXVQXuP3wVEjhoUGT zB6M_gWSkZn8X9tmO$8GXTrL-mkB_;K=jUe(3=CwP7Ft?ba*a(7CQ7z~4-XGqkmwlb zx{l7y&U|3`V4~z0^VwgRU5qjG_4VZoD+Uu01_uXCV-3T==;&xZv6;a{gr%h=Q{c(T z$$VqYfn{07?(VJ-8w!Q&z?uUSC8vh7v$M3=gM$ORu;#%;$%!|SNTgsbHsJPwi3q`9 z@IN*hjaqNOv)nQf{UZzO=;(;b%gZT|NKk8QD>25blxMv@0D1;L)B#k0YybcN07*qo IM6N<$f{pC3P5=M^ literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 9f87cedca5..789bb5709b 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -685,9 +685,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_stickers_you_have" = "Manage and reorder sticker packs"; "lng_stickers_packs" = "Sticker Packs"; "lng_stickers_reorder" = "Click and drag to reorder sticker packs"; +"lng_stickers_featured" = "Featured Stickers"; "lng_stickers_remove" = "Delete"; "lng_stickers_return" = "Undo"; "lng_stickers_restore" = "Restore"; +"lng_stickers_add" = "Add"; "lng_stickers_count" = "{count:Loading...|# sticker|# stickers}"; "lng_in_dlg_photo" = "Photo"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index e0dc511359..e6c12b071b 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -924,10 +924,10 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) _stickerSetRequests.remove(setId); if (result.type() != mtpc_messages_stickerSet) return; - const auto &d(result.c_messages_stickerSet()); + auto &d(result.c_messages_stickerSet()); if (d.vset.type() != mtpc_stickerSet) return; - const auto &s(d.vset.c_stickerSet()); + auto &s(d.vset.c_stickerSet()); auto &sets = Global::RefStickerSets(); auto it = sets.find(setId); @@ -937,7 +937,7 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) it->hash = s.vhash.v; it->shortName = qs(s.vshort_name); it->title = stickerSetTitle(s); - auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded); + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded); it->flags = s.vflags.v | clientFlags; it->flags &= ~MTPDstickerSet_ClientFlag::f_not_loaded; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 256421f300..094759909a 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -1979,6 +1979,9 @@ namespace { Global::SetStickerSets(Stickers::Sets()); Global::SetStickerSetsOrder(Stickers::Order()); Global::SetLastStickersUpdate(0); + Global::SetFeaturedStickerSetsOrder(Stickers::Order()); + Global::SetFeaturedStickerSetsUnreadCount(0); + Global::SetLastFeaturedStickersUpdate(0); cSetSavedGifs(SavedGifs()); cSetLastSavedGifsUpdate(0); cSetReportSpamStatuses(ReportSpamStatuses()); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 0f23423d58..f87cf0a9b3 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "boxes/confirmbox.h" #include "apiwrap.h" #include "localstorage.h" +#include "dialogs/dialogs_layout.h" StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget() , _input(set) { @@ -47,21 +48,21 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { _pack.clear(); _emoji.clear(); if (set.type() == mtpc_messages_stickerSet) { - const auto &d(set.c_messages_stickerSet()); - const auto &v(d.vdocuments.c_vector().v); + auto &d(set.c_messages_stickerSet()); + auto &v(d.vdocuments.c_vector().v); _pack.reserve(v.size()); - for (int32 i = 0, l = v.size(); i < l; ++i) { - DocumentData *doc = App::feedDocument(v.at(i)); + for (int i = 0, l = v.size(); i < l; ++i) { + auto doc = App::feedDocument(v.at(i)); if (!doc || !doc->sticker()) continue; _pack.push_back(doc); } - const auto &packs(d.vpacks.c_vector().v); - for (int32 i = 0, l = packs.size(); i < l; ++i) { + auto &packs(d.vpacks.c_vector().v); + for (int i = 0, l = packs.size(); i < l; ++i) { if (packs.at(i).type() != mtpc_stickerPack) continue; - const auto &pack(packs.at(i).c_stickerPack()); - if (EmojiPtr e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) { - const auto &stickers(pack.vdocuments.c_vector().v); + auto &pack(packs.at(i).c_stickerPack()); + if (auto e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) { + auto &stickers(pack.vdocuments.c_vector().v); StickerPack p; p.reserve(stickers.size()); for (int32 j = 0, c = stickers.size(); j < c; ++j) { @@ -74,7 +75,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { } } if (d.vset.type() == mtpc_stickerSet) { - const auto &s(d.vset.c_stickerSet()); + auto &s(d.vset.c_stickerSet()); _setTitle = stickerSetTitle(s); _title = st::boxTitleFont->elided(_setTitle, width() - st::boxTitlePosition.x() - st::boxTitleHeight); _setShortName = qs(s.vshort_name); @@ -83,6 +84,15 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { _setCount = s.vcount.v; _setHash = s.vhash.v; _setFlags = s.vflags.v; + auto &sets = Global::RefStickerSets(); + auto it = sets.find(_setId); + if (it != sets.cend()) { + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_unread); + _setFlags |= clientFlags; + it->flags = _setFlags; + it->stickers = _pack; + it->emoji = _emoji; + } } } @@ -116,13 +126,13 @@ void StickerSetInner::installDone(const MTPBool &result) { if (it == sets.cend()) { it = sets.insert(_setId, Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)); } else { - it.value().flags = _setFlags; + it->flags = _setFlags; } - it.value().stickers = _pack; - it.value().emoji = _emoji; + it->stickers = _pack; + it->emoji = _emoji; auto &order = Global::RefStickerSetsOrder(); - int32 insertAtIndex = 0, currentIndex = order.indexOf(_setId); + int insertAtIndex = 0, currentIndex = order.indexOf(_setId); if (currentIndex != insertAtIndex) { if (currentIndex > 0) { order.removeAt(currentIndex); @@ -132,8 +142,8 @@ void StickerSetInner::installDone(const MTPBool &result) { auto custom = sets.find(Stickers::CustomSetId); if (custom != sets.cend()) { - for (int32 i = 0, l = _pack.size(); i < l; ++i) { - int32 removeIndex = custom->stickers.indexOf(_pack.at(i)); + for_const (auto sticker, _pack) { + int removeIndex = custom->stickers.indexOf(sticker); if (removeIndex >= 0) custom->stickers.removeAt(removeIndex); } if (custom->stickers.isEmpty()) { @@ -141,8 +151,8 @@ void StickerSetInner::installDone(const MTPBool &result) { } } Local::writeStickers(); + emit App::main()->stickersUpdated(); emit installed(_setId); - Ui::hideLayer(); } bool StickerSetInner::installFailed(const RPCError &error) { @@ -295,7 +305,7 @@ StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st:: connect(&_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons())); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); - connect(&_inner, SIGNAL(installed(uint64)), this, SIGNAL(installed(uint64))); + connect(&_inner, SIGNAL(installed(uint64)), this, SLOT(onInstalled(uint64))); onStickersUpdated(); @@ -304,6 +314,11 @@ StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st:: prepare(); } +void StickerSetBox::onInstalled(uint64 setId) { + emit installed(setId); + onClose(); +} + void StickerSetBox::onStickersUpdated() { showAll(); } @@ -392,28 +407,44 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) { } } -StickersInner::StickersInner() : TWidget() +namespace internal { + +StickersInner::StickersInner(StickersBox::Section section) : TWidget() +, _section(section) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) -, _aboveShadowFadeStart(0) -, _aboveShadowFadeOpacity(0, 0) , _a_shifting(animation(this, &StickersInner::step_shifting)) , _itemsTop(st::membersPadding.top()) -, _saving(false) -, _removeSel(-1) -, _removeDown(-1) , _removeWidth(st::normalFont->width(lang(lng_stickers_remove))) , _returnWidth(st::normalFont->width(lang(lng_stickers_return))) , _restoreWidth(st::normalFont->width(lang(lng_stickers_restore))) -, _selected(-1) -, _started(-1) -, _dragging(-1) -, _above(-1) -, _aboveShadow(st::boxShadow) -, _scrollbar(0) { +, _addText(lang(lng_stickers_add).toUpper()) +, _addWidth(st::defaultActiveButton.font->width(_addText)) +, _aboveShadow(st::boxShadow) { connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); setMouseTracking(true); } +void StickersInner::paintFeaturedButton(Painter &p) const { + if (!_featuredHeight) return; + + if (_selected == -1) { + p.fillRect(0, st::membersPadding.top(), width(), _featuredHeight, st::contactsBgOver); + } + p.setFont(st::stickersFeaturedFont); + p.setPen(st::stickersFeaturedPen); + p.drawTextLeft(st::stickersFeaturedPosition.x(), st::membersPadding.top() + st::stickersFeaturedPosition.y(), width(), lang(lng_stickers_featured)); + + if (auto unread = Global::FeaturedStickerSetsUnreadCount()) { + Dialogs::Layout::UnreadBadgeStyle unreadSt; + unreadSt.sizeId = Dialogs::Layout::UnreadBadgeInStickersBox; + unreadSt.size = st::stickersFeaturedBadgeSize; + int unreadRight = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x()); + if (rtl()) unreadRight = width() - unreadRight; + int unreadTop = st::membersPadding.top() + (_featuredHeight - st::stickersFeaturedBadgeSize) / 2; + Dialogs::Layout::paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, unreadSt); + } +} + void StickersInner::paintEvent(QPaintEvent *e) { QRect r(e->rect()); Painter p(this); @@ -422,10 +453,13 @@ void StickersInner::paintEvent(QPaintEvent *e) { p.fillRect(r, st::white); p.setClipRect(r); + + paintFeaturedButton(p); + if (_rows.isEmpty()) { - p.setFont(st::noContactsFont->f); - p.setPen(st::noContactsColor->p); - p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); + p.setFont(st::noContactsFont); + p.setPen(st::noContactsColor); + p.drawText(QRect(0, _featuredHeight, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); } else { p.translate(0, _itemsTop); @@ -452,33 +486,50 @@ void StickersInner::paintRow(Painter &p, int32 index) { int32 xadd = 0, yadd = s->yadd.current(); if (xadd || yadd) p.translate(xadd, yadd); - bool removeSel = (index == _removeSel && (_removeDown < 0 || index == _removeDown)); - bool removeDown = removeSel && (index == _removeDown); + if (_section == Section::Installed) { + bool removeSel = (index == _actionSel && (_actionDown < 0 || index == _actionDown)); + bool removeDown = removeSel && (index == _actionDown); - p.setFont((removeSel ? st::linkOverFont : st::linkFont)->f); - if (removeDown) { - p.setPen(st::btnDefLink.downColor->p); - } else { - p.setPen(st::btnDefLink.color->p); - } - int32 remWidth = s->disabled ? (s->official ? _restoreWidth : _returnWidth) : _removeWidth; - QString remText = lang(s->disabled ? (s->official ? lng_stickers_restore : lng_stickers_return) : lng_stickers_remove); - p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), remText, remWidth); - - if (index == _above) { - float64 current = _aboveShadowFadeOpacity.current(); - if (_started >= 0) { - float64 o = aboveShadowOpacity(); - if (o > current) { - _aboveShadowFadeOpacity = anim::fvalue(o, o); - current = o; - } + p.setFont(removeSel ? st::linkOverFont : st::linkFont); + if (removeDown) { + p.setPen(st::btnDefLink.downColor); + } else { + p.setPen(st::btnDefLink.color); } - p.setOpacity(current); - QRect row(myrtlrect(_aboveShadow.getDimensions(st::boxShadowShift).left(), st::contactsPadding.top() / 2, width() - (st::contactsPadding.left() / 2) - _scrollbar - _aboveShadow.getDimensions(st::boxShadowShift).right(), _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2))); - _aboveShadow.paint(p, row, st::boxShadowShift); - p.fillRect(row, st::white); - p.setOpacity(1); + int32 remWidth = s->disabled ? (s->official ? _restoreWidth : _returnWidth) : _removeWidth; + QString remText = lang(s->disabled ? (s->official ? lng_stickers_restore : lng_stickers_return) : lng_stickers_remove); + p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), remText, remWidth); + + if (index == _above) { + float64 current = _aboveShadowFadeOpacity.current(); + if (_started >= 0) { + float64 o = aboveShadowOpacity(); + if (o > current) { + _aboveShadowFadeOpacity = anim::fvalue(o, o); + current = o; + } + } + p.setOpacity(current); + QRect row(myrtlrect(_aboveShadow.getDimensions(st::boxShadowShift).left(), st::contactsPadding.top() / 2, width() - (st::contactsPadding.left() / 2) - _scrollbar - _aboveShadow.getDimensions(st::boxShadowShift).right(), _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2))); + _aboveShadow.paint(p, row, st::boxShadowShift); + p.fillRect(row, st::white); + p.setOpacity(1); + } + } else if (s->installed) { + int addw = _addWidth - st::defaultActiveButton.width; + int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (addw + st::stickersFeaturedInstalled.width()) / 2); + int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2; + st::stickersFeaturedInstalled.paint(p, QPoint(checkx, checky), width()); + } else { + int addw = _addWidth - st::defaultActiveButton.width; + int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw; + int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2; + QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.height)); + + App::roundRect(p, add, st::defaultActiveButton.textBgOver); + p.setFont(st::defaultActiveButton.font); + p.setPen(st::defaultActiveButton.textFg); + p.drawTextLeft(addx - st::defaultActiveButton.width / 2, addy + st::defaultActiveButton.textTop, width(), _addText, _addWidth); } if (s->disabled) p.setOpacity(st::stickersRowDisabledOpacity); @@ -487,15 +538,28 @@ void StickersInner::paintRow(Painter &p, int32 index) { QPixmap pix(s->sticker->thumb->pix(s->pixw, s->pixh)); p.drawPixmapLeft(st::contactsPadding.left() + (st::contactsPhotoSize - s->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - s->pixh) / 2, width(), pix); } + + int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); + int namey = st::contactsPadding.top() + st::contactsNameTop; + int statusx = namex; + int statusy = st::contactsPadding.top() + st::contactsStatusTop; + + if (s->unread) { + p.setPen(Qt::NoPen); + p.setBrush(st::stickersFeaturedUnreadBg); + + p.setRenderHint(QPainter::HighQualityAntialiasing, true); + p.drawEllipse(rtlrect(namex, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width())); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + namex += st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; + } p.setFont(st::contactsNameFont); p.setPen(st::black); - - int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); - p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsNameTop, width(), s->title); + p.drawTextLeft(namex, namey, width(), s->title); p.setFont(st::contactsStatusFont); p.setPen(st::contactsStatusFg); - p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), lng_stickers_count(lt_count, s->count)); + p.drawTextLeft(statusx, statusy, width(), lng_stickers_count(lt_count, s->count)); p.setOpacity(1); if (xadd || yadd) p.translate(-xadd, -yadd); @@ -506,10 +570,12 @@ void StickersInner::mousePressEvent(QMouseEvent *e) { if (_dragging >= 0) mouseReleaseEvent(e); _mouse = e->globalPos(); onUpdateSelected(); - if (_removeSel >= 0) { - _removeDown = _removeSel; - update(0, _itemsTop + _removeSel * _rowHeight, width(), _rowHeight); - } else if (_selected >= 0) { + + _pressed = _selected; + if (_actionSel >= 0) { + _actionDown = _actionSel; + update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); + } else if (_selected >= 0 && _section == Section::Installed) { _above = _dragging = _started = _selected; _dragStart = mapFromGlobal(_mouse); } @@ -557,15 +623,39 @@ void StickersInner::onUpdateSelected() { emit checkDraggingScroll(local.y()); } else { bool in = rect().marginsRemoved(QMargins(0, _itemsTop, 0, st::membersPadding.bottom())).contains(local); - _selected = in ? floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1) : -1; - int32 removeSel = -1; + int selected = -2; + int actionSel = -1; + if (in) { + selected = floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1); - if (_selected >= 0) { - int32 remw = _rows.at(_selected)->disabled ? (_rows.at(_selected)->official ? _restoreWidth : _returnWidth) : _removeWidth; - QRect rem(myrtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - remw, st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, remw, st::normalFont->height)); - removeSel = rem.contains(local.x(), local.y() - _itemsTop - _selected * _rowHeight) ? _selected : -1; + if (_section == Section::Installed) { + int remw = _rows.at(selected)->disabled ? (_rows.at(selected)->official ? _restoreWidth : _returnWidth) : _removeWidth; + QRect rem(myrtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - remw, st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, remw, st::normalFont->height)); + actionSel = rem.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1; + } else if (_rows.at(selected)->installed) { + actionSel = -1; + } else { + int addw = _addWidth - st::defaultActiveButton.width; + int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw; + int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2; + QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.height)); + actionSel = add.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1; + } + } else if (_featuredHeight && QRect(0, st::membersPadding.top(), width(), _featuredHeight).contains(local)) { + selected = -1; + } else { + selected = -2; } - setRemoveSel(removeSel); + if (_selected != selected) { + if ((_selected == -1) != (selected == -1)) { + update(); + } + if (_section == Section::Featured && ((_selected >= 0 || _pressed >= 0) != (selected >= 0 || _pressed >= 0))) { + setCursor((selected >= 0 || _pressed >= 0) ? style::cur_pointer : style::cur_default); + } + _selected = selected; + } + setActionSel(actionSel); emit noDraggingScroll(); } } @@ -579,11 +669,23 @@ float64 StickersInner::aboveShadowOpacity() const { } void StickersInner::mouseReleaseEvent(QMouseEvent *e) { + auto pressed = _pressed; + _pressed = -2; + + if (_section == Section::Featured && _selected < 0 && pressed >= 0) { + setCursor(style::cur_default); + } + if (_saving) return; + _mouse = e->globalPos(); onUpdateSelected(); - if (_removeDown == _removeSel && _removeSel >= 0) { - _rows[_removeDown]->disabled = !_rows[_removeDown]->disabled; + if (_actionDown == _actionSel && _actionSel >= 0) { + if (_section == Section::Installed) { + _rows[_actionDown]->disabled = !_rows[_actionDown]->disabled; + } else { + installSet(_rows[_actionDown]->id); + } } else if (_dragging >= 0) { QPoint local(mapFromGlobal(_mouse)); _rows[_dragging]->yadd.start(0); @@ -594,13 +696,66 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) { } _dragging = _started = -1; + } else if (pressed == _selected) { + if (_selected == -1) { + _selected = -2; + Ui::showLayer(new StickersBox(Section::Featured), KeepOtherLayers); + } else if (_selected >= 0 && _section == Section::Featured) { + auto &sets = Global::RefStickerSets(); + auto it = sets.find(_rows.at(pressed)->id); + if (it != sets.cend()) { + _selected = -2; + Ui::showLayer(new StickerSetBox(Stickers::inputSetId(*it)), KeepOtherLayers); + } + } } - if (_removeDown >= 0) { - update(0, _itemsTop + _removeDown * _rowHeight, width(), _rowHeight); - _removeDown = -1; + if (_actionDown >= 0) { + update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight); + _actionDown = -1; } } +void StickersInner::leaveEvent(QEvent *e) { + _mouse = QPoint(-1, -1); + onUpdateSelected(); +} + +void StickersInner::installSet(uint64 setId) { + auto &sets = Global::RefStickerSets(); + auto it = sets.find(setId); + if (it == sets.cend()) { + rebuild(); + return; + } + + MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse())); + + it->flags &= ~(MTPDstickerSet::Flag::f_disabled | MTPDstickerSet_ClientFlag::f_unread); + it->flags |= MTPDstickerSet::Flag::f_installed; + + auto &order = Global::RefStickerSetsOrder(); + int insertAtIndex = 0, currentIndex = order.indexOf(setId); + if (currentIndex != insertAtIndex) { + if (currentIndex > 0) { + order.removeAt(currentIndex); + } + order.insert(insertAtIndex, setId); + } + + auto custom = sets.find(Stickers::CustomSetId); + if (custom != sets.cend()) { + for_const (auto sticker, it->stickers) { + int removeIndex = custom->stickers.indexOf(sticker); + if (removeIndex >= 0) custom->stickers.removeAt(removeIndex); + } + if (custom->stickers.isEmpty()) { + sets.erase(custom); + } + } + Local::writeStickers(); + emit App::main()->stickersUpdated(); +} + void StickersInner::step_shifting(uint64 ms, bool timer) { bool animating = false; int32 updateMin = -1, updateMax = 0; @@ -653,72 +808,123 @@ void StickersInner::clear() { _aboveShadowFadeStart = 0; _aboveShadowFadeOpacity = anim::fvalue(0, 0); _a_shifting.stop(); - _above = _dragging = _started = -1; - _selected = -1; - _removeDown = -1; - setRemoveSel(-1); - update(); +_above = _dragging = _started = -1; +_selected = -2; +_pressed = -2; +_actionDown = -1; +setActionSel(-1); +update(); } -void StickersInner::setRemoveSel(int32 removeSel) { - if (removeSel != _removeSel) { - if (_removeSel >= 0) update(0, _itemsTop + _removeSel * _rowHeight, width(), _rowHeight); - _removeSel = removeSel; - if (_removeSel >= 0) update(0, _itemsTop + _removeSel * _rowHeight, width(), _rowHeight); - setCursor((_removeSel >= 0 && (_removeDown < 0 || _removeDown == _removeSel)) ? style::cur_pointer : style::cur_default); +void StickersInner::setActionSel(int32 actionSel) { + if (actionSel != _actionSel) { + if (_actionSel >= 0) update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); + _actionSel = actionSel; + if (_actionSel >= 0) update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); + if (_section == Section::Installed) { + setCursor((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel)) ? style::cur_pointer : style::cur_default); + } } } void StickersInner::rebuild() { QList rows, rowsDisabled; - int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); - int32 namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x() - qMax(qMax(_returnWidth, _removeWidth), _restoreWidth); + _itemsTop = st::membersPadding.top(); + _featuredHeight = 0; + if (_section == Section::Installed && !Global::FeaturedStickerSetsOrder().isEmpty()) { + _featuredHeight = st::stickersFeaturedHeight; + _itemsTop += _featuredHeight + st::membersPadding.top(); + } + + int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); + int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); + if (_section == Section::Installed) { + namew -= qMax(qMax(_returnWidth, _removeWidth), _restoreWidth); + } else { + namew -= _addWidth - st::defaultActiveButton.width; + } clear(); - auto &order = Global::StickerSetsOrder(); + auto &order = (_section == Section::Installed) ? Global::StickerSetsOrder() : Global::FeaturedStickerSetsOrder(); _animStartTimes.reserve(order.size()); auto &sets = Global::StickerSets(); - for (int i = 0, l = order.size(); i < l; ++i) { - auto it = sets.constFind(order.at(i)); - if (it != sets.cend()) { - bool disabled = (it->flags & MTPDstickerSet::Flag::f_disabled); + for_const (auto setId, order) { + auto it = sets.constFind(setId); + if (it == sets.cend()) { + continue; + } - DocumentData *sticker = it->stickers.isEmpty() ? 0 : it->stickers.at(0); - int32 pixw = 0, pixh = 0; - if (sticker) { - pixw = sticker->thumb->width(); - pixh = sticker->thumb->height(); - if (pixw > st::contactsPhotoSize) { - if (pixw > pixh) { - pixh = (pixh * st::contactsPhotoSize) / pixw; - pixw = st::contactsPhotoSize; - } else { - pixw = (pixw * st::contactsPhotoSize) / pixh; - pixh = st::contactsPhotoSize; - } - } else if (pixh > st::contactsPhotoSize) { + bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); + bool disabled = (_section == Section::Installed) && (it->flags & MTPDstickerSet::Flag::f_disabled); + bool official = (it->flags & MTPDstickerSet::Flag::f_official); + bool unread = (_section == Section::Featured) && _unreadSets.contains(it->id); + if (!unread && _section == Section::Featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { + unread = true; + _unreadSets.insert(it->id); + } + + DocumentData *sticker = it->stickers.isEmpty() ? 0 : it->stickers.at(0); + int32 pixw = 0, pixh = 0; + if (sticker) { + pixw = sticker->thumb->width(); + pixh = sticker->thumb->height(); + if (pixw > st::contactsPhotoSize) { + if (pixw > pixh) { + pixh = (pixh * st::contactsPhotoSize) / pixw; + pixw = st::contactsPhotoSize; + } else { pixw = (pixw * st::contactsPhotoSize) / pixh; pixh = st::contactsPhotoSize; } + } else if (pixh > st::contactsPhotoSize) { + pixw = (pixw * st::contactsPhotoSize) / pixh; + pixh = st::contactsPhotoSize; } - QString title = it->title; - int32 titleWidth = st::contactsNameFont->width(title); - if (titleWidth > namew) { - title = st::contactsNameFont->elided(title, namew); - } - bool official = (it->flags & MTPDstickerSet::Flag::f_official); - (disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, official, disabled, pixw, pixh)); - _animStartTimes.push_back(0); - if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { - App::api()->scheduleStickerSetRequest(it->id, it->access); - } + } + QString title = it->title; + int32 titleWidth = st::contactsNameFont->width(title); + if (titleWidth > namew) { + title = st::contactsNameFont->elided(title, namew); + } + (disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, installed, official, unread, disabled, pixw, pixh)); + _animStartTimes.push_back(0); + if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + App::api()->scheduleStickerSetRequest(it->id, it->access); } } App::api()->requestStickerSets(); _rows = rows + rowsDisabled; resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom()); + + if (_section == Section::Featured && Global::FeaturedStickerSetsUnreadCount()) { + Global::SetFeaturedStickerSetsUnreadCount(0); + for (auto &set : Global::RefStickerSets()) { + set.flags &= ~MTPDstickerSet_ClientFlag::f_unread; + } + MTP::send(MTPmessages_ReadFeaturedStickers(), rpcDone(&StickersInner::readFeaturedDone), rpcFail(&StickersInner::readFeaturedFail)); + } +} + +void StickersInner::readFeaturedDone(const MTPBool &result) { + Local::writeStickers(); + emit App::main()->stickersUpdated(); +} + +bool StickersInner::readFeaturedFail(const RPCError &error) { + if (MTP::isDefaultHandledError(error)) return false; + + int unreadCount = 0; + for_const (auto &set, Global::StickerSets()) { + if (!(set.flags & MTPDstickerSet::Flag::f_installed)) { + if (set.flags & MTPDstickerSet_ClientFlag::f_unread) { + ++unreadCount; + } + } + } + Global::SetFeaturedStickerSetsUnreadCount(unreadCount); + return true; } QVector StickersInner::getOrder() const { @@ -755,27 +961,38 @@ StickersInner::~StickersInner() { clear(); } -StickersBox::StickersBox() : ItemListBox(st::boxScroll) -, _save(this, lang(lng_settings_save), st::defaultBoxButton) -, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +} // namespace internal + +StickersBox::StickersBox(Section section) : ItemListBox(st::boxScroll) +, _section(section) +, _inner(section) , _reorderRequest(0) , _topShadow(this, st::contactsAboutShadow) -, _bottomShadow(this) , _scrollDelta(0) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) -, _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) -, _aboutHeight(st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom()) { - ItemListBox::init(&_inner, st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(), st::boxTitleHeight + _aboutHeight); +, _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) { + + int bottomSkip = st::boxPadding.bottom(); + if (_section == Section::Installed) { + _aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom(); + + _save = new BoxButton(this, lang(lng_settings_save), st::defaultBoxButton); + connect(_save, SIGNAL(clicked()), this, SLOT(onSave())); + + _cancel = new BoxButton(this, lang(lng_cancel), st::cancelBoxButton); + connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + + _bottomShadow = new ScrollableBoxShadow(this); + bottomSkip = st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom(); + } + ItemListBox::init(_inner, bottomSkip, st::boxTitleHeight + _aboutHeight); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated())); App::main()->updateStickers(); - connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); - connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); - - connect(&_inner, SIGNAL(checkDraggingScroll(int)), this, SLOT(onCheckDraggingScroll(int))); - connect(&_inner, SIGNAL(noDraggingScroll()), this, SLOT(onNoDraggingScroll())); + connect(_inner, SIGNAL(checkDraggingScroll(int)), this, SLOT(onCheckDraggingScroll(int))); + connect(_inner, SIGNAL(noDraggingScroll()), this, SLOT(onNoDraggingScroll())); connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer())); _scrollTimer.setSingleShot(false); @@ -785,7 +1002,11 @@ StickersBox::StickersBox() : ItemListBox(st::boxScroll) } int32 StickersBox::countHeight() const { - return st::boxTitleHeight + _aboutHeight + _inner.height() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); + int bottomSkip = st::boxPadding.bottom(); + if (_section == Section::Installed) { + bottomSkip = st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom(); + } + return st::boxTitleHeight + _aboutHeight + _inner->height() + bottomSkip; } void StickersBox::disenableDone(const MTPBool & result, mtpRequestId req) { @@ -805,7 +1026,7 @@ bool StickersBox::disenableFail(const RPCError &error, mtpRequestId req) { } void StickersBox::saveOrder() { - QVector order = _inner.getOrder(); + auto order = _inner->getOrder(); if (order.size() > 1) { QVector mtpOrder; mtpOrder.reserve(order.size()); @@ -839,9 +1060,11 @@ void StickersBox::paintEvent(QPaintEvent *e) { paintTitle(p, lang(lng_stickers_packs)); p.translate(0, st::boxTitleHeight); - p.fillRect(0, 0, width(), _aboutHeight, st::contactsAboutBg); - p.setPen(st::stickersReorderFg); - _about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center); + if (_aboutHeight > 0) { + p.fillRect(0, 0, width(), _aboutHeight, st::contactsAboutBg); + p.setPen(st::stickersReorderFg); + _about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center); + } } void StickersBox::closePressed() { @@ -862,18 +1085,20 @@ void StickersBox::closePressed() { void StickersBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); - _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); - _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); - _inner.resize(width(), _inner.height()); + _inner->resize(width(), _inner->height()); _topShadow.setGeometry(0, st::boxTitleHeight + _aboutHeight, width(), st::lineWidth); - _bottomShadow.setGeometry(0, height() - st::boxButtonPadding.bottom() - _save.height() - st::boxButtonPadding.top() - st::lineWidth, width(), st::lineWidth); - _inner.setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); + _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); + if (_save) { + _save->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save->height()); + _cancel->moveToRight(st::boxButtonPadding.right() + _save->width() + st::boxButtonPadding.left(), _save->y()); + _bottomShadow->setGeometry(0, height() - st::boxButtonPadding.bottom() - _save->height() - st::boxButtonPadding.top() - st::lineWidth, width(), st::lineWidth); + } } void StickersBox::onStickersUpdated() { - _inner.rebuild(); + _inner->rebuild(); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); - _inner.setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); + _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); } void StickersBox::onCheckDraggingScroll(int localY) { @@ -901,7 +1126,7 @@ void StickersBox::onScrollTimer() { } void StickersBox::onSave() { - if (!_inner.savingStart()) { + if (!_inner->savingStart()) { return; } @@ -909,7 +1134,7 @@ void StickersBox::onSave() { RecentStickerPack &recent(cGetRecentStickers()); auto &sets = Global::RefStickerSets(); - QVector reorder = _inner.getOrder(), disabled = _inner.getDisabledSets(); + QVector reorder = _inner->getOrder(), disabled = _inner->getDisabledSets(); for (int32 i = 0, l = disabled.size(); i < l; ++i) { auto it = sets.find(disabled.at(i)); if (it != sets.cend()) { @@ -932,12 +1157,20 @@ void StickersBox::onSave() { if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)) { sets.erase(it); + } else { + it->flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet::Flag::f_disabled); } } } } } - Stickers::Order &order(Global::RefStickerSetsOrder()); + + // Clear all installed flags, set only for sets from order. + for (auto &set : sets) { + set.flags &= ~MTPDstickerSet::Flag::f_installed; + } + + auto &order(Global::RefStickerSetsOrder()); order.clear(); for (int i = 0, l = reorder.size(); i < l; ++i) { auto it = sets.find(reorder.at(i)); @@ -948,13 +1181,14 @@ void StickersBox::onSave() { it->flags &= ~MTPDstickerSet::Flag::f_disabled; } order.push_back(reorder.at(i)); + it->flags |= MTPDstickerSet::Flag::f_installed; } } for (auto it = sets.begin(); it != sets.cend();) { if (it->id == Stickers::CustomSetId || it->id == Stickers::RecentSetId || (it->flags & MTPDstickerSet_ClientFlag::f_featured) - || order.contains(it->id)) { + || (it->flags & MTPDstickerSet::Flag::f_installed)) { ++it; } else { it = sets.erase(it); @@ -973,18 +1207,22 @@ void StickersBox::onSave() { } void StickersBox::hideAll() { - _save.hide(); - _cancel.hide(); _topShadow.hide(); - _bottomShadow.hide(); + if (_save) { + _save->hide(); + _cancel->hide(); + _bottomShadow->hide(); + } ItemListBox::hideAll(); } void StickersBox::showAll() { - _save.show(); - _cancel.show(); _topShadow.show(); - _bottomShadow.show(); + if (_save) { + _save->show(); + _cancel->show(); + _bottomShadow->show(); + } ItemListBox::showAll(); } diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 9b6cd98918..1c8e9590d8 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -95,7 +95,6 @@ public: void resizeEvent(QResizeEvent *e); public slots: - void onStickersUpdated(); void onAddStickers(); void onShareStickers(); @@ -103,115 +102,38 @@ public slots: void onScroll(); -signals: +private slots: + void onInstalled(uint64 id); +signals: void installed(uint64 id); protected: - void hideAll(); void showAll(); private: - StickerSetInner _inner; ScrollableBoxShadow _shadow; BoxButton _add, _share, _cancel, _done; QString _title; + }; -class StickersInner : public TWidget { - Q_OBJECT - -public: - - StickersInner(); - - void paintEvent(QPaintEvent *e); - void mousePressEvent(QMouseEvent *e); - void mouseMoveEvent(QMouseEvent *e); - void mouseReleaseEvent(QMouseEvent *e); - - void rebuild(); - bool savingStart() { - if (_saving) return false; - _saving = true; - return true; - } - - QVector getOrder() const; - QVector getDisabledSets() const; - - void setVisibleScrollbar(int32 width); - - ~StickersInner(); - -signals: - - void checkDraggingScroll(int localY); - void noDraggingScroll(); - -public slots: - - void onUpdateSelected(); - -private: - - void step_shifting(uint64 ms, bool timer); - void paintRow(Painter &p, int32 index); - void clear(); - void setRemoveSel(int32 removeSel); - float64 aboveShadowOpacity() const; - - int32 _rowHeight; - struct StickerSetRow { - StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, bool official, bool disabled, int32 pixw, int32 pixh) : id(id) - , sticker(sticker) - , count(count) - , title(title) - , official(official) - , disabled(disabled) - , pixw(pixw) - , pixh(pixh) - , yadd(0, 0) { - } - uint64 id; - DocumentData *sticker; - int32 count; - QString title; - bool official, disabled; - int32 pixw, pixh; - anim::ivalue yadd; - }; - typedef QList StickerSetRows; - StickerSetRows _rows; - QList _animStartTimes; - uint64 _aboveShadowFadeStart; - anim::fvalue _aboveShadowFadeOpacity; - Animation _a_shifting; - - int32 _itemsTop; - - bool _saving; - - int32 _removeSel, _removeDown, _removeWidth, _returnWidth, _restoreWidth; - - QPoint _mouse; - int32 _selected; - QPoint _dragStart; - int32 _started, _dragging, _above; - - BoxShadow _aboveShadow; - - int32 _scrollbar; -}; +namespace internal { +class StickersInner; +} // namespace internal class StickersBox : public ItemListBox, public RPCSender { Q_OBJECT public: - StickersBox(); + enum class Section { + Installed, + Featured, + }; + StickersBox(Section section = Section::Installed); void resizeEvent(QResizeEvent *e); void paintEvent(QPaintEvent *e); @@ -242,20 +164,135 @@ private: bool reorderFail(const RPCError &result); void saveOrder(); - StickersInner _inner; - BoxButton _save, _cancel; + Section _section; + + ChildWidget _inner; + ChildWidget _save = { nullptr }; + ChildWidget _cancel = { nullptr }; QMap _disenableRequests; mtpRequestId _reorderRequest; PlainShadow _topShadow; - ScrollableBoxShadow _bottomShadow; + ChildWidget _bottomShadow = { nullptr }; QTimer _scrollTimer; int32 _scrollDelta; - int32 _aboutWidth; + int _aboutWidth = 0; Text _about; - int32 _aboutHeight; + int _aboutHeight = 0; }; int32 stickerPacksCount(bool includeDisabledOfficial = false); + +namespace internal { + +class StickersInner : public TWidget, public RPCSender { + Q_OBJECT + +public: + using Section = StickersBox::Section; + StickersInner(Section section); + + void rebuild(); + bool savingStart() { + if (_saving) return false; + _saving = true; + return true; + } + + QVector getOrder() const; + QVector getDisabledSets() const; + + void setVisibleScrollbar(int32 width); + + ~StickersInner(); + +protected: + void paintEvent(QPaintEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void leaveEvent(QEvent *e) override; + +signals: + void checkDraggingScroll(int localY); + void noDraggingScroll(); + +public slots: + void onUpdateSelected(); + +private: + void paintFeaturedButton(Painter &p) const; + + void step_shifting(uint64 ms, bool timer); + void paintRow(Painter &p, int32 index); + void clear(); + void setActionSel(int32 actionSel); + float64 aboveShadowOpacity() const; + + void installSet(uint64 setId); + void readFeaturedDone(const MTPBool &result); + bool readFeaturedFail(const RPCError &error); + + Section _section; + + int32 _rowHeight; + struct StickerSetRow { + StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, bool installed, bool official, bool unread, bool disabled, int32 pixw, int32 pixh) : id(id) + , sticker(sticker) + , count(count) + , title(title) + , installed(installed) + , official(official) + , unread(unread) + , disabled(disabled) + , pixw(pixw) + , pixh(pixh) + , yadd(0, 0) { + } + uint64 id; + DocumentData *sticker; + int32 count; + QString title; + bool installed, official, unread, disabled; + int32 pixw, pixh; + anim::ivalue yadd; + }; + typedef QList StickerSetRows; + StickerSetRows _rows; + QList _animStartTimes; + uint64 _aboveShadowFadeStart = 0; + anim::fvalue _aboveShadowFadeOpacity = { 0., 0. }; + Animation _a_shifting; + + int32 _itemsTop; + + bool _saving = false; + + int _actionSel = -1; + int _actionDown = -1; + + int _removeWidth, _returnWidth, _restoreWidth; + + QString _addText; + int _addWidth; + + int _featuredHeight = 0; + // Remember all the unread set ids to display unread dots. + OrderedSet _unreadSets; + + QPoint _mouse; + int _selected = -2; // -1 - featured stickers button + int _pressed = -2; + QPoint _dragStart; + int _started = -1; + int _dragging = -1; + int _above = -1; + + BoxShadow _aboveShadow; + + int32 _scrollbar = 0; +}; + +} // namespace internal diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index cc9afe6d61..ef1c72478f 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -29,7 +29,6 @@ dialogsUnreadBgActive: #ffffff; dialogsUnreadBgMutedActive: #d3e2ee; dialogsUnreadFont: font(12px bold); dialogsUnreadHeight: 19px; -dialogsUnreadTop: 1px; dialogsUnreadPadding: 5px; dialogsBg: windowBg; diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 8591ea74e5..ff70439639 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -222,7 +222,7 @@ void paintUnreadCount(Painter &p, const QString &text, int x, int y, const Unrea p.setFont(st.font); p.setPen(st.active ? st::dialogsUnreadFgActive : st::dialogsUnreadFg); - p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + st::dialogsUnreadTop + st.font->ascent, text); + p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + (unreadRectHeight - st.font->height) / 2 + st.font->ascent, text); } void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) { @@ -258,7 +258,7 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele auto counter = QString::number(unreadCount); auto mutedCounter = history->mute(); int unreadRight = w - st::dialogsPadding.x(); - int unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - st::dialogsUnreadTop; + int unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2; int unreadWidth = 0; UnreadBadgeStyle st; @@ -297,7 +297,7 @@ void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool o int unreadTop = (st::dialogsImportantBarHeight - st::dialogsUnreadHeight) / 2; bool mutedHidden = (current == Dialogs::Mode::Important); QString text = mutedHidden ? qsl("Show all chats") : qsl("Hide muted chats"); - int textBaseline = unreadTop + st::dialogsUnreadTop + st::dialogsUnreadFont->ascent; + int textBaseline = unreadTop + (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2 + st::dialogsUnreadFont->ascent; p.drawText(st::dialogsPadding.x(), textBaseline, text); if (mutedHidden) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.h b/Telegram/SourceFiles/dialogs/dialogs_layout.h index b0e5bd8b10..f083f062fe 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.h +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.h @@ -38,6 +38,8 @@ void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool o enum UnreadBadgeSize { UnreadBadgeInDialogs = 0, UnreadBadgeInHistoryToDown, + UnreadBadgeInStickersPanel, + UnreadBadgeInStickersBox, UnreadBadgeSizesCount }; diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index d4db768d28..fd31b7c85b 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "boxes/stickersetbox.h" #include "inline_bots/inline_bot_result.h" #include "inline_bots/inline_bot_layout_item.h" +#include "dialogs/dialogs_layout.h" #include "historywidget.h" #include "localstorage.h" #include "lang.h" @@ -2829,6 +2830,20 @@ void EmojiPan::onSaveConfigDelayed(int32 delay) { _saveConfigTimer.start(delay); } +void EmojiPan::paintStickerSettingsIcon(Painter &p) const { + int settingsLeft = _iconsLeft + 7 * st::rbEmoji.width; + p.drawSpriteLeft(settingsLeft + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::stickersSettings); + if (auto unread = Global::FeaturedStickerSetsUnreadCount()) { + Dialogs::Layout::UnreadBadgeStyle unreadSt; + unreadSt.sizeId = Dialogs::Layout::UnreadBadgeInStickersPanel; + unreadSt.size = st::stickersSettingsUnreadSize; + int unreadRight = settingsLeft + st::rbEmoji.width - st::stickersSettingsUnreadPosition.x(); + if (rtl()) unreadRight = width() - unreadRight; + int unreadTop = _iconsTop + st::stickersSettingsUnreadPosition.y(); + Dialogs::Layout::paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, unreadSt); + } +} + void EmojiPan::paintEvent(QPaintEvent *e) { Painter p(this); @@ -2846,7 +2861,7 @@ void EmojiPan::paintEvent(QPaintEvent *e) { p.fillRect(myrtlrect(r.x() + r.width() - st::emojiScroll.width, r.y(), st::emojiScroll.width, e_scroll.height()), st::white->b); if (_stickersShown && s_inner.showSectionIcons()) { p.fillRect(r.left(), _iconsTop, r.width(), st::rbEmoji.height, st::emojiPanCategories); - p.drawSpriteLeft(_iconsLeft + 7 * st::rbEmoji.width + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::stickersSettings); + paintStickerSettingsIcon(p); if (!_icons.isEmpty()) { int32 x = _iconsLeft, i = 0, selxrel = _iconsLeft + _iconSelX.current(), selx = selxrel - _iconsX.current(); @@ -3093,6 +3108,7 @@ void EmojiPan::refreshStickers() { if (!_stickersShown) { s_inner.preloadImages(); } + update(); } void EmojiPan::refreshSavedGifs() { diff --git a/Telegram/SourceFiles/dropdown.h b/Telegram/SourceFiles/dropdown.h index 32faf35687..dfd81a7cfd 100644 --- a/Telegram/SourceFiles/dropdown.h +++ b/Telegram/SourceFiles/dropdown.h @@ -656,6 +656,7 @@ signals: void updateStickers(); private: + void paintStickerSettingsIcon(Painter &p) const; void validateSelectedIcon(bool animated = false); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 3e1a181430..58175e636b 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -561,7 +561,7 @@ struct Data { Stickers::Order StickerSetsOrder; uint64 LastStickersUpdate = 0; Stickers::Order FeaturedStickerSetsOrder; - Stickers::UnreadMap FeaturedUnreadSets; + int FeaturedStickerSetsUnreadCount = 0; uint64 LastFeaturedStickersUpdate = 0; MTP::DcOptions DcOptions; @@ -630,7 +630,7 @@ DefineVar(Global, Stickers::Sets, StickerSets); DefineVar(Global, Stickers::Order, StickerSetsOrder); DefineVar(Global, uint64, LastStickersUpdate); DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder); -DefineVar(Global, Stickers::UnreadMap, FeaturedUnreadSets); +DefineVar(Global, int, FeaturedStickerSetsUnreadCount); DefineVar(Global, uint64, LastFeaturedStickersUpdate); DefineVar(Global, MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index f8831e798f..71cd432e58 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -199,7 +199,13 @@ struct Set { }; using Sets = QMap; using Order = QList; -using UnreadMap = OrderedSet; + +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)); +} } // namespace Stickers @@ -250,7 +256,7 @@ DeclareVar(Stickers::Sets, StickerSets); DeclareVar(Stickers::Order, StickerSetsOrder); DeclareVar(uint64, LastStickersUpdate); DeclareVar(Stickers::Order, FeaturedStickerSetsOrder); -DeclareVar(Stickers::UnreadMap, FeaturedUnreadSets); +DeclareVar(int, FeaturedStickerSetsUnreadCount); DeclareVar(uint64, LastFeaturedStickersUpdate); DeclareVar(MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/history/field_autocomplete.cpp b/Telegram/SourceFiles/history/field_autocomplete.cpp index 67995b523c..9bd12b0650 100644 --- a/Telegram/SourceFiles/history/field_autocomplete.cpp +++ b/Telegram/SourceFiles/history/field_autocomplete.cpp @@ -196,14 +196,14 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { } return true; }; - auto filterNotPassedByName = [this](UserData *user) -> bool { + auto filterNotPassedByName = [this, &filterNotPassedByUsername](UserData *user) -> bool { for_const (auto &namePart, user->names) { if (namePart.startsWith(_filter, Qt::CaseInsensitive)) { bool exactUsername = (user->username.compare(_filter, Qt::CaseInsensitive) == 0); return exactUsername; } } - return true; + return filterNotPassedByUsername(user); }; bool listAllSuggestions = _filter.isEmpty(); diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style index 59a20ef439..5f0bd07d1b 100644 --- a/Telegram/SourceFiles/history/history.style +++ b/Telegram/SourceFiles/history/history.style @@ -29,6 +29,8 @@ historyToDownArrow: icon { { "history_down_arrow", #b9b9b9, point(14px, 19px) }, }; historyToDownPaddingTop: 10px; +historyToDownBadgeFont: semiboldFont; +historyToDownBadgeSize: 22px; membersInnerScroll: flatScroll(solidScroll) { deltat: 3px; @@ -42,5 +44,3 @@ membersInnerDropdown: InnerDropdown(defaultInnerDropdown) { scrollMargin: margins(0px, 5px, 0px, 5px); scrollPadding: margins(0px, 3px, 8px, 3px); } -historyToDownBadgeFont: semiboldFont; -historyToDownBadgeSize: 22px; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 3bdd9da635..47a8fe198d 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3667,7 +3667,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { 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_not_loaded); + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded); it->flags = set.vflags.v | clientFlags; if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) { it->count = set.vcount.v; @@ -3739,6 +3739,11 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic if (stickers.type() != mtpc_messages_featuredStickers) return; auto &d(stickers.c_messages_featuredStickers()); + OrderedSet unread; + for_const (auto &unreadSetId, d.vunread.c_vector().v) { + unread.insert(unreadSetId.v); + } + auto &d_sets(d.vsets.c_vector().v); auto &setsOrder = Global::RefFeaturedStickerSetsOrder(); @@ -3755,13 +3760,23 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic auto it = sets.find(set.vid.v); QString title = stickerSetTitle(set); if (it == sets.cend()) { - 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 | MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded)); + auto clientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded; + if (unread.contains(set.vid.v)) { + clientFlags |= 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 | clientFlags)); } 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_not_loaded); - it->flags = set.vflags.v | clientFlags | MTPDstickerSet_ClientFlag::f_featured; + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded); + 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; @@ -3774,21 +3789,21 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic } } } - for (Stickers::Sets::iterator it = sets.begin(), e = sets.end(); it != e;) { + + 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); if (installed || featured) { + if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { + ++unreadCount; + } ++it; } else { it = sets.erase(it); } } - - auto &unreadFeatured = Global::RefFeaturedUnreadSets(); - unreadFeatured.clear(); - for_const (auto &unreadSetId, d.vunread.c_vector().v) { - unreadFeatured.insert(unreadSetId.v); - } + Global::SetFeaturedStickerSetsUnreadCount(unreadCount); 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())); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 3c2ab76d48..aeec358466 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3079,7 +3079,6 @@ namespace Local { } size += sizeof(qint32) + (Global::StickerSetsOrder().size() * sizeof(quint64)); size += sizeof(qint32) + (Global::FeaturedStickerSetsOrder().size() * sizeof(quint64)); - size += sizeof(qint32) + (Global::FeaturedUnreadSets().size() * sizeof(quint64)); if (!_stickersKey) { _stickersKey = genKey(); @@ -3094,11 +3093,6 @@ namespace Local { data.stream << Global::StickerSetsOrder(); data.stream << Global::FeaturedStickerSetsOrder(); - data.stream << qint32(Global::FeaturedUnreadSets().size()); - for_const (auto setId, Global::FeaturedUnreadSets()) { - data.stream << quint64(setId); - } - FileWriteDescriptor file(_stickersKey); file.writeEncrypted(data); } @@ -3200,9 +3194,6 @@ namespace Local { auto &featuredOrder = Global::RefFeaturedStickerSetsOrder(); featuredOrder.clear(); - auto &unreadFeatured = Global::RefFeaturedUnreadSets(); - unreadFeatured.clear(); - quint32 cnt; QByteArray hash; stickers.stream >> cnt >> hash; // ignore hash, it is counted @@ -3244,6 +3235,8 @@ namespace Local { } auto &set = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))).value(); + // We will set this flags from order lists below. + set.flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_featured); if (scnt < 0) { // disabled not loaded set set.count = -scnt; continue; @@ -3293,23 +3286,32 @@ namespace Local { stickers.stream >> order; stickers.stream >> featuredOrder; - qint32 unreadCount = 0; - stickers.stream >> unreadCount; - for (int i = 0; i < unreadCount; ++i) { - quint64 setId = 0; - stickers.stream >> setId; - if (setId) { - unreadFeatured.insert(setId); + // Set flags and count unread featured sets. + for_const (auto setId, order) { + auto it = sets.find(setId); + if (it != sets.cend()) { + it->flags |= MTPDstickerSet::Flag::f_installed; } } + int unreadCount = 0; + for_const (auto setId, featuredOrder) { + auto it = sets.find(setId); + if (it != sets.cend()) { + it->flags |= MTPDstickerSet_ClientFlag::f_featured; + if (it->flags & MTPDstickerSet_ClientFlag::f_unread) { + ++unreadCount; + } + } + } + Global::SetFeaturedStickerSetsUnreadCount(unreadCount); } } int32 countStickersHash(bool checkOfficial) { uint32 acc = 0; bool foundOfficial = false, foundBad = false;; - const Stickers::Sets &sets(Global::StickerSets()); - const Stickers::Order &order(Global::StickerSetsOrder()); + auto &sets = Global::StickerSets(); + auto &order = Global::StickerSetsOrder(); for (auto i = order.cbegin(), e = order.cend(); i != e; ++i) { auto j = sets.constFind(*i); if (j != sets.cend()) { @@ -3328,11 +3330,14 @@ namespace Local { int32 countFeaturedStickersHash() { uint32 acc = 0; - auto &featured(Global::FeaturedStickerSetsOrder()); + auto &sets = Global::StickerSets(); + auto &featured = Global::FeaturedStickerSetsOrder(); for_const (auto setId, featured) { acc = (acc * 20261) + uint32(setId >> 32); acc = (acc * 20261) + uint32(setId & 0xFFFFFFFF); - if (Global::FeaturedUnreadSets().contains(setId)) { + + auto it = sets.constFind(setId); + if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { acc = (acc * 20261) + 1U; } } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 6cb95b58cd..f5a74cc597 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3378,7 +3378,6 @@ void MainWidget::stickersBox(const MTPInputStickerSet &set) { } void MainWidget::onStickersInstalled(uint64 setId) { - emit stickersUpdated(); _history->stickersInstalled(setId); } @@ -4731,9 +4730,16 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateReadFeaturedStickers: { - Global::RefFeaturedUnreadSets().clear(); - Local::writeStickers(); - emit stickersUpdated(); + for (auto &set : Global::RefStickerSets()) { + if (set.flags & MTPDstickerSet_ClientFlag::f_unread) { + set.flags &= ~MTPDstickerSet_ClientFlag::f_unread; + } + } + if (Global::FeaturedStickerSetsUnreadCount()) { + Global::SetFeaturedStickerSetsUnreadCount(0); + Local::writeStickers(); + emit stickersUpdated(); + } } break; ////// Cloud saved GIFs diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 17669f57bd..4b4d05a88b 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -1291,7 +1291,7 @@ void MediaView::paintEvent(QPaintEvent *e) { if (_saveMsgOpacity.current() > 0) { p.setOpacity(_saveMsgOpacity.current()); App::roundRect(p, _saveMsg, st::medviewSaveMsg, MediaviewSaveCorners); - p.drawSprite(_saveMsg.topLeft() + st::medviewSaveMsgCheckPos, st::medviewSaveMsgCheck); + st::medviewSaveMsgCheck.paint(p, _saveMsg.topLeft() + st::medviewSaveMsgCheckPos, width()); p.setPen(st::white->p); textstyleSet(&st::medviewSaveAsTextStyle); diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index 96eebe2c3b..1438fe2126 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -1063,8 +1063,11 @@ enum class MTPDstickerSet_ClientFlag : int32 { // sticker set is one of featured (should be saved locally) f_featured = (1 << 29), + // sticker set is an unread featured set + f_unread = (1 << 28), + // update this when adding new client side flags - MIN_FIELD = (1 << 29), + MIN_FIELD = (1 << 28), }; DEFINE_MTP_CLIENT_FLAGS(MTPDstickerSet) From 8ea47c1811c20cbc058c587461190e85d7db957a Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 5 Jul 2016 17:48:36 +0300 Subject: [PATCH 03/13] Opened histories stack finished, stack of states in vector_of_moveable. --- .../SourceFiles/core/vector_of_moveable.h | 5 +- Telegram/SourceFiles/facades.cpp | 10 +- Telegram/SourceFiles/facades.h | 25 ++-- Telegram/SourceFiles/history.cpp | 2 +- Telegram/SourceFiles/historywidget.cpp | 28 ++-- Telegram/SourceFiles/mainwidget.cpp | 121 +++++++++++------- Telegram/SourceFiles/mainwidget.h | 30 +---- Telegram/SourceFiles/mtproto/scheme.tl | 1 + Telegram/SourceFiles/mtproto/scheme_auto.cpp | 14 ++ Telegram/SourceFiles/mtproto/scheme_auto.h | 47 +++++++ .../SourceFiles/profile/profile_cover.cpp | 2 +- .../SourceFiles/window/top_bar_widget.cpp | 2 +- 12 files changed, 184 insertions(+), 103 deletions(-) diff --git a/Telegram/SourceFiles/core/vector_of_moveable.h b/Telegram/SourceFiles/core/vector_of_moveable.h index 412d87b35e..608bb07965 100644 --- a/Telegram/SourceFiles/core/vector_of_moveable.h +++ b/Telegram/SourceFiles/core/vector_of_moveable.h @@ -141,7 +141,10 @@ private: void reallocate(int newCapacity) { auto newPlainData = operator new[](newCapacity * sizeof(T)); for (int i = 0; i < _size; ++i) { - *(reinterpret_cast(newPlainData) + i) = std_::move(*(data() + i)); + auto oldLocation = data() + i; + auto newLocation = reinterpret_cast(newPlainData) + i; + new (newLocation) T(std_::move(*oldLocation)); + oldLocation->~T(); } std::swap(_plaindata, newPlainData); _capacity = newCapacity; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 58175e636b..1e8a6239d3 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -33,6 +33,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org Q_DECLARE_METATYPE(ClickHandlerPtr); Q_DECLARE_METATYPE(Qt::MouseButton); +Q_DECLARE_METATYPE(Ui::ShowWay); namespace App { @@ -253,13 +254,14 @@ void showPeerOverview(const PeerId &peer, MediaOverviewType type) { } } -void showPeerHistory(const PeerId &peer, MsgId msgId, bool back) { - if (MainWidget *m = App::main()) m->ui_showPeerHistory(peer, msgId, back); +void showPeerHistory(const PeerId &peer, MsgId msgId, ShowWay way) { + if (MainWidget *m = App::main()) m->ui_showPeerHistory(peer, msgId, way); } -void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) { +void showPeerHistoryAsync(const PeerId &peer, MsgId msgId, ShowWay way) { if (MainWidget *m = App::main()) { - QMetaObject::invokeMethod(m, "ui_showPeerHistoryAsync", Qt::QueuedConnection, Q_ARG(quint64, peer), Q_ARG(qint32, msgId)); + qRegisterMetaType(); + QMetaObject::invokeMethod(m, "ui_showPeerHistoryAsync", Qt::QueuedConnection, Q_ARG(quint64, peer), Q_ARG(qint32, msgId), Q_ARG(Ui::ShowWay, way)); } } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 71cd432e58..59a990bbd3 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -83,22 +83,27 @@ inline void showPeerOverview(const History *history, MediaOverviewType type) { showPeerOverview(history->peer->id, type); } -void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false); -inline void showPeerHistory(const PeerData *peer, MsgId msgId, bool back = false) { - showPeerHistory(peer->id, msgId, back); +enum class ShowWay { + ClearStack, + Forward, + Backward, +}; +void showPeerHistory(const PeerId &peer, MsgId msgId, ShowWay way = ShowWay::ClearStack); +inline void showPeerHistory(const PeerData *peer, MsgId msgId, ShowWay way = ShowWay::ClearStack) { + showPeerHistory(peer->id, msgId, way); } -inline void showPeerHistory(const History *history, MsgId msgId, bool back = false) { - showPeerHistory(history->peer->id, msgId, back); +inline void showPeerHistory(const History *history, MsgId msgId, ShowWay way = ShowWay::ClearStack) { + showPeerHistory(history->peer->id, msgId, way); } -inline void showPeerHistoryAtItem(const HistoryItem *item) { - showPeerHistory(item->history()->peer->id, item->id); +inline void showPeerHistoryAtItem(const HistoryItem *item, ShowWay way = ShowWay::ClearStack) { + showPeerHistory(item->history()->peer->id, item->id, way); } -void showPeerHistoryAsync(const PeerId &peer, MsgId msgId); +void showPeerHistoryAsync(const PeerId &peer, MsgId msgId, ShowWay way = ShowWay::ClearStack); inline void showChatsList() { - showPeerHistory(PeerId(0), 0); + showPeerHistory(PeerId(0), 0, ShowWay::ClearStack); } inline void showChatsListAsync() { - showPeerHistoryAsync(PeerId(0), 0); + showPeerHistoryAsync(PeerId(0), 0, ShowWay::ClearStack); } PeerData *getPeerForMouseAction(); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index a29b920533..f298cde338 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -5178,7 +5178,7 @@ int HistorySticker::additionalWidth(const HistoryMessageVia *via, const HistoryM } void SendMessageClickHandler::onClickImpl() const { - Ui::showPeerHistory(peer()->id, ShowAtUnreadMsgId); + Ui::showPeerHistory(peer()->id, ShowAtUnreadMsgId, Ui::ShowWay::Forward); } void AddContactClickHandler::onClickImpl() const { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 47a8fe198d..6748fe79c6 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3761,7 +3761,7 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic QString title = stickerSetTitle(set); if (it == sets.cend()) { auto clientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded; - if (unread.contains(set.vid.v)) { + if (unread.contains(set.vid.v) || !(set.vflags.v & MTPDstickerSet::Flag::f_installed)) { clientFlags |= 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 | clientFlags)); @@ -4673,7 +4673,7 @@ bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId if (error.type() == qstr("CHANNEL_PRIVATE") || error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA") || error.type() == qstr("USER_BANNED_IN_CHANNEL")) { PeerData *was = _peer; - Ui::showChatsList(); + App::main()->showBackFromStack(); Ui::showLayer(new InformBox(lang((was && was->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible))); return true; } @@ -4685,7 +4685,7 @@ bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId _preloadDownRequest = 0; } else if (_firstLoadRequest == requestId) { _firstLoadRequest = 0; - Ui::showChatsList(); + App::main()->showBackFromStack(); } else if (_delayedShowAtRequest == requestId) { _delayedShowAtRequest = 0; } @@ -5704,7 +5704,7 @@ void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotC Ui::Toast::Show(App::wnd(), toast); } } else if (answerData.has_url()) { - UrlClickHandler::doOpen(qs(answerData.vurl)); + HiddenUrlClickHandler(qs(answerData.vurl)).onClick(Qt::LeftButton); } } } @@ -6139,7 +6139,7 @@ void HistoryWidget::paintTopBar(Painter &p, float64 over, int32 decreaseWidth) { if (!_history) return; - int32 increaseLeft = Adaptive::OneColumn() ? (st::topBarForwardPadding.right() - st::topBarForwardPadding.left()) : 0; + int32 increaseLeft = (Adaptive::OneColumn() || !App::main()->stackIsEmpty()) ? (st::topBarForwardPadding.right() - st::topBarForwardPadding.left()) : 0; decreaseWidth += increaseLeft; QRect rectForName(st::topBarForwardPadding.left() + increaseLeft, st::topBarForwardPadding.top(), width() - decreaseWidth - st::topBarForwardPadding.left() - st::topBarForwardPadding.right(), st::msgNameFont->height); p.setFont(st::dialogsTextFont); @@ -6154,7 +6154,7 @@ void HistoryWidget::paintTopBar(Painter &p, float64 over, int32 decreaseWidth) { p.setPen(st::dialogsNameFg); _peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); - if (Adaptive::OneColumn()) { + if (Adaptive::OneColumn() || !App::main()->stackIsEmpty()) { p.setOpacity(st::topBarForwardAlpha + (1 - st::topBarForwardAlpha) * over); p.drawSprite(QPoint((st::topBarForwardPadding.right() - st::topBarBackwardImg.pxWidth()) / 2, (st::topBarHeight - st::topBarBackwardImg.pxHeight()) / 2), st::topBarBackwardImg); } else { @@ -6164,7 +6164,7 @@ void HistoryWidget::paintTopBar(Painter &p, float64 over, int32 decreaseWidth) { } QRect HistoryWidget::getMembersShowAreaGeometry() const { - int increaseLeft = Adaptive::OneColumn() ? (st::topBarForwardPadding.right() - st::topBarForwardPadding.left()) : 0; + int increaseLeft = (Adaptive::OneColumn() || !App::main()->stackIsEmpty()) ? (st::topBarForwardPadding.right() - st::topBarForwardPadding.left()) : 0; int membersTextLeft = st::topBarForwardPadding.left() + increaseLeft; int membersTextTop = st::topBarHeight - st::topBarForwardPadding.bottom() - st::dialogsTextFont->height; int membersTextWidth = _titlePeerTextWidth; @@ -6210,8 +6210,8 @@ void HistoryWidget::onMembersDropdownHidden() { } void HistoryWidget::topBarClick() { - if (Adaptive::OneColumn()) { - Ui::showChatsList(); + if (Adaptive::OneColumn() || !App::main()->stackIsEmpty()) { + App::main()->showBackFromStack(); } else { if (_history) Ui::showPeerProfile(_peer); } @@ -6763,10 +6763,10 @@ void HistoryWidget::onReportSpamClear() { if (_clearPeer->isUser()) { App::main()->deleteConversation(_clearPeer); } else if (_clearPeer->isChat()) { - Ui::showChatsList(); + App::main()->showBackFromStack(); MTP::send(MTPmessages_DeleteChatUser(_clearPeer->asChat()->inputChat, App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistoryAfterLeave, _clearPeer), App::main()->rpcFail(&MainWidget::leaveChatFailed, _clearPeer)); } else if (_clearPeer->isChannel()) { - Ui::showChatsList(); + App::main()->showBackFromStack(); if (_clearPeer->migrateFrom()) { App::main()->deleteConversation(_clearPeer->migrateFrom()); } @@ -7294,7 +7294,7 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Escape) { e->ignore(); } else if (e->key() == Qt::Key_Back) { - Ui::showChatsList(); + App::main()->showBackFromStack(); emit cancelled(); } else if (e->key() == Qt::Key_PageDown) { _scroll.keyPressEvent(e); @@ -8072,7 +8072,7 @@ void HistoryWidget::onCancel() { } else if (!_fieldAutocomplete->isHidden()) { _fieldAutocomplete->hideStart(); } else { - Ui::showChatsList(); + App::main()->showBackFromStack(); emit cancelled(); } } @@ -8110,7 +8110,7 @@ void HistoryWidget::peerUpdated(PeerData *data) { } QString restriction = _peer->restrictionReason(); if (!restriction.isEmpty()) { - Ui::showChatsList(); + App::main()->showBackFromStack(); Ui::showLayer(new InformBox(restriction)); return; } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index f5a74cc597..23e4170429 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1519,8 +1519,8 @@ void MainWidget::onSharePhoneWithBot(PeerData *recipient) { onShareContact(recipient->id, App::self()); } -void MainWidget::ui_showPeerHistoryAsync(quint64 peerId, qint32 showAtMsgId) { - Ui::showPeerHistory(peerId, showAtMsgId); +void MainWidget::ui_showPeerHistoryAsync(quint64 peerId, qint32 showAtMsgId, Ui::ShowWay way) { + Ui::showPeerHistory(peerId, showAtMsgId, way); } void MainWidget::ui_autoplayMediaInlineAsync(qint32 channelId, qint32 msgId) { @@ -2016,7 +2016,7 @@ void MainWidget::ctrlEnterSubmitUpdated() { _history->updateFieldSubmitSettings(); } -void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool back) { +void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::ShowWay way) { if (PeerData *peer = App::peerLoaded(peerId)) { if (peer->migrateTo()) { peer = peer->migrateTo(); @@ -2030,8 +2030,37 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac return; } } - if (!back && (!peerId || (_stack.size() == 1 && _stack[0]->type() == HistoryStackItem && _stack[0]->peer->id == peerId))) { - back = true; + + bool back = (way == Ui::ShowWay::Backward || !peerId); + bool foundInStack = !peerId; + if (foundInStack || (way == Ui::ShowWay::ClearStack)) { + for_const (auto &item, _stack) { + clearBotStartToken(item->peer); + } + _stack.clear(); + } else { + for (int i = 0, s = _stack.size(); i < s; ++i) { + if (_stack.at(i)->type() == HistoryStackItem && _stack.at(i)->peer->id == peerId) { + foundInStack = true; + while (_stack.size() > i) { + clearBotStartToken(_stack.back()->peer); + _stack.pop_back(); + } + if (!back) { + back = true; + } + break; + } + } + } + + if (back || (way == Ui::ShowWay::ClearStack)) { + dlgUpdated(); + _peerInStack = nullptr; + _msgIdInStack = 0; + dlgUpdated(); + } else { + saveSectionInStack(); } PeerData *wasActivePeer = activePeer(); @@ -2043,10 +2072,12 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac } Window::SectionSlideParams animationParams; - if (!_a_show.animating() && ((_history->isHidden() && (_wideSection || _overview)) || (Adaptive::OneColumn() && (_history->isHidden() || !peerId)))) { + if (!_a_show.animating() && ((_history->isHidden() && (_wideSection || _overview)) || (Adaptive::OneColumn() && (_history->isHidden() || !peerId)) || back || (way == Ui::ShowWay::Forward))) { animationParams = prepareHistoryAnimation(peerId); } - if (_history->peer() && _history->peer()->id != peerId) clearBotStartToken(_history->peer()); + if (_history->peer() && _history->peer()->id != peerId) { + clearBotStartToken(_history->peer()); + } _history->showHistory(peerId, showAtMsgId); bool noPeer = (!_history->peer() || !_history->peer()->id), onlyDialogs = noPeer && Adaptive::OneColumn(); @@ -2063,11 +2094,6 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac _overview->rpcClear(); _overview = nullptr; } - clearBotStartToken(_peerInStack); - dlgUpdated(); - _peerInStack = 0; - _msgIdInStack = 0; - _stack.clear(); } if (onlyDialogs) { _topBar->hide(); @@ -2111,6 +2137,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac } _dialogs->update(); } + topBar()->showAll(); App::wnd()->getTitle()->updateBackButton(); } @@ -2167,6 +2194,21 @@ bool MainWidget::mediaTypeSwitch() { return true; } +void MainWidget::saveSectionInStack() { + if (_overview) { + _stack.push_back(std_::make_unique(_overview->peer(), _overview->type(), _overview->lastWidth(), _overview->lastScrollTop())); + } else if (_wideSection) { + _stack.push_back(std_::make_unique(_wideSection->createMemento())); + } else if (_history->peer()) { + dlgUpdated(); + _peerInStack = _history->peer(); + _msgIdInStack = _history->msgId(); + dlgUpdated(); + + _stack.push_back(std_::make_unique(_peerInStack, _msgIdInStack, _history->replyReturns())); + } +} + void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool back, int32 lastScrollTop) { if (peer->migrateTo()) { peer = peer->migrateTo(); @@ -2187,17 +2229,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool animationParams = prepareOverviewAnimation(); } if (!back) { - if (_overview) { - _stack.push_back(new StackItemOverview(_overview->peer(), _overview->type(), _overview->lastWidth(), _overview->lastScrollTop())); - } else if (_wideSection) { - _stack.push_back(new StackItemSection(_wideSection->createMemento())); - } else if (_history->peer()) { - dlgUpdated(); - _peerInStack = _history->peer(); - _msgIdInStack = _history->msgId(); - dlgUpdated(); - _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, _history->replyReturns())); - } + saveSectionInStack(); } if (_overview) { _overview->hide(); @@ -2222,7 +2254,9 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool _overview->fastShow(); } _history->animStop(); - if (back) clearBotStartToken(_history->peer()); + if (back) { + clearBotStartToken(_history->peer()); + } _history->showHistory(0, 0); _history->hide(); if (Adaptive::OneColumn()) _dialogs->hide(); @@ -2238,17 +2272,7 @@ void MainWidget::showWideSection(const Window::SectionMemento &memento) { return; } - if (_overview) { - _stack.push_back(new StackItemOverview(_overview->peer(), _overview->type(), _overview->lastWidth(), _overview->lastScrollTop())); - } else if (_wideSection) { - _stack.push_back(new StackItemSection(_wideSection->createMemento())); - } else if (_history->peer()) { - dlgUpdated(); - _peerInStack = _history->peer(); - _msgIdInStack = _history->msgId(); - dlgUpdated(); - _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, _history->replyReturns())); - } + saveSectionInStack(); showWideSectionAnimated(&memento, false); } @@ -2341,6 +2365,10 @@ void MainWidget::showWideSectionAnimated(const Window::SectionMemento *memento, App::wnd()->getTitle()->updateBackButton(); } +bool MainWidget::stackIsEmpty() const { + return _stack.isEmpty(); +} + void MainWidget::showBackFromStack() { if (selectingPeer()) return; if (_stack.isEmpty()) { @@ -2348,34 +2376,33 @@ void MainWidget::showBackFromStack() { if (App::wnd()) QTimer::singleShot(0, App::wnd(), SLOT(setInnerFocus())); return; } - StackItem *item = _stack.back(); + auto item = std_::move(_stack.back()); _stack.pop_back(); if (auto currentHistoryPeer = _history->peer()) { clearBotStartToken(currentHistoryPeer); } if (item->type() == HistoryStackItem) { dlgUpdated(); - _peerInStack = 0; + _peerInStack = nullptr; _msgIdInStack = 0; for (int32 i = _stack.size(); i > 0;) { if (_stack.at(--i)->type() == HistoryStackItem) { - _peerInStack = static_cast(_stack.at(i))->peer; - _msgIdInStack = static_cast(_stack.at(i))->msgId; + _peerInStack = static_cast(_stack.at(i).get())->peer; + _msgIdInStack = static_cast(_stack.at(i).get())->msgId; dlgUpdated(); break; } } - StackItemHistory *histItem = static_cast(item); - Ui::showPeerHistory(histItem->peer->id, App::main()->activeMsgId(), true); + StackItemHistory *histItem = static_cast(item.get()); + Ui::showPeerHistory(histItem->peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Backward); _history->setReplyReturns(histItem->peer->id, histItem->replyReturns); } else if (item->type() == SectionStackItem) { - StackItemSection *sectionItem = static_cast(item); + StackItemSection *sectionItem = static_cast(item.get()); showWideSectionAnimated(sectionItem->memento(), true); } else if (item->type() == OverviewStackItem) { - StackItemOverview *overItem = static_cast(item); + StackItemOverview *overItem = static_cast(item.get()); showMediaOverview(overItem->peer, overItem->mediaType, true, overItem->lastScrollTop); } - delete item; } void MainWidget::orderWidgets() { @@ -3343,7 +3370,7 @@ void MainWidget::openPeerByName(const QString &username, MsgId msgId, const QStr Ui::showLayer(new ContactsBox(peer->asUser())); } else if (peer->isUser() && peer->asUser()->botInfo) { // Always open bot chats, even from mention links. - Ui::showPeerHistoryAsync(peer->id, ShowAtUnreadMsgId); + Ui::showPeerHistoryAsync(peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Forward); } else { Ui::showPeerProfile(peer); } @@ -3358,7 +3385,7 @@ void MainWidget::openPeerByName(const QString &username, MsgId msgId, const QStr _history->resizeEvent(0); } } - Ui::showPeerHistoryAsync(peer->id, msgId); + Ui::showPeerHistoryAsync(peer->id, msgId, Ui::ShowWay::Forward); } } else { MTP::send(MTPcontacts_ResolveUsername(MTP_string(username)), rpcDone(&MainWidget::usernameResolveDone, qMakePair(msgId, startToken)), rpcFail(&MainWidget::usernameResolveFail, username)); @@ -3425,7 +3452,7 @@ void MainWidget::usernameResolveDone(QPair msgIdAndStartToken, c Ui::showLayer(new ContactsBox(peer->asUser())); } else if (peer->isUser() && peer->asUser()->botInfo) { // Always open bot chats, even from mention links. - Ui::showPeerHistoryAsync(peer->id, ShowAtUnreadMsgId); + Ui::showPeerHistoryAsync(peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Forward); } else { Ui::showPeerProfile(peer); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index c6e937e423..baae91478b 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -108,27 +108,6 @@ public: int32 lastWidth, lastScrollTop; }; -class StackItems : public QVector { -public: - bool contains(PeerData *peer) const { - for (int32 i = 0, l = size(); i < l; ++i) { - if (at(i)->peer == peer) { - return true; - } - } - return false; - } - void clear() { - for (int32 i = 0, l = size(); i < l; ++i) { - delete at(i); - } - QVector::clear(); - } - ~StackItems() { - clear(); - } -}; - enum SilentNotifiesStatus { SilentNotifiesDontChange, SilentNotifiesSetSilent, @@ -224,6 +203,7 @@ public: bool mediaTypeSwitch(); void showWideSection(const Window::SectionMemento &memento); void showMediaOverview(PeerData *peer, MediaOverviewType type, bool back = false, int32 lastScrollTop = -1); + bool stackIsEmpty() const; void showBackFromStack(); void orderWidgets(); QRect historyRect() const; @@ -404,7 +384,7 @@ public: void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout); bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout); bool ui_isInlineItemBeingChosen(); - void ui_showPeerHistory(quint64 peer, qint32 msgId, bool back); + void ui_showPeerHistory(quint64 peer, qint32 msgId, Ui::ShowWay way); PeerData *ui_getPeerForMouseAction(); void notify_botCommandsChanged(UserData *bot); @@ -493,7 +473,7 @@ public slots: void onSharePhoneWithBot(PeerData *recipient); - void ui_showPeerHistoryAsync(quint64 peerId, qint32 showAtMsgId); + void ui_showPeerHistoryAsync(quint64 peerId, qint32 showAtMsgId, Ui::ShowWay way); void ui_autoplayMediaInlineAsync(qint32 channelId, qint32 msgId); private slots: @@ -519,6 +499,8 @@ private: Window::SectionSlideParams prepareOverviewAnimation(); Window::SectionSlideParams prepareDialogsAnimation(); + void saveSectionInStack(); + bool _started = false; uint64 failedObjId = 0; @@ -598,7 +580,7 @@ private: ChildWidget _topBar; ConfirmBox *_forwardConfirm = nullptr; // for single column layout ChildWidget _hider = { nullptr }; - StackItems _stack; + std_::vector_of_moveable> _stack; PeerData *_peerInStack = nullptr; MsgId _msgIdInStack = 0; diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index 777de9b153..aaa8866758 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -507,6 +507,7 @@ documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = Docume documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; +documentAttributeVersion#99cd09ab version:int = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp index f22248eaa7..9b4b655c16 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp +++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp @@ -4018,6 +4018,19 @@ void _serialize_documentAttributeFilename(MTPStringLogger &to, int32 stage, int3 } } +void _serialize_documentAttributeVersion(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ documentAttributeVersion"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" version: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_messages_stickersNotModified(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ messages_stickersNotModified }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -8612,6 +8625,7 @@ namespace { _serializers.insert(mtpc_documentAttributeVideo, _serialize_documentAttributeVideo); _serializers.insert(mtpc_documentAttributeAudio, _serialize_documentAttributeAudio); _serializers.insert(mtpc_documentAttributeFilename, _serialize_documentAttributeFilename); + _serializers.insert(mtpc_documentAttributeVersion, _serialize_documentAttributeVersion); _serializers.insert(mtpc_messages_stickersNotModified, _serialize_messages_stickersNotModified); _serializers.insert(mtpc_messages_stickers, _serialize_messages_stickers); _serializers.insert(mtpc_stickerPack, _serialize_stickerPack); diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h index 15b3d4942f..0c0d69db2c 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.h +++ b/Telegram/SourceFiles/mtproto/scheme_auto.h @@ -372,6 +372,7 @@ enum { mtpc_documentAttributeVideo = 0x5910cccb, mtpc_documentAttributeAudio = 0x9852f9c6, mtpc_documentAttributeFilename = 0x15590068, + mtpc_documentAttributeVersion = 0x99cd09ab, mtpc_messages_stickersNotModified = 0xf1749a22, mtpc_messages_stickers = 0x8a8ecd32, mtpc_stickerPack = 0x12b299d4, @@ -1138,6 +1139,7 @@ class MTPDdocumentAttributeSticker; class MTPDdocumentAttributeVideo; class MTPDdocumentAttributeAudio; class MTPDdocumentAttributeFilename; +class MTPDdocumentAttributeVersion; class MTPmessages_stickers; class MTPDmessages_stickers; @@ -6971,6 +6973,18 @@ public: return *(const MTPDdocumentAttributeFilename*)data; } + MTPDdocumentAttributeVersion &_documentAttributeVersion() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_documentAttributeVersion) throw mtpErrorWrongTypeId(_type, mtpc_documentAttributeVersion); + split(); + return *(MTPDdocumentAttributeVersion*)data; + } + const MTPDdocumentAttributeVersion &c_documentAttributeVersion() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_documentAttributeVersion) throw mtpErrorWrongTypeId(_type, mtpc_documentAttributeVersion); + return *(const MTPDdocumentAttributeVersion*)data; + } + uint32 innerLength() const; mtpTypeId type() const; void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); @@ -6985,6 +6999,7 @@ private: explicit MTPdocumentAttribute(MTPDdocumentAttributeVideo *_data); explicit MTPdocumentAttribute(MTPDdocumentAttributeAudio *_data); explicit MTPdocumentAttribute(MTPDdocumentAttributeFilename *_data); + explicit MTPdocumentAttribute(MTPDdocumentAttributeVersion *_data); friend class MTP::internal::TypeCreator; @@ -12818,6 +12833,16 @@ public: MTPstring vfile_name; }; +class MTPDdocumentAttributeVersion : public mtpDataImpl { +public: + MTPDdocumentAttributeVersion() { + } + MTPDdocumentAttributeVersion(MTPint _version) : vversion(_version) { + } + + MTPint vversion; +}; + class MTPDmessages_stickers : public mtpDataImpl { public: MTPDmessages_stickers() { @@ -23329,6 +23354,9 @@ public: inline static MTPdocumentAttribute new_documentAttributeFilename(const MTPstring &_file_name) { return MTPdocumentAttribute(new MTPDdocumentAttributeFilename(_file_name)); } + inline static MTPdocumentAttribute new_documentAttributeVersion(MTPint _version) { + return MTPdocumentAttribute(new MTPDdocumentAttributeVersion(_version)); + } inline static MTPmessages_stickers new_messages_stickersNotModified() { return MTPmessages_stickers(mtpc_messages_stickersNotModified); } @@ -31459,6 +31487,10 @@ inline uint32 MTPdocumentAttribute::innerLength() const { const MTPDdocumentAttributeFilename &v(c_documentAttributeFilename()); return v.vfile_name.innerLength(); } + case mtpc_documentAttributeVersion: { + const MTPDdocumentAttributeVersion &v(c_documentAttributeVersion()); + return v.vversion.innerLength(); + } } return 0; } @@ -31503,6 +31535,11 @@ inline void MTPdocumentAttribute::read(const mtpPrime *&from, const mtpPrime *en MTPDdocumentAttributeFilename &v(_documentAttributeFilename()); v.vfile_name.read(from, end); } break; + case mtpc_documentAttributeVersion: _type = cons; { + if (!data) setData(new MTPDdocumentAttributeVersion()); + MTPDdocumentAttributeVersion &v(_documentAttributeVersion()); + v.vversion.read(from, end); + } break; default: throw mtpErrorUnexpected(cons, "MTPdocumentAttribute"); } } @@ -31536,6 +31573,10 @@ inline void MTPdocumentAttribute::write(mtpBuffer &to) const { const MTPDdocumentAttributeFilename &v(c_documentAttributeFilename()); v.vfile_name.write(to); } break; + case mtpc_documentAttributeVersion: { + const MTPDdocumentAttributeVersion &v(c_documentAttributeVersion()); + v.vversion.write(to); + } break; } } inline MTPdocumentAttribute::MTPdocumentAttribute(mtpTypeId type) : mtpDataOwner(0), _type(type) { @@ -31546,6 +31587,7 @@ inline MTPdocumentAttribute::MTPdocumentAttribute(mtpTypeId type) : mtpDataOwner case mtpc_documentAttributeVideo: setData(new MTPDdocumentAttributeVideo()); break; case mtpc_documentAttributeAudio: setData(new MTPDdocumentAttributeAudio()); break; case mtpc_documentAttributeFilename: setData(new MTPDdocumentAttributeFilename()); break; + case mtpc_documentAttributeVersion: setData(new MTPDdocumentAttributeVersion()); break; default: throw mtpErrorBadTypeId(type, "MTPdocumentAttribute"); } } @@ -31559,6 +31601,8 @@ inline MTPdocumentAttribute::MTPdocumentAttribute(MTPDdocumentAttributeAudio *_d } inline MTPdocumentAttribute::MTPdocumentAttribute(MTPDdocumentAttributeFilename *_data) : mtpDataOwner(_data), _type(mtpc_documentAttributeFilename) { } +inline MTPdocumentAttribute::MTPdocumentAttribute(MTPDdocumentAttributeVersion *_data) : mtpDataOwner(_data), _type(mtpc_documentAttributeVersion) { +} inline MTPdocumentAttribute MTP_documentAttributeImageSize(MTPint _w, MTPint _h) { return MTP::internal::TypeCreator::new_documentAttributeImageSize(_w, _h); } @@ -31578,6 +31622,9 @@ inline MTPdocumentAttribute MTP_documentAttributeAudio(const MTPflagsisHidden()) { - if (Adaptive::OneColumn()) { + if (Adaptive::OneColumn() || !App::main()->stackIsEmpty()) { _info->setPeer(h); _info->show(); } else { From cd36d367ed25474be893907d502af6f5ce32f3ce Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 8 Jul 2016 16:56:53 +0300 Subject: [PATCH 04/13] Version raised to 0.9.58. Version field of documents supported. --- Telegram/Resources/winrc/Telegram.rc | 8 +- Telegram/Resources/winrc/Updater.rc | 8 +- Telegram/SourceFiles/app.cpp | 35 +- Telegram/SourceFiles/app.h | 2 +- Telegram/SourceFiles/boxes/stickersetbox.cpp | 2 +- Telegram/SourceFiles/core/version.h | 4 +- .../inline_bots/inline_bot_result.cpp | 2 +- Telegram/SourceFiles/localimageloader.cpp | 4 +- Telegram/SourceFiles/localstorage.cpp | 6 +- .../SourceFiles/mtproto/file_download.cpp | 22 +- Telegram/SourceFiles/mtproto/file_download.h | 19 +- Telegram/SourceFiles/mtproto/scheme.tl | 14 +- Telegram/SourceFiles/mtproto/scheme_auto.cpp | 78 +++- Telegram/SourceFiles/mtproto/scheme_auto.h | 337 ++++++++++++++---- .../serialize/serialize_document.cpp | 24 +- .../serialize/serialize_document.h | 6 +- Telegram/SourceFiles/structs.cpp | 29 +- Telegram/SourceFiles/structs.h | 10 +- Telegram/SourceFiles/ui/images.h | 9 +- Telegram/Telegram.xcodeproj/project.pbxproj | 4 +- Telegram/build/version | 6 +- 21 files changed, 461 insertions(+), 168 deletions(-) diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index a04176115f..3132ab97ac 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,57,0 - PRODUCTVERSION 0,9,57,0 + FILEVERSION 0,9,58,0 + PRODUCTVERSION 0,9,58,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.9.57.0" + VALUE "FileVersion", "0.9.58.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.57.0" + VALUE "ProductVersion", "0.9.58.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index edc6944fb6..69822ab7a5 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,57,0 - PRODUCTVERSION 0,9,57,0 + FILEVERSION 0,9,58,0 + PRODUCTVERSION 0,9,58,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,10 +43,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Updater" - VALUE "FileVersion", "0.9.57.0" + VALUE "FileVersion", "0.9.58.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.57.0" + VALUE "ProductVersion", "0.9.58.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 048dc3bab3..888a7db717 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -29,6 +29,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "lang.h" #include "data/data_abstract_structure.h" #include "history/history_service_layout.h" +#include "inline_bots/inline_bot_layout_item.h" #include "audio.h" #include "application.h" #include "fileuploader.h" @@ -1454,7 +1455,7 @@ namespace { switch (document.type()) { case mtpc_document: { const auto &d(document.c_document()); - return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation()); + return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vversion.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation()); } break; case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v); } @@ -1467,14 +1468,14 @@ namespace { return feedDocument(document.c_document(), convert); } break; case mtpc_documentEmpty: { - return App::documentSet(document.c_documentEmpty().vid.v, convert, 0, 0, QVector(), QString(), ImagePtr(), 0, 0, StorageImageLocation()); + return App::documentSet(document.c_documentEmpty().vid.v, convert, 0, 0, 0, QVector(), QString(), ImagePtr(), 0, 0, StorageImageLocation()); } break; } return App::document(0); } DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) { - return App::documentSet(document.vid.v, convert, document.vaccess_hash.v, document.vdate.v, document.vattributes.c_vector().v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v, App::imageLocation(document.vthumb)); + return App::documentSet(document.vid.v, convert, document.vaccess_hash.v, document.vversion.v, document.vdate.v, document.vattributes.c_vector().v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v, App::imageLocation(document.vthumb)); } WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert) { @@ -1631,11 +1632,13 @@ namespace { return i.value(); } - DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation) { + DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 version, int32 date, const QVector &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation) { + bool versionChanged = false; bool sentSticker = false; if (convert) { MediaKey oldKey = convert->mediaKey(); - if (convert->id != document) { + bool idChanged = (convert->id != document); + if (idChanged) { DocumentsData::iterator i = ::documentsData.find(convert->id); if (i != ::documentsData.cend() && i.value() == convert) { ::documentsData.erase(i); @@ -1647,10 +1650,11 @@ namespace { } if (date) { convert->setattributes(attributes); + versionChanged = convert->setRemoteVersion(version); convert->setRemoteLocation(dc, access); convert->date = date; convert->mime = mime; - if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height())) { + if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height() || versionChanged)) { updateImage(convert->thumb, thumb); } convert->size = size; @@ -1660,7 +1664,7 @@ namespace { } MediaKey newKey = convert->mediaKey(); - if (newKey != oldKey) { + if (idChanged) { if (convert->voice()) { Local::copyAudio(oldKey, newKey); } else if (convert->sticker() || convert->isAnimation()) { @@ -1679,7 +1683,7 @@ namespace { if (convert) { result = convert; } else { - result = DocumentData::create(document, dc, access, attributes); + result = DocumentData::create(document, dc, access, version, attributes); result->date = date; result->mime = mime; result->thumb = thumb; @@ -1694,12 +1698,13 @@ namespace { result = i.value(); if (result != convert && date) { result->setattributes(attributes); + versionChanged = result->setRemoteVersion(version); if (!result->isValid()) { result->setRemoteLocation(dc, access); } result->date = date; result->mime = mime; - if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height())) { + if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height() || versionChanged)) { result->thumb = thumb; } result->size = size; @@ -1712,6 +1717,18 @@ namespace { if (sentSticker && App::main()) { App::main()->incrementSticker(result); } + if (versionChanged) { + if (result->sticker()) { + Local::writeStickers(); + } + auto &items = App::documentItems(); + auto i = items.constFind(result); + if (i != items.cend()) { + for (auto j = i->cbegin(), e = i->cend(); j != e; ++j) { + j.key()->setPendingInitDimensions(); + } + } + } return result; } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 9bdb14fdf8..0c12a7615e 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -149,7 +149,7 @@ namespace App { PhotoData *photo(const PhotoId &photo); PhotoData *photoSet(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 date, const ImagePtr &thumb, const ImagePtr &medium, const ImagePtr &full); DocumentData *document(const DocumentId &document); - DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation); + DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 version, int32 date, const QVector &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation); WebPageData *webPage(const WebPageId &webPage); WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill); LocationData *location(const LocationCoords &coords); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 6d838b0ce5..78837cc1e6 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -530,7 +530,7 @@ void StickersInner::paintRow(Painter &p, int32 index) { int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2; QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.height)); - App::roundRect(p, add, st::defaultActiveButton.textBgOver); + App::roundRect(p, add, st::defaultActiveButton.textBgOver, ImageRoundRadius::Small); p.setFont(st::defaultActiveButton.font); p.setPen(st::defaultActiveButton.textFg); p.drawTextLeft(addx - st::defaultActiveButton.width / 2, addy + st::defaultActiveButton.textTop, width(), _addText, _addWidth); diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 7e443e7811..795b8bef4e 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #define BETA_VERSION_MACRO (0ULL) -constexpr int AppVersion = 9057; -constexpr str_const AppVersionStr = "0.9.57"; +constexpr int AppVersion = 9058; +constexpr str_const AppVersionStr = "0.9.58"; constexpr bool AppAlphaVersion = true; constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index 29a4909c70..d3afc27b4a 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp @@ -352,7 +352,7 @@ void Result::createDocument() { attributes.push_back(MTP_documentAttributeAudio(MTP_flags(flags), MTP_int(_duration), MTPstring(), MTPstring(), MTPbytes())); } - MTPDocument document = MTP_document(MTP_long(docId), MTP_long(0), MTP_int(unixtime()), MTP_string(mime), MTP_int(0), MTP_photoSizeEmpty(MTP_string("")), MTP_int(MTP::maindc()), MTP_vector(attributes)); + MTPDocument document = MTP_document(MTP_long(docId), MTP_long(0), MTP_int(unixtime()), MTP_string(mime), MTP_int(0), MTP_photoSizeEmpty(MTP_string("")), MTP_int(MTP::maindc()), MTP_int(0), MTP_vector(attributes)); _document = App::feedDocument(document); _document->setContentUrl(_content_url); diff --git a/Telegram/SourceFiles/localimageloader.cpp b/Telegram/SourceFiles/localimageloader.cpp index f484ccb9bf..3d3e162ce1 100644 --- a/Telegram/SourceFiles/localimageloader.cpp +++ b/Telegram/SourceFiles/localimageloader.cpp @@ -413,9 +413,9 @@ void FileLoadTask::process() { if (voice) { attributes[0] = MTP_documentAttributeAudio(MTP_flags(MTPDdocumentAttributeAudio::Flag::f_voice | MTPDdocumentAttributeAudio::Flag::f_waveform), MTP_int(_duration), MTPstring(), MTPstring(), MTP_bytes(documentWaveformEncode5bit(_waveform))); attributes.resize(1); - document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_vector(attributes)); + document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_int(0), MTP_vector(attributes)); } else { - document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_vector(attributes)); + document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_int(0), MTP_vector(attributes)); if (photo.type() == mtpc_photoEmpty) { _type = PrepareDocument; } diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index aeec358466..4b2e792c26 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3145,7 +3145,7 @@ namespace Local { attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height))); } - DocumentData *doc = App::documentSet(id, 0, access, date, attributes, mime, ImagePtr(), dc, size, StorageImageLocation()); + DocumentData *doc = App::documentSet(id, 0, access, 0, date, attributes, mime, ImagePtr(), dc, size, StorageImageLocation()); if (!doc->sticker()) continue; if (value > 0) { @@ -3247,7 +3247,7 @@ namespace Local { Serialize::Document::StickerSetInfo info(setId, setAccess, setShortName); OrderedSet read; for (int32 j = 0; j < scnt; ++j) { - auto document = Serialize::Document::readStickerFromStream(stickers.stream, info); + auto document = Serialize::Document::readStickerFromStream(stickers.version, stickers.stream, info); if (!document || !document->sticker()) continue; if (read.contains(document->id)) continue; @@ -3407,7 +3407,7 @@ namespace Local { saved.reserve(cnt); OrderedSet read; for (uint32 i = 0; i < cnt; ++i) { - DocumentData *document = Serialize::Document::readFromStream(gifs.stream); + DocumentData *document = Serialize::Document::readFromStream(gifs.version, gifs.stream); if (!document || !document->isAnimation()) continue; if (read.contains(document->id)) continue; diff --git a/Telegram/SourceFiles/mtproto/file_download.cpp b/Telegram/SourceFiles/mtproto/file_download.cpp index ab8a25af52..f8a5c0018b 100644 --- a/Telegram/SourceFiles/mtproto/file_download.cpp +++ b/Telegram/SourceFiles/mtproto/file_download.cpp @@ -350,13 +350,8 @@ void FileLoader::startLoading(bool loadFirst, bool prior) { mtpFileLoader::mtpFileLoader(const StorageImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading) : FileLoader(QString(), size, UnknownFileLocation, LoadToCacheAsWell, fromCloud, autoLoading) -, _lastComplete(false) -, _skippedBytes(0) -, _nextRequestOffset(0) , _dc(location->dc()) -, _location(location) -, _id(0) -, _access(0) { +, _location(location) { LoaderQueues::iterator i = queues.find(MTP::dldDcId(_dc, 0)); if (i == queues.cend()) { i = queues.insert(MTP::dldDcId(_dc, 0), FileLoaderQueue(MaxFileQueries)); @@ -364,15 +359,12 @@ mtpFileLoader::mtpFileLoader(const StorageImageLocation *location, int32 size, L _queue = &i.value(); } -mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, LocationType type, const QString &to, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading) +mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, int32 version, LocationType type, const QString &to, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading) : FileLoader(to, size, type, toCache, fromCloud, autoLoading) -, _lastComplete(false) -, _skippedBytes(0) -, _nextRequestOffset(0) , _dc(dc) -, _location(0) , _id(id) -, _access(access) { +, _access(access) +, _version(version) { LoaderQueues::iterator i = queues.find(MTP::dldDcId(_dc, 0)); if (i == queues.cend()) { i = queues.insert(MTP::dldDcId(_dc, 0), FileLoaderQueue(MaxFileQueries)); @@ -421,7 +413,7 @@ bool mtpFileLoader::loadPart() { switch (_locationType) { case VideoFileLocation: case AudioFileLocation: - case DocumentFileLocation: loc = MTP_inputDocumentFileLocation(MTP_long(_id), MTP_long(_access)); break; + case DocumentFileLocation: loc = MTP_inputDocumentFileLocation(MTP_long(_id), MTP_long(_access), MTP_int(_version)); break; default: cancel(true); return false; break; } } @@ -531,7 +523,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe if (_localStatus == LocalNotFound || _localStatus == LocalFailed) { if (_locationType != UnknownFileLocation) { // audio, video, document - MediaKey mkey = mediaKey(_locationType, _dc, _id); + MediaKey mkey = mediaKey(_locationType, _dc, _id, _version); if (!_fname.isEmpty()) { Local::writeFileLocation(mkey, FileLocation(mtpToStorageType(_type), _fname)); } @@ -593,7 +585,7 @@ bool mtpFileLoader::tryLoadLocal() { _localTaskId = Local::startImageLoad(storageKey(*_location), this); } else { if (_toCache == LoadToCacheAsWell) { - MediaKey mkey = mediaKey(_locationType, _dc, _id); + MediaKey mkey = mediaKey(_locationType, _dc, _id, _version); if (_locationType == DocumentFileLocation) { _localTaskId = Local::startStickerImageLoad(mkey, this); } else if (_locationType == AudioFileLocation) { diff --git a/Telegram/SourceFiles/mtproto/file_download.h b/Telegram/SourceFiles/mtproto/file_download.h index f8a05d7ea6..94b65fb2b4 100644 --- a/Telegram/SourceFiles/mtproto/file_download.h +++ b/Telegram/SourceFiles/mtproto/file_download.h @@ -28,6 +28,8 @@ namespace MTP { enum LocationType { UnknownFileLocation = 0, + // 1, 2, etc are used as "version" value in mediaKey() method. + DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation @@ -221,9 +223,8 @@ class mtpFileLoader : public FileLoader, public RPCSender { Q_OBJECT public: - mtpFileLoader(const StorageImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading); - mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, LocationType type, const QString &toFile, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading); + mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, int32 version, LocationType type, const QString &toFile, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading); virtual int32 currentOffset(bool includeSkipped = false) const; @@ -245,7 +246,6 @@ public: ~mtpFileLoader(); protected: - virtual bool tryLoadLocal(); virtual void cancelRequests(); @@ -256,15 +256,16 @@ protected: void partLoaded(int32 offset, const MTPupload_File &result, mtpRequestId req); bool partFailed(const RPCError &error); - bool _lastComplete; - int32 _skippedBytes; - int32 _nextRequestOffset; + bool _lastComplete = false; + int32 _skippedBytes = 0; + int32 _nextRequestOffset = 0; int32 _dc; - const StorageImageLocation *_location; + const StorageImageLocation *_location = nullptr; - uint64 _id; // for other locations - uint64 _access; + uint64 _id = 0; // for other locations + uint64 _access = 0; + int32 _version = 0; }; diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index aaa8866758..d1179d198a 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -168,7 +168,7 @@ inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#4e45abe9 id:long access_hash:long = InputFileLocation; +inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputPhotoCropAuto#ade6b004 = InputPhotoCrop; inputPhotoCrop#d9915325 crop_left:double crop_top:double crop_width:double = InputPhotoCrop; @@ -393,6 +393,7 @@ updateInlineBotCallbackQuery#2cbd95af query_id:long user_id:int msg_id:InputBotI updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; +updateRecentStickers#9a422c20 = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -455,7 +456,7 @@ inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; -document#f9a39f4f id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector = Document; +document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; @@ -507,7 +508,6 @@ documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = Docume documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeVersion#99cd09ab version:int = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; @@ -549,7 +549,7 @@ chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#93e99b60 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string = ChatInvite; +chatInvite#2d492881 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; @@ -701,6 +701,9 @@ draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?in messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#ed6392b7 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; +messages.recentStickersNotModified#b17f890 = messages.RecentStickers; +messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -837,6 +840,9 @@ messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flag messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#e21cbb = Bool; +messages.getRecentStickers#99197c2c hash:int = messages.RecentStickers; +messages.clearRecentStickers#ab02e5d2 = Bool; +messages.getUnusedStickers#a978d356 limit:int = Vector; updates.getState#edd4882a = updates.State; updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp index 9b4b655c16..5669a5323b 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp +++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp @@ -828,6 +828,7 @@ void _serialize_inputDocumentFileLocation(MTPStringLogger &to, int32 stage, int3 switch (stage) { case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" version: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -3016,6 +3017,10 @@ void _serialize_updateReadFeaturedStickers(MTPStringLogger &to, int32 stage, int to.add("{ updateReadFeaturedStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } +void _serialize_updateRecentStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + to.add("{ updateRecentStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); +} + void _serialize_updates_state(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -3676,7 +3681,8 @@ void _serialize_document(MTPStringLogger &to, int32 stage, int32 lev, Types &typ case 4: to.add(" size: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 5: to.add(" thumb: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 6: to.add(" dc_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 7: to.add(" attributes: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 7: to.add(" version: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 8: to.add(" attributes: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -4018,19 +4024,6 @@ void _serialize_documentAttributeFilename(MTPStringLogger &to, int32 stage, int3 } } -void _serialize_documentAttributeVersion(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { - if (stage) { - to.add(",\n").addSpaces(lev); - } else { - to.add("{ documentAttributeVersion"); - to.add("\n").addSpaces(lev); - } - switch (stage) { - case 0: to.add(" version: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; - } -} - void _serialize_messages_stickersNotModified(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ messages_stickersNotModified }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -4356,6 +4349,8 @@ void _serialize_chatInvite(MTPStringLogger &to, int32 stage, int32 lev, Types &t case 3: to.add(" public: "); ++stages.back(); if (flag & MTPDchatInvite::Flag::f_public) { to.add("YES [ BY BIT 2 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; case 4: to.add(" megagroup: "); ++stages.back(); if (flag & MTPDchatInvite::Flag::f_megagroup) { to.add("YES [ BY BIT 3 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; case 5: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 6: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 7: to.add(" participants: "); ++stages.back(); if (flag & MTPDchatInvite::Flag::f_participants) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -5783,6 +5778,24 @@ void _serialize_messages_featuredStickers(MTPStringLogger &to, int32 stage, int3 } } +void _serialize_messages_recentStickersNotModified(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + to.add("{ messages_recentStickersNotModified }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); +} + +void _serialize_messages_recentStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_recentStickers"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" stickers: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -6405,6 +6418,10 @@ void _serialize_messages_readFeaturedStickers(MTPStringLogger &to, int32 stage, to.add("{ messages_readFeaturedStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } +void _serialize_messages_clearRecentStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + to.add("{ messages_clearRecentStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); +} + void _serialize_upload_saveFilePart(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -8084,6 +8101,32 @@ void _serialize_messages_getFeaturedStickers(MTPStringLogger &to, int32 stage, i } } +void _serialize_messages_getRecentStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_getRecentStickers"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + +void _serialize_messages_getUnusedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_getUnusedStickers"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_updates_getState(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ updates_getState }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -8542,6 +8585,7 @@ namespace { _serializers.insert(mtpc_updateReadChannelOutbox, _serialize_updateReadChannelOutbox); _serializers.insert(mtpc_updateDraftMessage, _serialize_updateDraftMessage); _serializers.insert(mtpc_updateReadFeaturedStickers, _serialize_updateReadFeaturedStickers); + _serializers.insert(mtpc_updateRecentStickers, _serialize_updateRecentStickers); _serializers.insert(mtpc_updates_state, _serialize_updates_state); _serializers.insert(mtpc_updates_differenceEmpty, _serialize_updates_differenceEmpty); _serializers.insert(mtpc_updates_difference, _serialize_updates_difference); @@ -8625,7 +8669,6 @@ namespace { _serializers.insert(mtpc_documentAttributeVideo, _serialize_documentAttributeVideo); _serializers.insert(mtpc_documentAttributeAudio, _serialize_documentAttributeAudio); _serializers.insert(mtpc_documentAttributeFilename, _serialize_documentAttributeFilename); - _serializers.insert(mtpc_documentAttributeVersion, _serialize_documentAttributeVersion); _serializers.insert(mtpc_messages_stickersNotModified, _serialize_messages_stickersNotModified); _serializers.insert(mtpc_messages_stickers, _serialize_messages_stickers); _serializers.insert(mtpc_stickerPack, _serialize_stickerPack); @@ -8758,6 +8801,8 @@ namespace { _serializers.insert(mtpc_draftMessage, _serialize_draftMessage); _serializers.insert(mtpc_messages_featuredStickersNotModified, _serialize_messages_featuredStickersNotModified); _serializers.insert(mtpc_messages_featuredStickers, _serialize_messages_featuredStickers); + _serializers.insert(mtpc_messages_recentStickersNotModified, _serialize_messages_recentStickersNotModified); + _serializers.insert(mtpc_messages_recentStickers, _serialize_messages_recentStickers); _serializers.insert(mtpc_req_pq, _serialize_req_pq); _serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params); @@ -8805,6 +8850,7 @@ namespace { _serializers.insert(mtpc_messages_setBotCallbackAnswer, _serialize_messages_setBotCallbackAnswer); _serializers.insert(mtpc_messages_saveDraft, _serialize_messages_saveDraft); _serializers.insert(mtpc_messages_readFeaturedStickers, _serialize_messages_readFeaturedStickers); + _serializers.insert(mtpc_messages_clearRecentStickers, _serialize_messages_clearRecentStickers); _serializers.insert(mtpc_upload_saveFilePart, _serialize_upload_saveFilePart); _serializers.insert(mtpc_upload_saveBigFilePart, _serialize_upload_saveBigFilePart); _serializers.insert(mtpc_help_saveAppLog, _serialize_help_saveAppLog); @@ -8924,6 +8970,8 @@ namespace { _serializers.insert(mtpc_messages_getBotCallbackAnswer, _serialize_messages_getBotCallbackAnswer); _serializers.insert(mtpc_messages_getPeerDialogs, _serialize_messages_getPeerDialogs); _serializers.insert(mtpc_messages_getFeaturedStickers, _serialize_messages_getFeaturedStickers); + _serializers.insert(mtpc_messages_getRecentStickers, _serialize_messages_getRecentStickers); + _serializers.insert(mtpc_messages_getUnusedStickers, _serialize_messages_getUnusedStickers); _serializers.insert(mtpc_updates_getState, _serialize_updates_getState); _serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference); _serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference); diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h index 0c0d69db2c..e0e2cb8975 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.h +++ b/Telegram/SourceFiles/mtproto/scheme_auto.h @@ -112,7 +112,7 @@ enum { mtpc_inputPhoto = 0xfb95c6c4, mtpc_inputFileLocation = 0x14637196, mtpc_inputEncryptedFileLocation = 0xf5235d55, - mtpc_inputDocumentFileLocation = 0x4e45abe9, + mtpc_inputDocumentFileLocation = 0x430f0724, mtpc_inputPhotoCropAuto = 0xade6b004, mtpc_inputPhotoCrop = 0xd9915325, mtpc_inputAppEvent = 0x770656a8, @@ -289,6 +289,7 @@ enum { mtpc_updateReadChannelOutbox = 0x25d6c9c7, mtpc_updateDraftMessage = 0xee2bb969, mtpc_updateReadFeaturedStickers = 0x571d2742, + mtpc_updateRecentStickers = 0x9a422c20, mtpc_updates_state = 0xa56c2a3e, mtpc_updates_differenceEmpty = 0x5d75a138, mtpc_updates_difference = 0xf49ca0, @@ -331,7 +332,7 @@ enum { mtpc_inputDocumentEmpty = 0x72f0eaae, mtpc_inputDocument = 0x18798952, mtpc_documentEmpty = 0x36f8c871, - mtpc_document = 0xf9a39f4f, + mtpc_document = 0x87232bc7, mtpc_help_support = 0x17c6b5f6, mtpc_notifyPeer = 0x9fd40bd8, mtpc_notifyUsers = 0xb4c83b4c, @@ -372,7 +373,6 @@ enum { mtpc_documentAttributeVideo = 0x5910cccb, mtpc_documentAttributeAudio = 0x9852f9c6, mtpc_documentAttributeFilename = 0x15590068, - mtpc_documentAttributeVersion = 0x99cd09ab, mtpc_messages_stickersNotModified = 0xf1749a22, mtpc_messages_stickers = 0x8a8ecd32, mtpc_stickerPack = 0x12b299d4, @@ -398,7 +398,7 @@ enum { mtpc_chatInviteEmpty = 0x69df3769, mtpc_chatInviteExported = 0xfc2e05bc, mtpc_chatInviteAlready = 0x5a686d7c, - mtpc_chatInvite = 0x93e99b60, + mtpc_chatInvite = 0x2d492881, mtpc_inputStickerSetEmpty = 0xffb62b95, mtpc_inputStickerSetID = 0x9de7a269, mtpc_inputStickerSetShortName = 0x861cc8a0, @@ -505,6 +505,8 @@ enum { mtpc_draftMessage = 0xfd8e711f, mtpc_messages_featuredStickersNotModified = 0x4ede3cf, mtpc_messages_featuredStickers = 0xed6392b7, + mtpc_messages_recentStickersNotModified = 0xb17f890, + mtpc_messages_recentStickers = 0x5ce20970, mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsgs = 0x3dc4b4f0, mtpc_initConnection = 0x69796de9, @@ -634,6 +636,9 @@ enum { mtpc_messages_getAllDrafts = 0x6a3f8d65, mtpc_messages_getFeaturedStickers = 0x2dacca4f, mtpc_messages_readFeaturedStickers = 0xe21cbb, + mtpc_messages_getRecentStickers = 0x99197c2c, + mtpc_messages_clearRecentStickers = 0xab02e5d2, + mtpc_messages_getUnusedStickers = 0xa978d356, mtpc_updates_getState = 0xedd4882a, mtpc_updates_getDifference = 0xa041495, mtpc_updates_getChannelDifference = 0xbb32d7c0, @@ -1139,7 +1144,6 @@ class MTPDdocumentAttributeSticker; class MTPDdocumentAttributeVideo; class MTPDdocumentAttributeAudio; class MTPDdocumentAttributeFilename; -class MTPDdocumentAttributeVersion; class MTPmessages_stickers; class MTPDmessages_stickers; @@ -1363,6 +1367,9 @@ class MTPDdraftMessage; class MTPmessages_featuredStickers; class MTPDmessages_featuredStickers; +class MTPmessages_recentStickers; +class MTPDmessages_recentStickers; + // Boxed types definitions typedef MTPBoxed MTPResPQ; @@ -1538,6 +1545,7 @@ typedef MTPBoxed MTPTopPeerCategoryPeers; typedef MTPBoxed MTPcontacts_TopPeers; typedef MTPBoxed MTPDraftMessage; typedef MTPBoxed MTPmessages_FeaturedStickers; +typedef MTPBoxed MTPmessages_RecentStickers; // Type classes definitions @@ -6973,18 +6981,6 @@ public: return *(const MTPDdocumentAttributeFilename*)data; } - MTPDdocumentAttributeVersion &_documentAttributeVersion() { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_documentAttributeVersion) throw mtpErrorWrongTypeId(_type, mtpc_documentAttributeVersion); - split(); - return *(MTPDdocumentAttributeVersion*)data; - } - const MTPDdocumentAttributeVersion &c_documentAttributeVersion() const { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_documentAttributeVersion) throw mtpErrorWrongTypeId(_type, mtpc_documentAttributeVersion); - return *(const MTPDdocumentAttributeVersion*)data; - } - uint32 innerLength() const; mtpTypeId type() const; void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); @@ -6999,7 +6995,6 @@ private: explicit MTPdocumentAttribute(MTPDdocumentAttributeVideo *_data); explicit MTPdocumentAttribute(MTPDdocumentAttributeAudio *_data); explicit MTPdocumentAttribute(MTPDdocumentAttributeFilename *_data); - explicit MTPdocumentAttribute(MTPDdocumentAttributeVersion *_data); friend class MTP::internal::TypeCreator; @@ -9593,6 +9588,43 @@ private: }; typedef MTPBoxed MTPmessages_FeaturedStickers; +class MTPmessages_recentStickers : private mtpDataOwner { +public: + MTPmessages_recentStickers() : mtpDataOwner(0), _type(0) { + } + MTPmessages_recentStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_recentStickers &_messages_recentStickers() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_recentStickers) throw mtpErrorWrongTypeId(_type, mtpc_messages_recentStickers); + split(); + return *(MTPDmessages_recentStickers*)data; + } + const MTPDmessages_recentStickers &c_messages_recentStickers() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_recentStickers) throw mtpErrorWrongTypeId(_type, mtpc_messages_recentStickers); + return *(const MTPDmessages_recentStickers*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_recentStickers(mtpTypeId type); + explicit MTPmessages_recentStickers(MTPDmessages_recentStickers *_data); + + friend class MTP::internal::TypeCreator; + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_RecentStickers; + // Type constructors with data class MTPDresPQ : public mtpDataImpl { @@ -10185,11 +10217,12 @@ class MTPDinputDocumentFileLocation : public mtpDataImpl { @@ -12612,7 +12645,7 @@ class MTPDdocument : public mtpDataImpl { public: MTPDdocument() { } - MTPDdocument(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, const MTPVector &_attributes) : vid(_id), vaccess_hash(_access_hash), vdate(_date), vmime_type(_mime_type), vsize(_size), vthumb(_thumb), vdc_id(_dc_id), vattributes(_attributes) { + MTPDdocument(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, MTPint _version, const MTPVector &_attributes) : vid(_id), vaccess_hash(_access_hash), vdate(_date), vmime_type(_mime_type), vsize(_size), vthumb(_thumb), vdc_id(_dc_id), vversion(_version), vattributes(_attributes) { } MTPlong vid; @@ -12622,6 +12655,7 @@ public: MTPint vsize; MTPPhotoSize vthumb; MTPint vdc_id; + MTPint vversion; MTPVector vattributes; }; @@ -12833,16 +12867,6 @@ public: MTPstring vfile_name; }; -class MTPDdocumentAttributeVersion : public mtpDataImpl { -public: - MTPDdocumentAttributeVersion() { - } - MTPDdocumentAttributeVersion(MTPint _version) : vversion(_version) { - } - - MTPint vversion; -}; - class MTPDmessages_stickers : public mtpDataImpl { public: MTPDmessages_stickers() { @@ -13121,8 +13145,9 @@ public: f_broadcast = (1 << 1), f_public = (1 << 2), f_megagroup = (1 << 3), + f_participants = (1 << 4), - MAX_FIELD = (1 << 3), + MAX_FIELD = (1 << 4), }; Q_DECLARE_FLAGS(Flags, Flag); friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } @@ -13131,14 +13156,17 @@ public: bool is_broadcast() const { return vflags.v & Flag::f_broadcast; } bool is_public() const { return vflags.v & Flag::f_public; } bool is_megagroup() const { return vflags.v & Flag::f_megagroup; } + bool has_participants() const { return vflags.v & Flag::f_participants; } MTPDchatInvite() { } - MTPDchatInvite(const MTPflags &_flags, const MTPstring &_title) : vflags(_flags), vtitle(_title) { + MTPDchatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, const MTPVector &_participants) : vflags(_flags), vtitle(_title), vphoto(_photo), vparticipants(_participants) { } MTPflags vflags; MTPstring vtitle; + MTPChatPhoto vphoto; + MTPVector vparticipants; }; class MTPDinputStickerSetID : public mtpDataImpl { @@ -14500,6 +14528,17 @@ public: MTPVector vunread; }; +class MTPDmessages_recentStickers : public mtpDataImpl { +public: + MTPDmessages_recentStickers() { + } + MTPDmessages_recentStickers(MTPint _hash, const MTPVector &_stickers) : vhash(_hash), vstickers(_stickers) { + } + + MTPint vhash; + MTPVector vstickers; +}; + // RPC methods class MTPreq_pq { // RPC method 'req_pq' @@ -20561,6 +20600,115 @@ public: } }; +class MTPmessages_getRecentStickers { // RPC method 'messages.getRecentStickers' +public: + MTPint vhash; + + MTPmessages_getRecentStickers() { + } + MTPmessages_getRecentStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getRecentStickers) { + read(from, end, cons); + } + MTPmessages_getRecentStickers(MTPint _hash) : vhash(_hash) { + } + + uint32 innerLength() const { + return vhash.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_getRecentStickers; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getRecentStickers) { + vhash.read(from, end); + } + void write(mtpBuffer &to) const { + vhash.write(to); + } + + typedef MTPmessages_RecentStickers ResponseType; +}; +class MTPmessages_GetRecentStickers : public MTPBoxed { +public: + MTPmessages_GetRecentStickers() { + } + MTPmessages_GetRecentStickers(const MTPmessages_getRecentStickers &v) : MTPBoxed(v) { + } + MTPmessages_GetRecentStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetRecentStickers(MTPint _hash) : MTPBoxed(MTPmessages_getRecentStickers(_hash)) { + } +}; + +class MTPmessages_clearRecentStickers { // RPC method 'messages.clearRecentStickers' +public: + MTPmessages_clearRecentStickers() { + } + MTPmessages_clearRecentStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_clearRecentStickers) { + read(from, end, cons); + } + + uint32 innerLength() const { + return 0; + } + mtpTypeId type() const { + return mtpc_messages_clearRecentStickers; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_clearRecentStickers) { + } + void write(mtpBuffer &to) const { + } + + typedef MTPBool ResponseType; +}; +class MTPmessages_ClearRecentStickers : public MTPBoxed { +public: + MTPmessages_ClearRecentStickers() { + } + MTPmessages_ClearRecentStickers(const MTPmessages_clearRecentStickers &v) : MTPBoxed(v) { + } + MTPmessages_ClearRecentStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } +}; + +class MTPmessages_getUnusedStickers { // RPC method 'messages.getUnusedStickers' +public: + MTPint vlimit; + + MTPmessages_getUnusedStickers() { + } + MTPmessages_getUnusedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getUnusedStickers) { + read(from, end, cons); + } + MTPmessages_getUnusedStickers(MTPint _limit) : vlimit(_limit) { + } + + uint32 innerLength() const { + return vlimit.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_getUnusedStickers; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getUnusedStickers) { + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + vlimit.write(to); + } + + typedef MTPVector ResponseType; +}; +class MTPmessages_GetUnusedStickers : public MTPBoxed { +public: + MTPmessages_GetUnusedStickers() { + } + MTPmessages_GetUnusedStickers(const MTPmessages_getUnusedStickers &v) : MTPBoxed(v) { + } + MTPmessages_GetUnusedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetUnusedStickers(MTPint _limit) : MTPBoxed(MTPmessages_getUnusedStickers(_limit)) { + } +}; + class MTPupdates_getState { // RPC method 'updates.getState' public: MTPupdates_getState() { @@ -22574,8 +22722,8 @@ public: inline static MTPinputFileLocation new_inputEncryptedFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { return MTPinputFileLocation(new MTPDinputEncryptedFileLocation(_id, _access_hash)); } - inline static MTPinputFileLocation new_inputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { - return MTPinputFileLocation(new MTPDinputDocumentFileLocation(_id, _access_hash)); + inline static MTPinputFileLocation new_inputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash, MTPint _version) { + return MTPinputFileLocation(new MTPDinputDocumentFileLocation(_id, _access_hash, _version)); } inline static MTPinputPhotoCrop new_inputPhotoCropAuto() { return MTPinputPhotoCrop(mtpc_inputPhotoCropAuto); @@ -23105,6 +23253,9 @@ public: inline static MTPupdate new_updateReadFeaturedStickers() { return MTPupdate(mtpc_updateReadFeaturedStickers); } + inline static MTPupdate new_updateRecentStickers() { + return MTPupdate(mtpc_updateRecentStickers); + } inline static MTPupdates_state new_updates_state(MTPint _pts, MTPint _qts, MTPint _date, MTPint _seq, MTPint _unread_count) { return MTPupdates_state(new MTPDupdates_state(_pts, _qts, _date, _seq, _unread_count)); } @@ -23231,8 +23382,8 @@ public: inline static MTPdocument new_documentEmpty(const MTPlong &_id) { return MTPdocument(new MTPDdocumentEmpty(_id)); } - inline static MTPdocument new_document(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, const MTPVector &_attributes) { - return MTPdocument(new MTPDdocument(_id, _access_hash, _date, _mime_type, _size, _thumb, _dc_id, _attributes)); + inline static MTPdocument new_document(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, MTPint _version, const MTPVector &_attributes) { + return MTPdocument(new MTPDdocument(_id, _access_hash, _date, _mime_type, _size, _thumb, _dc_id, _version, _attributes)); } inline static MTPhelp_support new_help_support(const MTPstring &_phone_number, const MTPUser &_user) { return MTPhelp_support(new MTPDhelp_support(_phone_number, _user)); @@ -23354,9 +23505,6 @@ public: inline static MTPdocumentAttribute new_documentAttributeFilename(const MTPstring &_file_name) { return MTPdocumentAttribute(new MTPDdocumentAttributeFilename(_file_name)); } - inline static MTPdocumentAttribute new_documentAttributeVersion(MTPint _version) { - return MTPdocumentAttribute(new MTPDdocumentAttributeVersion(_version)); - } inline static MTPmessages_stickers new_messages_stickersNotModified() { return MTPmessages_stickers(mtpc_messages_stickersNotModified); } @@ -23432,8 +23580,8 @@ public: inline static MTPchatInvite new_chatInviteAlready(const MTPChat &_chat) { return MTPchatInvite(new MTPDchatInviteAlready(_chat)); } - inline static MTPchatInvite new_chatInvite(const MTPflags &_flags, const MTPstring &_title) { - return MTPchatInvite(new MTPDchatInvite(_flags, _title)); + inline static MTPchatInvite new_chatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, const MTPVector &_participants) { + return MTPchatInvite(new MTPDchatInvite(_flags, _title, _photo, _participants)); } inline static MTPinputStickerSet new_inputStickerSetEmpty() { return MTPinputStickerSet(mtpc_inputStickerSetEmpty); @@ -23753,6 +23901,12 @@ public: inline static MTPmessages_featuredStickers new_messages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) { return MTPmessages_featuredStickers(new MTPDmessages_featuredStickers(_hash, _sets, _unread)); } + inline static MTPmessages_recentStickers new_messages_recentStickersNotModified() { + return MTPmessages_recentStickers(mtpc_messages_recentStickersNotModified); + } + inline static MTPmessages_recentStickers new_messages_recentStickers(MTPint _hash, const MTPVector &_stickers) { + return MTPmessages_recentStickers(new MTPDmessages_recentStickers(_hash, _stickers)); + } }; } // namespace internal @@ -25419,7 +25573,7 @@ inline uint32 MTPinputFileLocation::innerLength() const { } case mtpc_inputDocumentFileLocation: { const MTPDinputDocumentFileLocation &v(c_inputDocumentFileLocation()); - return v.vid.innerLength() + v.vaccess_hash.innerLength(); + return v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vversion.innerLength(); } } return 0; @@ -25449,6 +25603,7 @@ inline void MTPinputFileLocation::read(const mtpPrime *&from, const mtpPrime *en MTPDinputDocumentFileLocation &v(_inputDocumentFileLocation()); v.vid.read(from, end); v.vaccess_hash.read(from, end); + v.vversion.read(from, end); } break; default: throw mtpErrorUnexpected(cons, "MTPinputFileLocation"); } @@ -25470,6 +25625,7 @@ inline void MTPinputFileLocation::write(mtpBuffer &to) const { const MTPDinputDocumentFileLocation &v(c_inputDocumentFileLocation()); v.vid.write(to); v.vaccess_hash.write(to); + v.vversion.write(to); } break; } } @@ -25493,8 +25649,8 @@ inline MTPinputFileLocation MTP_inputFileLocation(const MTPlong &_volume_id, MTP inline MTPinputFileLocation MTP_inputEncryptedFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { return MTP::internal::TypeCreator::new_inputEncryptedFileLocation(_id, _access_hash); } -inline MTPinputFileLocation MTP_inputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { - return MTP::internal::TypeCreator::new_inputDocumentFileLocation(_id, _access_hash); +inline MTPinputFileLocation MTP_inputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash, MTPint _version) { + return MTP::internal::TypeCreator::new_inputDocumentFileLocation(_id, _access_hash, _version); } inline uint32 MTPinputPhotoCrop::innerLength() const { @@ -28971,6 +29127,7 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI v.vdraft.read(from, end); } break; case mtpc_updateReadFeaturedStickers: _type = cons; break; + case mtpc_updateRecentStickers: _type = cons; break; default: throw mtpErrorUnexpected(cons, "MTPupdate"); } } @@ -29305,6 +29462,7 @@ inline MTPupdate::MTPupdate(mtpTypeId type) : mtpDataOwner(0), _type(type) { case mtpc_updateReadChannelOutbox: setData(new MTPDupdateReadChannelOutbox()); break; case mtpc_updateDraftMessage: setData(new MTPDupdateDraftMessage()); break; case mtpc_updateReadFeaturedStickers: break; + case mtpc_updateRecentStickers: break; default: throw mtpErrorBadTypeId(type, "MTPupdate"); } } @@ -29555,6 +29713,9 @@ inline MTPupdate MTP_updateDraftMessage(const MTPPeer &_peer, const MTPDraftMess inline MTPupdate MTP_updateReadFeaturedStickers() { return MTP::internal::TypeCreator::new_updateReadFeaturedStickers(); } +inline MTPupdate MTP_updateRecentStickers() { + return MTP::internal::TypeCreator::new_updateRecentStickers(); +} inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) { } @@ -30864,7 +31025,7 @@ inline uint32 MTPdocument::innerLength() const { } case mtpc_document: { const MTPDdocument &v(c_document()); - return v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vdate.innerLength() + v.vmime_type.innerLength() + v.vsize.innerLength() + v.vthumb.innerLength() + v.vdc_id.innerLength() + v.vattributes.innerLength(); + return v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vdate.innerLength() + v.vmime_type.innerLength() + v.vsize.innerLength() + v.vthumb.innerLength() + v.vdc_id.innerLength() + v.vversion.innerLength() + v.vattributes.innerLength(); } } return 0; @@ -30891,6 +31052,7 @@ inline void MTPdocument::read(const mtpPrime *&from, const mtpPrime *end, mtpTyp v.vsize.read(from, end); v.vthumb.read(from, end); v.vdc_id.read(from, end); + v.vversion.read(from, end); v.vattributes.read(from, end); } break; default: throw mtpErrorUnexpected(cons, "MTPdocument"); @@ -30911,6 +31073,7 @@ inline void MTPdocument::write(mtpBuffer &to) const { v.vsize.write(to); v.vthumb.write(to); v.vdc_id.write(to); + v.vversion.write(to); v.vattributes.write(to); } break; } @@ -30929,8 +31092,8 @@ inline MTPdocument::MTPdocument(MTPDdocument *_data) : mtpDataOwner(_data), _typ inline MTPdocument MTP_documentEmpty(const MTPlong &_id) { return MTP::internal::TypeCreator::new_documentEmpty(_id); } -inline MTPdocument MTP_document(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, const MTPVector &_attributes) { - return MTP::internal::TypeCreator::new_document(_id, _access_hash, _date, _mime_type, _size, _thumb, _dc_id, _attributes); +inline MTPdocument MTP_document(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, const MTPstring &_mime_type, MTPint _size, const MTPPhotoSize &_thumb, MTPint _dc_id, MTPint _version, const MTPVector &_attributes) { + return MTP::internal::TypeCreator::new_document(_id, _access_hash, _date, _mime_type, _size, _thumb, _dc_id, _version, _attributes); } inline MTPhelp_support::MTPhelp_support() : mtpDataOwner(new MTPDhelp_support()) { @@ -31487,10 +31650,6 @@ inline uint32 MTPdocumentAttribute::innerLength() const { const MTPDdocumentAttributeFilename &v(c_documentAttributeFilename()); return v.vfile_name.innerLength(); } - case mtpc_documentAttributeVersion: { - const MTPDdocumentAttributeVersion &v(c_documentAttributeVersion()); - return v.vversion.innerLength(); - } } return 0; } @@ -31535,11 +31694,6 @@ inline void MTPdocumentAttribute::read(const mtpPrime *&from, const mtpPrime *en MTPDdocumentAttributeFilename &v(_documentAttributeFilename()); v.vfile_name.read(from, end); } break; - case mtpc_documentAttributeVersion: _type = cons; { - if (!data) setData(new MTPDdocumentAttributeVersion()); - MTPDdocumentAttributeVersion &v(_documentAttributeVersion()); - v.vversion.read(from, end); - } break; default: throw mtpErrorUnexpected(cons, "MTPdocumentAttribute"); } } @@ -31573,10 +31727,6 @@ inline void MTPdocumentAttribute::write(mtpBuffer &to) const { const MTPDdocumentAttributeFilename &v(c_documentAttributeFilename()); v.vfile_name.write(to); } break; - case mtpc_documentAttributeVersion: { - const MTPDdocumentAttributeVersion &v(c_documentAttributeVersion()); - v.vversion.write(to); - } break; } } inline MTPdocumentAttribute::MTPdocumentAttribute(mtpTypeId type) : mtpDataOwner(0), _type(type) { @@ -31587,7 +31737,6 @@ inline MTPdocumentAttribute::MTPdocumentAttribute(mtpTypeId type) : mtpDataOwner case mtpc_documentAttributeVideo: setData(new MTPDdocumentAttributeVideo()); break; case mtpc_documentAttributeAudio: setData(new MTPDdocumentAttributeAudio()); break; case mtpc_documentAttributeFilename: setData(new MTPDdocumentAttributeFilename()); break; - case mtpc_documentAttributeVersion: setData(new MTPDdocumentAttributeVersion()); break; default: throw mtpErrorBadTypeId(type, "MTPdocumentAttribute"); } } @@ -31601,8 +31750,6 @@ inline MTPdocumentAttribute::MTPdocumentAttribute(MTPDdocumentAttributeAudio *_d } inline MTPdocumentAttribute::MTPdocumentAttribute(MTPDdocumentAttributeFilename *_data) : mtpDataOwner(_data), _type(mtpc_documentAttributeFilename) { } -inline MTPdocumentAttribute::MTPdocumentAttribute(MTPDdocumentAttributeVersion *_data) : mtpDataOwner(_data), _type(mtpc_documentAttributeVersion) { -} inline MTPdocumentAttribute MTP_documentAttributeImageSize(MTPint _w, MTPint _h) { return MTP::internal::TypeCreator::new_documentAttributeImageSize(_w, _h); } @@ -31622,9 +31769,6 @@ inline MTPdocumentAttribute MTP_documentAttributeAudio(const MTPflags(); } } break; default: throw mtpErrorUnexpected(cons, "MTPchatInvite"); } @@ -32333,6 +32479,8 @@ inline void MTPchatInvite::write(mtpBuffer &to) const { const MTPDchatInvite &v(c_chatInvite()); v.vflags.write(to); v.vtitle.write(to); + v.vphoto.write(to); + if (v.has_participants()) v.vparticipants.write(to); } break; } } @@ -32351,8 +32499,8 @@ inline MTPchatInvite MTP_chatInviteAlready(const MTPChat &_chat) { return MTP::internal::TypeCreator::new_chatInviteAlready(_chat); } Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDchatInvite::Flags) -inline MTPchatInvite MTP_chatInvite(const MTPflags &_flags, const MTPstring &_title) { - return MTP::internal::TypeCreator::new_chatInvite(_flags, _title); +inline MTPchatInvite MTP_chatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, const MTPVector &_participants) { + return MTP::internal::TypeCreator::new_chatInvite(_flags, _title, _photo, _participants); } inline uint32 MTPinputStickerSet::innerLength() const { @@ -35152,6 +35300,57 @@ inline MTPmessages_featuredStickers MTP_messages_featuredStickersNotModified() { inline MTPmessages_featuredStickers MTP_messages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) { return MTP::internal::TypeCreator::new_messages_featuredStickers(_hash, _sets, _unread); } + +inline uint32 MTPmessages_recentStickers::innerLength() const { + switch (_type) { + case mtpc_messages_recentStickers: { + const MTPDmessages_recentStickers &v(c_messages_recentStickers()); + return v.vhash.innerLength() + v.vstickers.innerLength(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_recentStickers::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_recentStickers::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_recentStickersNotModified: _type = cons; break; + case mtpc_messages_recentStickers: _type = cons; { + if (!data) setData(new MTPDmessages_recentStickers()); + MTPDmessages_recentStickers &v(_messages_recentStickers()); + v.vhash.read(from, end); + v.vstickers.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_recentStickers"); + } +} +inline void MTPmessages_recentStickers::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_recentStickers: { + const MTPDmessages_recentStickers &v(c_messages_recentStickers()); + v.vhash.write(to); + v.vstickers.write(to); + } break; + } +} +inline MTPmessages_recentStickers::MTPmessages_recentStickers(mtpTypeId type) : mtpDataOwner(0), _type(type) { + switch (type) { + case mtpc_messages_recentStickersNotModified: break; + case mtpc_messages_recentStickers: setData(new MTPDmessages_recentStickers()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_recentStickers"); + } +} +inline MTPmessages_recentStickers::MTPmessages_recentStickers(MTPDmessages_recentStickers *_data) : mtpDataOwner(_data), _type(mtpc_messages_recentStickers) { +} +inline MTPmessages_recentStickers MTP_messages_recentStickersNotModified() { + return MTP::internal::TypeCreator::new_messages_recentStickersNotModified(); +} +inline MTPmessages_recentStickers MTP_messages_recentStickers(MTPint _hash, const MTPVector &_stickers) { + return MTP::internal::TypeCreator::new_messages_recentStickers(_hash, _stickers); +} inline MTPDmessage::Flags mtpCastFlags(MTPDmessageService::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } inline MTPDmessage::Flags mtpCastFlags(MTPflags flags) { return mtpCastFlags(flags.v); } inline MTPDmessage::Flags mtpCastFlags(MTPDupdateShortMessage::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } diff --git a/Telegram/SourceFiles/serialize/serialize_document.cpp b/Telegram/SourceFiles/serialize/serialize_document.cpp index 73823edf56..6f489e690a 100644 --- a/Telegram/SourceFiles/serialize/serialize_document.cpp +++ b/Telegram/SourceFiles/serialize/serialize_document.cpp @@ -37,6 +37,7 @@ namespace Serialize { void Document::writeToStream(QDataStream &stream, DocumentData *document) { stream << quint64(document->id) << quint64(document->_access) << qint32(document->date); + stream << qint32(document->_version); stream << document->name << document->mime << qint32(document->_dc) << qint32(document->size); stream << qint32(document->dimensions.width()) << qint32(document->dimensions.height()); stream << qint32(document->type); @@ -61,11 +62,16 @@ void Document::writeToStream(QDataStream &stream, DocumentData *document) { } } -DocumentData *Document::readFromStreamHelper(QDataStream &stream, const StickerSetInfo *info) { +DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &stream, const StickerSetInfo *info) { quint64 id, access; QString name, mime; - qint32 date, dc, size, width, height, type; + qint32 date, dc, size, width, height, type, version; stream >> id >> access >> date; + if (streamAppVersion >= 9058) { + stream >> version; + } else { + version = 0; + } stream >> name >> mime >> dc >> size; stream >> width >> height; stream >> type; @@ -122,22 +128,22 @@ DocumentData *Document::readFromStreamHelper(QDataStream &stream, const StickerS if (!dc && !access) { return nullptr; } - return App::documentSet(id, nullptr, access, date, attributes, mime, thumb.isNull() ? ImagePtr() : ImagePtr(thumb), dc, size, thumb); + return App::documentSet(id, nullptr, access, version, date, attributes, mime, thumb.isNull() ? ImagePtr() : ImagePtr(thumb), dc, size, thumb); } -DocumentData *Document::readStickerFromStream(QDataStream &stream, const StickerSetInfo &info) { - return readFromStreamHelper(stream, &info); +DocumentData *Document::readStickerFromStream(int streamAppVersion, QDataStream &stream, const StickerSetInfo &info) { + return readFromStreamHelper(streamAppVersion, stream, &info); } -DocumentData *Document::readFromStream(QDataStream &stream) { - return readFromStreamHelper(stream, nullptr); +DocumentData *Document::readFromStream(int streamAppVersion, QDataStream &stream) { + return readFromStreamHelper(streamAppVersion, stream, nullptr); } int Document::sizeInStream(DocumentData *document) { int result = 0; - // id + access + date - result += sizeof(quint64) + sizeof(quint64) + sizeof(qint32); + // id + access + date + version + result += sizeof(quint64) + sizeof(quint64) + sizeof(qint32) + sizeof(qint32); // + namelen + name + mimelen + mime + dc + size result += stringSize(document->name) + stringSize(document->mime) + sizeof(qint32) + sizeof(qint32); // + width + height diff --git a/Telegram/SourceFiles/serialize/serialize_document.h b/Telegram/SourceFiles/serialize/serialize_document.h index b0ed77282d..44ad8cd2fe 100644 --- a/Telegram/SourceFiles/serialize/serialize_document.h +++ b/Telegram/SourceFiles/serialize/serialize_document.h @@ -39,12 +39,12 @@ public: }; static void writeToStream(QDataStream &stream, DocumentData *document); - static DocumentData *readStickerFromStream(QDataStream &stream, const StickerSetInfo &info); - static DocumentData *readFromStream(QDataStream &stream); + static DocumentData *readStickerFromStream(int streamAppVersion, QDataStream &stream, const StickerSetInfo &info); + static DocumentData *readFromStream(int streamAppVersion, QDataStream &stream); static int sizeInStream(DocumentData *document); private: - static DocumentData *readFromStreamHelper(QDataStream &stream, const StickerSetInfo *info); + static DocumentData *readFromStreamHelper(int streamAppVersion, QDataStream &stream, const StickerSetInfo *info); }; diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 662420bc30..cd57d76aa8 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -1082,10 +1082,11 @@ VoiceData::~VoiceData() { DocumentAdditionalData::~DocumentAdditionalData() { } -DocumentData::DocumentData(DocumentId id, int32 dc, uint64 accessHash, const QString &url, const QVector &attributes) +DocumentData::DocumentData(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QString &url, const QVector &attributes) : id(id) , _dc(dc) , _access(accessHash) +, _version(version) , _url(url) { setattributes(attributes); if (_dc && _access) { @@ -1094,15 +1095,15 @@ DocumentData::DocumentData(DocumentId id, int32 dc, uint64 accessHash, const QSt } DocumentData *DocumentData::create(DocumentId id) { - return new DocumentData(id, 0, 0, QString(), QVector()); + return new DocumentData(id, 0, 0, 0, QString(), QVector()); } -DocumentData *DocumentData::create(DocumentId id, int32 dc, uint64 accessHash, const QVector &attributes) { - return new DocumentData(id, dc, accessHash, QString(), attributes); +DocumentData *DocumentData::create(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QVector &attributes) { + return new DocumentData(id, dc, accessHash, version, QString(), attributes); } DocumentData *DocumentData::create(DocumentId id, const QString &url, const QVector &attributes) { - return new DocumentData(id, 0, 0, url, attributes); + return new DocumentData(id, 0, 0, 0, url, attributes); } void DocumentData::setattributes(const QVector &attributes) { @@ -1385,7 +1386,7 @@ void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMs if (!_access && !_url.isEmpty()) { _loader = new webFileLoader(_url, toFile, fromCloud, autoLoading); } else { - _loader = new mtpFileLoader(_dc, id, _access, locationType(), toFile, size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading); + _loader = new mtpFileLoader(_dc, id, _access, _version, locationType(), toFile, size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading); } _loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(documentLoadProgress(FileLoader*))); _loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(documentLoadFailed(FileLoader*,bool))); @@ -1526,6 +1527,22 @@ void DocumentData::recountIsImage() { _duration = fileIsImage(name, mime) ? 1 : -1; // hack } +bool DocumentData::setRemoteVersion(int32 version) { + if (_version == version) { + return false; + } + _version = version; + _location = FileLocation(); + _data = QByteArray(); + status = FileReady; + if (loading()) { + _loader->deleteLater(); + _loader->stop(); + _loader = nullptr; + } + return true; +} + void DocumentData::setRemoteLocation(int32 dc, uint64 access) { _dc = dc; _access = access; diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 1a948de465..876d6a9d66 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -1068,7 +1068,7 @@ class Document; class DocumentData { public: static DocumentData *create(DocumentId id); - static DocumentData *create(DocumentId id, int32 dc, uint64 accessHash, const QVector &attributes); + static DocumentData *create(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QVector &attributes); static DocumentData *create(DocumentId id, const QString &url, const QVector &attributes); void setattributes(const QVector &attributes); @@ -1159,6 +1159,7 @@ public: _data = data; } + bool setRemoteVersion(int32 version); // Returns true if version has changed. void setRemoteLocation(int32 dc, uint64 access); void setContentUrl(const QString &url); bool hasRemoteLocation() const { @@ -1196,11 +1197,11 @@ public: int32 md5[8]; MediaKey mediaKey() const { - return ::mediaKey(locationType(), _dc, id); + return ::mediaKey(locationType(), _dc, id, _version); } private: - DocumentData(DocumentId id, int32 dc, uint64 accessHash, const QString &url, const QVector &attributes); + DocumentData(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QString &url, const QVector &attributes); friend class Serialize::Document; @@ -1208,9 +1209,10 @@ private: return voice() ? AudioFileLocation : (isVideo() ? VideoFileLocation : DocumentFileLocation); } - // Two types of location: from MTProto by dc+access or from web by url + // Two types of location: from MTProto by dc+access+version or from web by url int32 _dc = 0; uint64 _access = 0; + int32 _version = 0; QString _url; FileLocation _location; diff --git a/Telegram/SourceFiles/ui/images.h b/Telegram/SourceFiles/ui/images.h index 8596dbfc47..5bb7c28117 100644 --- a/Telegram/SourceFiles/ui/images.h +++ b/Telegram/SourceFiles/ui/images.h @@ -486,8 +486,13 @@ typedef QPair MediaKey; inline uint64 mediaMix32To64(int32 a, int32 b) { return (uint64(*reinterpret_cast(&a)) << 32) | uint64(*reinterpret_cast(&b)); } -inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) { - return MediaKey(mediaMix32To64(type, dc), id); +// Old method, should not be used anymore. +//inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) { +// return MediaKey(mediaMix32To64(type, dc), id); +//} +// New method when version was introduced, type is not relevant anymore (all files are Documents). +inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id, int32 version) { + return (version > 0) ? MediaKey(mediaMix32To64(version, dc), id) : MediaKey(mediaMix32To64(type, dc), id); } inline StorageKey mediaKey(const MTPDfileLocation &location) { return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v); diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index a50bf242c1..e5022f18dd 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -2375,7 +2375,7 @@ SDKROOT = macosx; SYMROOT = ./../Mac; TDESKTOP_MAJOR_VERSION = 0.9; - TDESKTOP_VERSION = 0.9.57; + TDESKTOP_VERSION = 0.9.58; }; name = Release; }; @@ -2516,7 +2516,7 @@ SDKROOT = macosx; SYMROOT = ./../Mac; TDESKTOP_MAJOR_VERSION = 0.9; - TDESKTOP_VERSION = 0.9.57; + TDESKTOP_VERSION = 0.9.58; }; name = Debug; }; diff --git a/Telegram/build/version b/Telegram/build/version index 4a048eef7e..f5aff1e62d 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,6 +1,6 @@ -AppVersion 9057 +AppVersion 9058 AppVersionStrMajor 0.9 -AppVersionStrSmall 0.9.57 -AppVersionStr 0.9.57 +AppVersionStrSmall 0.9.58 +AppVersionStr 0.9.58 AlphaChannel 1 BetaVersion 0 From 66e2fce8d5cae8622d7ffc86101b91160d113253 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 8 Jul 2016 19:59:46 +0300 Subject: [PATCH 05/13] New design of a chat invite link import box with title, photo, users. --- Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/app.cpp | 744 ++++++++++--------- Telegram/SourceFiles/app.h | 2 + Telegram/SourceFiles/boxes/boxes.style | 50 ++ Telegram/SourceFiles/boxes/confirmbox.cpp | 84 +++ Telegram/SourceFiles/boxes/confirmbox.h | 23 + Telegram/SourceFiles/boxes/stickersetbox.cpp | 4 +- Telegram/SourceFiles/dialogs/dialogs.style | 4 +- Telegram/SourceFiles/mainwidget.cpp | 19 +- Telegram/Telegram.vcxproj | 3 + Telegram/Telegram.vcxproj.filters | 9 + 11 files changed, 572 insertions(+), 372 deletions(-) create mode 100644 Telegram/SourceFiles/boxes/boxes.style diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 3f3a2dc0bb..d05f7de460 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -602,6 +602,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_group_invite_want_join_channel" = "Do you want to join the channel «{title}»?"; "lng_group_invite_join" = "Join"; +"lng_group_invite_members" = "{count:_not_used_|# member|# members}, among them:"; + "lng_group_invite_link" = "Invite link:"; "lng_group_invite_create" = "Create an invite link"; "lng_group_invite_about" = "Telegram users will be able to join\nyour group by following this link."; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 888a7db717..ee5b159b70 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -383,397 +383,413 @@ namespace { return (online > now); } - UserData *feedUsers(const MTPVector &users) { - UserData *result = nullptr; - for_const (auto &user, users.c_vector().v) { - UserData *data = nullptr; - bool wasContact = false, minimal = false; - const MTPUserStatus *status = 0, emptyStatus = MTP_userStatusEmpty(); + UserData *feedUser(const MTPUser &user) { + UserData *data = nullptr; + bool wasContact = false, minimal = false; + const MTPUserStatus *status = 0, emptyStatus = MTP_userStatusEmpty(); - Notify::PeerUpdate update; - using UpdateFlag = Notify::PeerUpdate::Flag; + Notify::PeerUpdate update; + using UpdateFlag = Notify::PeerUpdate::Flag; - switch (user.type()) { - case mtpc_userEmpty: { - const auto &d(user.c_userEmpty()); + switch (user.type()) { + case mtpc_userEmpty: { + auto &d(user.c_userEmpty()); - PeerId peer(peerFromUser(d.vid.v)); - data = App::user(peer); - auto canShareThisContact = data->canShareThisContactFast(); - wasContact = data->isContact(); + PeerId peer(peerFromUser(d.vid.v)); + data = App::user(peer); + auto canShareThisContact = data->canShareThisContactFast(); + wasContact = data->isContact(); - data->input = MTP_inputPeerUser(d.vid, MTP_long(0)); - data->inputUser = MTP_inputUser(d.vid, MTP_long(0)); + data->input = MTP_inputPeerUser(d.vid, MTP_long(0)); + data->inputUser = MTP_inputUser(d.vid, MTP_long(0)); + data->setName(lang(lng_deleted), QString(), QString(), QString()); + data->setPhoto(MTP_userProfilePhotoEmpty()); + data->access = UserNoAccess; + data->flags = 0; + data->setBotInfoVersion(-1); + status = &emptyStatus; + data->contact = -1; + + if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact; + if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact; + } break; + case mtpc_user: { + auto &d(user.c_user()); + minimal = d.is_min(); + + PeerId peer(peerFromUser(d.vid.v)); + data = App::user(peer); + auto canShareThisContact = data->canShareThisContactFast(); + wasContact = data->isContact(); + if (!minimal) { + data->flags = d.vflags.v; + if (d.is_self()) { + data->input = MTP_inputPeerSelf(); + data->inputUser = MTP_inputUserSelf(); + } else if (!d.has_access_hash()) { + data->input = MTP_inputPeerUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access)); + data->inputUser = MTP_inputUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access)); + } else { + data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash); + data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash); + } + if (d.is_restricted()) { + data->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason))); + } else { + data->setRestrictionReason(QString()); + } + } + if (d.is_deleted()) { + if (!data->phone().isEmpty()) { + data->setPhone(QString()); + update.flags |= UpdateFlag::UserPhoneChanged; + } data->setName(lang(lng_deleted), QString(), QString(), QString()); data->setPhoto(MTP_userProfilePhotoEmpty()); data->access = UserNoAccess; - data->flags = 0; - data->setBotInfoVersion(-1); status = &emptyStatus; - data->contact = -1; + } else { + // apply first_name and last_name from minimal user only if we don't have + // local values for first name and last name already, otherwise skip + bool noLocalName = data->firstName.isEmpty() && data->lastName.isEmpty(); + QString fname = (!minimal || noLocalName) ? (d.has_first_name() ? textOneLine(qs(d.vfirst_name)) : QString()) : data->firstName; + QString lname = (!minimal || noLocalName) ? (d.has_last_name() ? textOneLine(qs(d.vlast_name)) : QString()) : data->lastName; - if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact; - if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact; - } break; - case mtpc_user: { - const auto &d(user.c_user()); - minimal = d.is_min(); + QString phone = minimal ? data->phone() : (d.has_phone() ? qs(d.vphone) : QString()); + QString uname = minimal ? data->username : (d.has_username() ? textOneLine(qs(d.vusername)) : QString()); - PeerId peer(peerFromUser(d.vid.v)); - data = App::user(peer); - auto canShareThisContact = data->canShareThisContactFast(); - wasContact = data->isContact(); - if (!minimal) { - data->flags = d.vflags.v; - if (d.is_self()) { - data->input = MTP_inputPeerSelf(); - data->inputUser = MTP_inputUserSelf(); - } else if (!d.has_access_hash()) { - data->input = MTP_inputPeerUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access)); - data->inputUser = MTP_inputUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access)); - } else { - data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash); - data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash); - } - if (d.is_restricted()) { - data->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason))); - } else { - data->setRestrictionReason(QString()); - } + bool phoneChanged = (data->phone() != phone); + if (phoneChanged) { + data->setPhone(phone); + update.flags |= UpdateFlag::UserPhoneChanged; } - if (d.is_deleted()) { - if (!data->phone().isEmpty()) { - data->setPhone(QString()); - update.flags |= UpdateFlag::UserPhoneChanged; - } - data->setName(lang(lng_deleted), QString(), QString(), QString()); - data->setPhoto(MTP_userProfilePhotoEmpty()); - data->access = UserNoAccess; - status = &emptyStatus; + bool nameChanged = (data->firstName != fname) || (data->lastName != lname); + + bool showPhone = !isServiceUser(data->id) && !d.is_self() && !d.is_contact() && !d.is_mutual_contact(); + bool showPhoneChanged = !isServiceUser(data->id) && !d.is_self() && ((showPhone && data->contact) || (!showPhone && !data->contact)); + if (minimal) { + showPhoneChanged = false; + showPhone = !isServiceUser(data->id) && (data->id != peerFromUser(MTP::authedId())) && !data->contact; + } + + // see also Local::readPeer + + QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone; + + if (!minimal && d.is_self() && uname != data->username) { + SignalHandlers::setCrashAnnotation("Username", uname); + } + data->setName(fname, lname, pname, uname); + if (d.has_photo()) { + data->setPhoto(d.vphoto); } else { - // apply first_name and last_name from minimal user only if we don't have - // local values for first name and last name already, otherwise skip - bool noLocalName = data->firstName.isEmpty() && data->lastName.isEmpty(); - QString fname = (!minimal || noLocalName) ? (d.has_first_name() ? textOneLine(qs(d.vfirst_name)) : QString()) : data->firstName; - QString lname = (!minimal || noLocalName) ? (d.has_last_name() ? textOneLine(qs(d.vlast_name)) : QString()) : data->lastName; - - QString phone = minimal ? data->phone() : (d.has_phone() ? qs(d.vphone) : QString()); - QString uname = minimal ? data->username : (d.has_username() ? textOneLine(qs(d.vusername)) : QString()); - - bool phoneChanged = (data->phone() != phone); - if (phoneChanged) { - data->setPhone(phone); - update.flags |= UpdateFlag::UserPhoneChanged; - } - bool nameChanged = (data->firstName != fname) || (data->lastName != lname); - - bool showPhone = !isServiceUser(data->id) && !d.is_self() && !d.is_contact() && !d.is_mutual_contact(); - bool showPhoneChanged = !isServiceUser(data->id) && !d.is_self() && ((showPhone && data->contact) || (!showPhone && !data->contact)); - if (minimal) { - showPhoneChanged = false; - showPhone = !isServiceUser(data->id) && (data->id != peerFromUser(MTP::authedId())) && !data->contact; - } - - // see also Local::readPeer - - QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone; - - if (!minimal && d.is_self() && uname != data->username) { - SignalHandlers::setCrashAnnotation("Username", uname); - } - data->setName(fname, lname, pname, uname); - if (d.has_photo()) { - data->setPhoto(d.vphoto); - } else { - data->setPhoto(MTP_userProfilePhotoEmpty()); - } - if (d.has_access_hash()) data->access = d.vaccess_hash.v; - status = d.has_status() ? &d.vstatus : &emptyStatus; + data->setPhoto(MTP_userProfilePhotoEmpty()); } - if (!minimal) { - if (d.has_bot_info_version()) { - data->setBotInfoVersion(d.vbot_info_version.v); - data->botInfo->readsAllHistory = d.is_bot_chat_history(); - if (data->botInfo->cantJoinGroups != d.is_bot_nochats()) { - data->botInfo->cantJoinGroups = d.is_bot_nochats(); - update.flags |= UpdateFlag::BotCanAddToGroups; - } - data->botInfo->inlinePlaceholder = d.has_bot_inline_placeholder() ? '_' + qs(d.vbot_inline_placeholder) : QString(); - } else { - data->setBotInfoVersion(-1); - } - data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone().isEmpty() ? -1 : 0); - if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsHidden) != dbiprsHidden) { - cRefReportSpamStatuses().insert(data->id, dbiprsHidden); - Local::writeReportSpamStatuses(); - } - if (d.is_self() && ::self != data) { - ::self = data; - if (App::wnd()) App::wnd()->updateGlobalMenu(); + if (d.has_access_hash()) data->access = d.vaccess_hash.v; + status = d.has_status() ? &d.vstatus : &emptyStatus; + } + if (!minimal) { + if (d.has_bot_info_version()) { + data->setBotInfoVersion(d.vbot_info_version.v); + data->botInfo->readsAllHistory = d.is_bot_chat_history(); + if (data->botInfo->cantJoinGroups != d.is_bot_nochats()) { + data->botInfo->cantJoinGroups = d.is_bot_nochats(); + update.flags |= UpdateFlag::BotCanAddToGroups; } + data->botInfo->inlinePlaceholder = d.has_bot_inline_placeholder() ? '_' + qs(d.vbot_inline_placeholder) : QString(); + } else { + data->setBotInfoVersion(-1); } - - if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact; - if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact; - } break; - } - - if (!data) continue; - - if (minimal) { - if (data->loadedStatus == PeerData::NotLoaded) { - data->loadedStatus = PeerData::MinimalLoaded; + data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone().isEmpty() ? -1 : 0); + if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsHidden) != dbiprsHidden) { + cRefReportSpamStatuses().insert(data->id, dbiprsHidden); + Local::writeReportSpamStatuses(); } - } else if (data->loadedStatus != PeerData::FullLoaded) { - data->loadedStatus = PeerData::FullLoaded; - } - - auto oldOnlineTill = data->onlineTill; - if (status && !minimal) switch (status->type()) { - case mtpc_userStatusEmpty: data->onlineTill = 0; break; - case mtpc_userStatusRecently: - if (data->onlineTill > -10) { // don't modify pseudo-online - data->onlineTill = -2; - } - break; - case mtpc_userStatusLastWeek: data->onlineTill = -3; break; - case mtpc_userStatusLastMonth: data->onlineTill = -4; break; - case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break; - case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break; - } - if (oldOnlineTill != data->onlineTill) { - update.flags |= UpdateFlag::UserOnlineChanged; - } - - if (data->contact < 0 && !data->phone().isEmpty() && peerToUser(data->id) != MTP::authedId()) { - data->contact = 0; - } - if (App::main()) { - if ((data->contact > 0 && !wasContact) || (wasContact && data->contact < 1)) { - Notify::userIsContactChanged(data); - } - - markPeerUpdated(data); - if (update.flags) { - update.peer = data; - Notify::peerUpdatedDelayed(update); + if (d.is_self() && ::self != data) { + ::self = data; + if (App::wnd()) App::wnd()->updateGlobalMenu(); } } - result = data; + + if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact; + if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact; + } break; + } + + if (!data) { + return nullptr; + } + + if (minimal) { + if (data->loadedStatus == PeerData::NotLoaded) { + data->loadedStatus = PeerData::MinimalLoaded; + } + } else if (data->loadedStatus != PeerData::FullLoaded) { + data->loadedStatus = PeerData::FullLoaded; + } + + auto oldOnlineTill = data->onlineTill; + if (status && !minimal) switch (status->type()) { + case mtpc_userStatusEmpty: data->onlineTill = 0; break; + case mtpc_userStatusRecently: + if (data->onlineTill > -10) { // don't modify pseudo-online + data->onlineTill = -2; + } + break; + case mtpc_userStatusLastWeek: data->onlineTill = -3; break; + case mtpc_userStatusLastMonth: data->onlineTill = -4; break; + case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break; + case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break; + } + if (oldOnlineTill != data->onlineTill) { + update.flags |= UpdateFlag::UserOnlineChanged; + } + + if (data->contact < 0 && !data->phone().isEmpty() && peerToUser(data->id) != MTP::authedId()) { + data->contact = 0; + } + if (App::main()) { + if ((data->contact > 0 && !wasContact) || (wasContact && data->contact < 1)) { + Notify::userIsContactChanged(data); + } + + markPeerUpdated(data); + if (update.flags) { + update.peer = data; + Notify::peerUpdatedDelayed(update); + } + } + return data; + } + + UserData *feedUsers(const MTPVector &users) { + UserData *result = nullptr; + for_const (auto &user, users.c_vector().v) { + if (auto feededUser = feedUser(user)) { + result = feededUser; + } } return result; } + PeerData *feedChat(const MTPChat &chat) { + PeerData *data = nullptr; + bool minimal = false; + + Notify::PeerUpdate update; + using UpdateFlag = Notify::PeerUpdate::Flag; + + switch (chat.type()) { + case mtpc_chat: { + auto &d(chat.c_chat()); + + data = App::chat(peerFromChat(d.vid.v)); + auto cdata = data->asChat(); + auto canEdit = cdata->canEdit(); + + if (cdata->version < d.vversion.v) { + cdata->version = d.vversion.v; + cdata->invalidateParticipants(); + } + + data->input = MTP_inputPeerChat(d.vid); + cdata->setName(qs(d.vtitle)); + cdata->setPhoto(d.vphoto); + cdata->date = d.vdate.v; + + if (d.has_migrated_to() && d.vmigrated_to.type() == mtpc_inputChannel) { + const auto &c(d.vmigrated_to.c_inputChannel()); + ChannelData *channel = App::channel(peerFromChannel(c.vchannel_id)); + if (!channel->mgInfo) { + channel->flags |= MTPDchannel::Flag::f_megagroup; + channel->flagsUpdated(); + } + if (!channel->access) { + channel->input = MTP_inputPeerChannel(c.vchannel_id, c.vaccess_hash); + channel->inputChannel = d.vmigrated_to; + channel->access = d.vmigrated_to.c_inputChannel().vaccess_hash.v; + } + bool updatedTo = (cdata->migrateToPtr != channel), updatedFrom = (channel->mgInfo->migrateFromPtr != cdata); + if (updatedTo) { + cdata->migrateToPtr = channel; + } + if (updatedFrom) { + channel->mgInfo->migrateFromPtr = cdata; + if (History *h = App::historyLoaded(cdata->id)) { + if (History *hto = App::historyLoaded(channel->id)) { + if (!h->isEmpty()) { + h->clear(true); + } + if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { + App::removeDialog(h); + } + } + } + Notify::migrateUpdated(channel); + update.flags |= UpdateFlag::MigrationChanged; + } + if (updatedTo) { + Notify::migrateUpdated(cdata); + update.flags |= UpdateFlag::MigrationChanged; + } + } + + if (!(cdata->flags & MTPDchat::Flag::f_admins_enabled) && (d.vflags.v & MTPDchat::Flag::f_admins_enabled)) { + cdata->invalidateParticipants(); + } + cdata->flags = d.vflags.v; + + cdata->count = d.vparticipants_count.v; + cdata->isForbidden = false; + if (canEdit != cdata->canEdit()) { + update.flags |= UpdateFlag::ChatCanEdit; + } + } break; + case mtpc_chatForbidden: { + auto &d(chat.c_chatForbidden()); + + data = App::chat(peerFromChat(d.vid.v)); + auto cdata = data->asChat(); + auto canEdit = cdata->canEdit(); + + data->input = MTP_inputPeerChat(d.vid); + cdata->setName(qs(d.vtitle)); + cdata->setPhoto(MTP_chatPhotoEmpty()); + cdata->date = 0; + cdata->count = -1; + cdata->invalidateParticipants(); + cdata->flags = 0; + cdata->isForbidden = true; + if (canEdit != cdata->canEdit()) { + update.flags |= UpdateFlag::ChatCanEdit; + } + } break; + case mtpc_channel: { + auto &d(chat.c_channel()); + + auto peerId = peerFromChannel(d.vid.v); + minimal = d.is_min(); + if (minimal) { + data = App::channelLoaded(peerId); + if (!data) { + return nullptr; // minimal is not loaded, need to make getDifference + } + } else { + data = App::channel(peerId); + data->input = MTP_inputPeerChannel(d.vid, d.has_access_hash() ? d.vaccess_hash : MTP_long(0)); + } + + auto cdata = data->asChannel(); + auto wasInChannel = cdata->amIn(); + auto canEditPhoto = cdata->canEditPhoto(); + auto canViewAdmins = cdata->canViewAdmins(); + auto canViewMembers = cdata->canViewMembers(); + auto canAddMembers = cdata->canAddMembers(); + auto wasEditor = cdata->amEditor(); + + if (minimal) { + auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy; + cdata->flags = (cdata->flags & ~mask) | (d.vflags.v & mask); + } else { + cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); + cdata->access = d.vaccess_hash.v; + cdata->date = d.vdate.v; + if (cdata->version < d.vversion.v) { + cdata->version = d.vversion.v; + } + if (d.is_restricted()) { + cdata->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason))); + } else { + cdata->setRestrictionReason(QString()); + } + cdata->flags = d.vflags.v; + } + cdata->flagsUpdated(); + + QString uname = d.has_username() ? textOneLine(qs(d.vusername)) : QString(); + cdata->setName(qs(d.vtitle), uname); + + cdata->isForbidden = false; + cdata->setPhoto(d.vphoto); + + if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn; + if (canEditPhoto != cdata->canEditPhoto()) update.flags |= UpdateFlag::ChannelCanEditPhoto; + if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins; + if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers; + if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers; + if (wasEditor != cdata->amEditor()) { + cdata->selfAdminUpdated(); + update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged); + } + } break; + case mtpc_channelForbidden: { + auto &d(chat.c_channelForbidden()); + + auto peerId = peerFromChannel(d.vid.v); + data = App::channel(peerId); + data->input = MTP_inputPeerChannel(d.vid, d.vaccess_hash); + + auto cdata = data->asChannel(); + auto wasInChannel = cdata->amIn(); + auto canEditPhoto = cdata->canEditPhoto(); + auto canViewAdmins = cdata->canViewAdmins(); + auto canViewMembers = cdata->canViewMembers(); + auto canAddMembers = cdata->canAddMembers(); + auto wasEditor = cdata->amEditor(); + + cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); + + auto mask = mtpCastFlags(MTPDchannelForbidden::Flag::f_broadcast | MTPDchannelForbidden::Flag::f_megagroup); + cdata->flags = (cdata->flags & ~mask) | (mtpCastFlags(d.vflags) & mask); + cdata->flagsUpdated(); + + cdata->setName(qs(d.vtitle), QString()); + + cdata->access = d.vaccess_hash.v; + cdata->setPhoto(MTP_chatPhotoEmpty()); + cdata->date = 0; + cdata->setMembersCount(0); + cdata->isForbidden = true; + + if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn; + if (canEditPhoto != cdata->canEditPhoto()) update.flags |= UpdateFlag::ChannelCanEditPhoto; + if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins; + if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers; + if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers; + if (wasEditor != cdata->amEditor()) { + cdata->selfAdminUpdated(); + update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged); + } + } break; + } + if (!data) { + return nullptr; + } + + if (minimal) { + if (data->loadedStatus == PeerData::NotLoaded) { + data->loadedStatus = PeerData::MinimalLoaded; + } + } else if (data->loadedStatus != PeerData::FullLoaded) { + data->loadedStatus = PeerData::FullLoaded; + } + if (App::main()) { + markPeerUpdated(data); + if (update.flags) { + update.peer = data; + Notify::peerUpdatedDelayed(update); + } + } + return data; + } + PeerData *feedChats(const MTPVector &chats) { PeerData *result = nullptr; for_const (auto &chat, chats.c_vector().v) { - PeerData *data = nullptr; - bool minimal = false; - - Notify::PeerUpdate update; - using UpdateFlag = Notify::PeerUpdate::Flag; - - switch (chat.type()) { - case mtpc_chat: { - auto &d(chat.c_chat()); - - data = App::chat(peerFromChat(d.vid.v)); - auto cdata = data->asChat(); - auto canEdit = cdata->canEdit(); - - if (cdata->version < d.vversion.v) { - cdata->version = d.vversion.v; - cdata->invalidateParticipants(); - } - - data->input = MTP_inputPeerChat(d.vid); - cdata->setName(qs(d.vtitle)); - cdata->setPhoto(d.vphoto); - cdata->date = d.vdate.v; - - if (d.has_migrated_to() && d.vmigrated_to.type() == mtpc_inputChannel) { - const auto &c(d.vmigrated_to.c_inputChannel()); - ChannelData *channel = App::channel(peerFromChannel(c.vchannel_id)); - if (!channel->mgInfo) { - channel->flags |= MTPDchannel::Flag::f_megagroup; - channel->flagsUpdated(); - } - if (!channel->access) { - channel->input = MTP_inputPeerChannel(c.vchannel_id, c.vaccess_hash); - channel->inputChannel = d.vmigrated_to; - channel->access = d.vmigrated_to.c_inputChannel().vaccess_hash.v; - } - bool updatedTo = (cdata->migrateToPtr != channel), updatedFrom = (channel->mgInfo->migrateFromPtr != cdata); - if (updatedTo) { - cdata->migrateToPtr = channel; - } - if (updatedFrom) { - channel->mgInfo->migrateFromPtr = cdata; - if (History *h = App::historyLoaded(cdata->id)) { - if (History *hto = App::historyLoaded(channel->id)) { - if (!h->isEmpty()) { - h->clear(true); - } - if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { - App::removeDialog(h); - } - } - } - Notify::migrateUpdated(channel); - update.flags |= UpdateFlag::MigrationChanged; - } - if (updatedTo) { - Notify::migrateUpdated(cdata); - update.flags |= UpdateFlag::MigrationChanged; - } - } - - if (!(cdata->flags & MTPDchat::Flag::f_admins_enabled) && (d.vflags.v & MTPDchat::Flag::f_admins_enabled)) { - cdata->invalidateParticipants(); - } - cdata->flags = d.vflags.v; - - cdata->count = d.vparticipants_count.v; - cdata->isForbidden = false; - if (canEdit != cdata->canEdit()) { - update.flags |= UpdateFlag::ChatCanEdit; - } - } break; - case mtpc_chatForbidden: { - auto &d(chat.c_chatForbidden()); - - data = App::chat(peerFromChat(d.vid.v)); - auto cdata = data->asChat(); - auto canEdit = cdata->canEdit(); - - data->input = MTP_inputPeerChat(d.vid); - cdata->setName(qs(d.vtitle)); - cdata->setPhoto(MTP_chatPhotoEmpty()); - cdata->date = 0; - cdata->count = -1; - cdata->invalidateParticipants(); - cdata->flags = 0; - cdata->isForbidden = true; - if (canEdit != cdata->canEdit()) { - update.flags |= UpdateFlag::ChatCanEdit; - } - } break; - case mtpc_channel: { - auto &d(chat.c_channel()); - - auto peerId = peerFromChannel(d.vid.v); - minimal = d.is_min(); - if (minimal) { - data = App::channelLoaded(peerId); - if (!data) { - continue; // minimal is not loaded, need to make getDifference - } - } else { - data = App::channel(peerId); - data->input = MTP_inputPeerChannel(d.vid, d.has_access_hash() ? d.vaccess_hash : MTP_long(0)); - } - - auto cdata = data->asChannel(); - auto wasInChannel = cdata->amIn(); - auto canEditPhoto = cdata->canEditPhoto(); - auto canViewAdmins = cdata->canViewAdmins(); - auto canViewMembers = cdata->canViewMembers(); - auto canAddMembers = cdata->canAddMembers(); - auto wasEditor = cdata->amEditor(); - - if (minimal) { - auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy; - cdata->flags = (cdata->flags & ~mask) | (d.vflags.v & mask); - } else { - cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); - cdata->access = d.vaccess_hash.v; - cdata->date = d.vdate.v; - if (cdata->version < d.vversion.v) { - cdata->version = d.vversion.v; - } - if (d.is_restricted()) { - cdata->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason))); - } else { - cdata->setRestrictionReason(QString()); - } - cdata->flags = d.vflags.v; - } - cdata->flagsUpdated(); - - QString uname = d.has_username() ? textOneLine(qs(d.vusername)) : QString(); - cdata->setName(qs(d.vtitle), uname); - - cdata->isForbidden = false; - cdata->setPhoto(d.vphoto); - - if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn; - if (canEditPhoto != cdata->canEditPhoto()) update.flags |= UpdateFlag::ChannelCanEditPhoto; - if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins; - if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers; - if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers; - if (wasEditor != cdata->amEditor()) { - cdata->selfAdminUpdated(); - update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged); - } - } break; - case mtpc_channelForbidden: { - auto &d(chat.c_channelForbidden()); - - auto peerId = peerFromChannel(d.vid.v); - data = App::channel(peerId); - data->input = MTP_inputPeerChannel(d.vid, d.vaccess_hash); - - auto cdata = data->asChannel(); - auto wasInChannel = cdata->amIn(); - auto canEditPhoto = cdata->canEditPhoto(); - auto canViewAdmins = cdata->canViewAdmins(); - auto canViewMembers = cdata->canViewMembers(); - auto canAddMembers = cdata->canAddMembers(); - auto wasEditor = cdata->amEditor(); - - cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); - - auto mask = mtpCastFlags(MTPDchannelForbidden::Flag::f_broadcast | MTPDchannelForbidden::Flag::f_megagroup); - cdata->flags = (cdata->flags & ~mask) | (mtpCastFlags(d.vflags) & mask); - cdata->flagsUpdated(); - - cdata->setName(qs(d.vtitle), QString()); - - cdata->access = d.vaccess_hash.v; - cdata->setPhoto(MTP_chatPhotoEmpty()); - cdata->date = 0; - cdata->setMembersCount(0); - cdata->isForbidden = true; - - if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn; - if (canEditPhoto != cdata->canEditPhoto()) update.flags |= UpdateFlag::ChannelCanEditPhoto; - if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins; - if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers; - if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers; - if (wasEditor != cdata->amEditor()) { - cdata->selfAdminUpdated(); - update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged); - } - } break; + if (auto feededChat = feedChat(chat)) { + result = feededChat; } - if (!data) continue; - - if (minimal) { - if (data->loadedStatus == PeerData::NotLoaded) { - data->loadedStatus = PeerData::MinimalLoaded; - } - } else if (data->loadedStatus != PeerData::FullLoaded) { - data->loadedStatus = PeerData::FullLoaded; - } - if (App::main()) { - markPeerUpdated(data); - if (update.flags) { - update.peer = data; - Notify::peerUpdatedDelayed(update); - } - } - result = data; } return result; } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 0c12a7615e..c05ca179d8 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -65,7 +65,9 @@ namespace App { bool onlineColorUse(UserData *user, TimeId now); bool onlineColorUse(TimeId online, TimeId now); + UserData *feedUser(const MTPUser &user); UserData *feedUsers(const MTPVector &users); // returns last user + PeerData *feedChat(const MTPChat &chat); PeerData *feedChats(const MTPVector &chats); // returns last chat void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos, bool emitPeerUpdated = true); diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style new file mode 100644 index 0000000000..42c691542f --- /dev/null +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -0,0 +1,50 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +using "basic.style"; + +confirmInviteTitle: flatLabel(labelDefFlat) { + font: font(16px semibold); + align: align(center); + width: 320px; + maxHeight: 24px; + textFg: #333333; +} +confirmInviteStatus: flatLabel(labelDefFlat) { + font: font(boxFontSize); + align: align(center); + width: 320px; + maxHeight: 20px; + textFg: windowSubTextFg; +} +confirmInviteTitleTop: 106px; +confirmInvitePhotoSize: 76px; +confirmInvitePhotoTop: 20px; +confirmInviteStatusTop: 136px; +confirmInviteUserHeight: 80px; +confirmInviteUserPhotoSize: 56px; +confirmInviteUserPhotoTop: 166px; +confirmInviteUserName: flatLabel(labelDefFlat) { + font: normalFont; + align: align(center); + width: 66px; + maxHeight: 20px; +} +confirmInviteUserNameTop: 227px; diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index 83ce306433..39c978ed30 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.cpp +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "apiwrap.h" #include "application.h" #include "core/click_handler_types.h" +#include "styles/style_boxes.h" TextParseOptions _confirmBoxTextOptions = { TextParseLinks | TextParseMultiline | TextParseRichText, // flags @@ -520,3 +521,86 @@ void KickMemberBox::onConfirm() { App::api()->kickParticipant(channel, _member); } } + +ConfirmInviteBox::ConfirmInviteBox(const QString &title, const MTPChatPhoto &photo, int count, const QVector &participants) : AbstractBox() +, _title(this, st::confirmInviteTitle) +, _status(this, st::confirmInviteStatus) +, _photo(chatDefPhoto(0)) +, _participants(participants) +, _join(this, lang(lng_group_invite_join), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) { + if (_participants.size() > 4) { + _participants.resize(4); + } + + _title->setText(title); + QString status; + if (_participants.isEmpty() || _participants.size() >= count) { + status = lng_chat_status_members(lt_count, count); + } else { + status = lng_group_invite_members(lt_count, count); + } + _status->setText(status); + if (photo.type() == mtpc_chatPhoto) { + auto &d = photo.c_chatPhoto(); + auto location = App::imageLocation(160, 160, d.vphoto_small); + if (!location.isNull()) { + _photo = ImagePtr(location); + if (!_photo->loaded()) { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + _photo->load(); + } + } + } + + int h = st::confirmInviteStatusTop + _status->height() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _join->height() + st::boxButtonPadding.bottom(); + if (!_participants.isEmpty()) { + int skip = (width() - 4 * st::confirmInviteUserPhotoSize) / 5; + int padding = skip / 2; + _userWidth = (st::confirmInviteUserPhotoSize + 2 * padding); + int sumWidth = _participants.size() * _userWidth; + int left = (width() - sumWidth) / 2; + for_const (auto user, _participants) { + auto name = new FlatLabel(this, st::confirmInviteUserName); + name->resizeToWidth(st::confirmInviteUserPhotoSize + padding); + name->setText(user->firstName.isEmpty() ? App::peerName(user) : user->firstName); + name->moveToLeft(left + (padding / 2), st::confirmInviteUserNameTop); + left += _userWidth; + } + + h += st::confirmInviteUserHeight; + } + setMaxHeight(h); + + connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + connect(_join, SIGNAL(clicked()), App::main(), SLOT(onInviteImport())); +} + +void ConfirmInviteBox::resizeEvent(QResizeEvent *e) { + _title->move((width() - _title->width()) / 2, st::confirmInviteTitleTop); + _status->move((width() - _status->width()) / 2, st::confirmInviteStatusTop); + _join->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _join->height()); + _cancel->moveToRight(st::boxButtonPadding.right() + _join->width() + st::boxButtonPadding.left(), _join->y()); +} + +void ConfirmInviteBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + p.drawPixmap((width() - st::confirmInvitePhotoSize) / 2, st::confirmInvitePhotoTop, _photo->pixCircled(st::confirmInvitePhotoSize, st::confirmInvitePhotoSize)); + + int sumWidth = _participants.size() * _userWidth; + int left = (width() - sumWidth) / 2; + for_const (auto user, _participants) { + user->paintUserpicLeft(p, st::confirmInviteUserPhotoSize, left + (_userWidth - st::confirmInviteUserPhotoSize) / 2, st::confirmInviteUserPhotoTop, width()); + left += _userWidth; + } +} + +void ConfirmInviteBox::showAll() { + showChildren(); +} + +void ConfirmInviteBox::hideAll() { + hideChildren(); +} diff --git a/Telegram/SourceFiles/boxes/confirmbox.h b/Telegram/SourceFiles/boxes/confirmbox.h index 59f27336d3..ebad005d5f 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.h +++ b/Telegram/SourceFiles/boxes/confirmbox.h @@ -266,3 +266,26 @@ private: UserData *_member; }; + +class ConfirmInviteBox : public AbstractBox, public RPCSender { + Q_OBJECT + +public: + ConfirmInviteBox(const QString &title, const MTPChatPhoto &photo, int count, const QVector &participants); + +protected: + void resizeEvent(QResizeEvent *e) override; + void paintEvent(QPaintEvent *e) override; + + void showAll(); + void hideAll(); + +private: + ChildWidget _title, _status; + ImagePtr _photo; + QVector _participants; + + ChildWidget _join, _cancel; + int _userWidth = 0; + +}; diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 78837cc1e6..51d52bb827 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -530,9 +530,9 @@ void StickersInner::paintRow(Painter &p, int32 index) { int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2; QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.height)); - App::roundRect(p, add, st::defaultActiveButton.textBgOver, ImageRoundRadius::Small); + App::roundRect(p, add, st::defaultActiveButton.textBg, ImageRoundRadius::Small); p.setFont(st::defaultActiveButton.font); - p.setPen(st::defaultActiveButton.textFg); + p.setPen(st::defaultActiveButton.textFg); // textBgOver / downTextTop p.drawTextLeft(addx - st::defaultActiveButton.width / 2, addy + st::defaultActiveButton.textTop, width(), _addText, _addWidth); } diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 8ca6163bc4..ce4681df04 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -85,8 +85,8 @@ dialogsTextStyleActive: textStyle(dialogsTextStyle) { linkFgDown: dialogsTextFgActive; } dialogsTextStyleDraftActive: textStyle(dialogsTextStyle) { - linkFg: #ffd6d6; - linkFgDown: #ffd6d6; + linkFg: #c6e1f7; + linkFgDown: #c6e1f7; } dialogsNewChatIcon: icon { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 184556342c..f4b456789e 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3487,11 +3487,22 @@ bool MainWidget::usernameResolveFail(QString name, const RPCError &error) { void MainWidget::inviteCheckDone(QString hash, const MTPChatInvite &invite) { switch (invite.type()) { case mtpc_chatInvite: { - const auto &d(invite.c_chatInvite()); - ConfirmBox *box = new ConfirmBox(((d.is_channel() && !d.is_megagroup()) ? lng_group_invite_want_join_channel : lng_group_invite_want_join)(lt_title, qs(d.vtitle)), lang(lng_group_invite_join)); + auto &d(invite.c_chatInvite()); + ((d.is_channel() && !d.is_megagroup()) ? lng_group_invite_want_join_channel : lng_group_invite_want_join)(lt_title, qs(d.vtitle)), lang(lng_group_invite_join); + + QVector participants; + if (d.has_participants()) { + auto &v = d.vparticipants.c_vector().v; + participants.reserve(v.size()); + for_const (auto &user, v) { + if (auto feededUser = App::feedUser(user)) { + participants.push_back(feededUser); + } + } + } + auto box = std_::make_unique(qs(d.vtitle), d.vphoto, 3, participants); _inviteHash = hash; - connect(box, SIGNAL(confirmed()), this, SLOT(onInviteImport())); - Ui::showLayer(box); + Ui::showLayer(box.release()); } break; case mtpc_chatInviteAlready: { diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index 5b8fc9a823..749debce75 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -1185,6 +1185,7 @@ + @@ -1457,6 +1458,7 @@ + @@ -2876,6 +2878,7 @@ Compiling style %(Identity)... + diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 2d1a1f3934..2272084383 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -1344,6 +1344,9 @@ SourceFiles\platform\linux + + GeneratedFiles\styles + @@ -1595,6 +1598,9 @@ SourceFiles\platform\linux + + GeneratedFiles\styles + @@ -1966,6 +1972,9 @@ SourceFiles\profile + + SourceFiles\boxes + From 640f9d7389772a85a6480a3464296d00aa4cec41 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 8 Jul 2016 20:24:48 +0300 Subject: [PATCH 06/13] Active and pressed buttons state in featured stickers box. --- Telegram/SourceFiles/boxes/stickersetbox.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 51d52bb827..1e9a3cedc6 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -530,10 +530,12 @@ void StickersInner::paintRow(Painter &p, int32 index) { int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2; QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.height)); - App::roundRect(p, add, st::defaultActiveButton.textBg, ImageRoundRadius::Small); + auto textBg = (_actionSel == index) ? st::defaultActiveButton.textBgOver : st::defaultActiveButton.textBg; + App::roundRect(p, add, textBg, ImageRoundRadius::Small); p.setFont(st::defaultActiveButton.font); - p.setPen(st::defaultActiveButton.textFg); // textBgOver / downTextTop - p.drawTextLeft(addx - st::defaultActiveButton.width / 2, addy + st::defaultActiveButton.textTop, width(), _addText, _addWidth); + p.setPen(st::defaultActiveButton.textFg); + int textTop = (_actionSel == index && _actionDown == index) ? st::defaultActiveButton.downTextTop : st::defaultActiveButton.textTop; + p.drawTextLeft(addx - st::defaultActiveButton.width / 2, addy + textTop, width(), _addText, _addWidth); } if (s->disabled) p.setOpacity(st::stickersRowDisabledOpacity); @@ -700,7 +702,7 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) { } _dragging = _started = -1; - } else if (pressed == _selected) { + } else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) { if (_selected == -1) { _selected = -2; Ui::showLayer(new StickersBox(Section::Featured), KeepOtherLayers); From bf4acc4e52f8c0d16a2530aa091f230b05c4c90c Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Jul 2016 14:59:55 +0300 Subject: [PATCH 07/13] Fixed reading stickers from old versioned local storage. Handling error when installing sticker set from featured. --- Telegram/SourceFiles/boxes/stickersetbox.cpp | 38 ++++++++++++++-- Telegram/SourceFiles/boxes/stickersetbox.h | 3 +- Telegram/SourceFiles/localstorage.cpp | 46 ++++++++++---------- Telegram/SourceFiles/mainwidget.cpp | 3 +- Telegram/SourceFiles/mtproto/scheme.tl | 2 +- Telegram/SourceFiles/mtproto/scheme_auto.cpp | 3 +- Telegram/SourceFiles/mtproto/scheme_auto.h | 17 +++++--- Telegram/SourceFiles/ui/flatbutton.cpp | 1 + 8 files changed, 74 insertions(+), 39 deletions(-) diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 1e9a3cedc6..18d5a9741f 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -155,11 +155,11 @@ void StickerSetInner::installDone(const MTPBool &result) { emit installed(_setId); } -bool StickerSetInner::installFailed(const RPCError &error) { +bool StickerSetInner::installFail(const RPCError &error) { if (MTP::isDefaultHandledError(error)) return false; if (error.type() == qstr("STICKERSETS_TOO_MUCH")) { - Ui::showLayer(new InformBox(lang(lng_stickers_too_many_packs))); + Ui::showLayer(new InformBox(lang(lng_stickers_too_many_packs)), KeepOtherLayers); } else { Ui::showLayer(new InformBox(lang(lng_stickers_not_found))); } @@ -283,7 +283,7 @@ QString StickerSetInner::shortName() const { void StickerSetInner::install() { if (_installRequest) return; - _installRequest = MTP::send(MTPmessages_InstallStickerSet(_input, MTP_bool(false)), rpcDone(&StickerSetInner::installDone), rpcFail(&StickerSetInner::installFailed)); + _installRequest = MTP::send(MTPmessages_InstallStickerSet(_input, MTP_bool(false)), rpcDone(&StickerSetInner::installDone), rpcFail(&StickerSetInner::installFail)); } StickerSetInner::~StickerSetInner() { @@ -734,7 +734,7 @@ void StickersInner::installSet(uint64 setId) { return; } - MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse())); + MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), RPCDoneHandlerPtr(), rpcFail(&StickersInner::installFail, setId)); it->flags &= ~(MTPDstickerSet::Flag::f_disabled | MTPDstickerSet_ClientFlag::f_unread); it->flags |= MTPDstickerSet::Flag::f_installed; @@ -762,6 +762,36 @@ void StickersInner::installSet(uint64 setId) { emit App::main()->stickersUpdated(); } +bool StickersInner::installFail(uint64 setId, const RPCError &error) { + if (MTP::isDefaultHandledError(error)) return false; + + auto &sets = Global::RefStickerSets(); + auto it = sets.find(setId); + if (it == sets.cend()) { + rebuild(); + return true; + } + + it->flags &= ~MTPDstickerSet::Flag::f_installed; + + auto &order = Global::RefStickerSetsOrder(); + int currentIndex = order.indexOf(setId); + if (currentIndex >= 0) { + order.removeAt(currentIndex); + } + + Local::writeStickers(); + emit App::main()->stickersUpdated(); + + if (error.type() == qstr("STICKERSETS_TOO_MUCH")) { + Ui::showLayer(new InformBox(lang(lng_stickers_too_many_packs)), KeepOtherLayers); + } else { + Ui::showLayer(new InformBox(lang(lng_stickers_not_found)), KeepOtherLayers); + } + + return true; +} + void StickersInner::step_shifting(uint64 ms, bool timer) { bool animating = false; int32 updateMin = -1, updateMax = 0; diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 1c8e9590d8..28bddfac0c 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -63,7 +63,7 @@ private: bool failedSet(const RPCError &error); void installDone(const MTPBool &result); - bool installFailed(const RPCError &error); + bool installFail(const RPCError &error); StickerPack _pack; StickersByEmojiMap _emoji; @@ -232,6 +232,7 @@ private: float64 aboveShadowOpacity() const; void installSet(uint64 setId); + bool installFail(uint64 setId, const RPCError &error); void readFeaturedDone(const MTPBool &result); bool readFeaturedFail(const RPCError &error); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 4b2e792c26..b4e1417a9e 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3214,20 +3214,20 @@ namespace Local { setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_not_loaded); } } - if (stickers.version < 9057) { + if (stickers.version < 9058) { setFlags |= qFlags(MTPDstickerSet::Flag::f_installed); } if (setId == Stickers::DefaultSetId) { setTitle = lang(lng_stickers_default_set); setFlags |= qFlags(MTPDstickerSet::Flag::f_official); - if (stickers.version < 9057) { + if (stickers.version < 9058) { order.push_front(setId); } } else if (setId == Stickers::CustomSetId) { setTitle = lang(lng_custom_stickers); } else if (setId) { - if (stickers.version < 9057) { + if (stickers.version < 9058) { order.push_back(setId); } } else { @@ -3282,29 +3282,29 @@ namespace Local { } // Read orders of installed and featured stickers. - if (stickers.version >= 9057) { + if (stickers.version >= 9058) { stickers.stream >> order; stickers.stream >> featuredOrder; - - // Set flags and count unread featured sets. - for_const (auto setId, order) { - auto it = sets.find(setId); - if (it != sets.cend()) { - it->flags |= MTPDstickerSet::Flag::f_installed; - } - } - int unreadCount = 0; - for_const (auto setId, featuredOrder) { - auto it = sets.find(setId); - if (it != sets.cend()) { - it->flags |= MTPDstickerSet_ClientFlag::f_featured; - if (it->flags & MTPDstickerSet_ClientFlag::f_unread) { - ++unreadCount; - } - } - } - Global::SetFeaturedStickerSetsUnreadCount(unreadCount); } + + // Set flags and count unread featured sets. + for_const (auto setId, order) { + auto it = sets.find(setId); + if (it != sets.cend()) { + it->flags |= MTPDstickerSet::Flag::f_installed; + } + } + int unreadCount = 0; + for_const (auto setId, featuredOrder) { + auto it = sets.find(setId); + if (it != sets.cend()) { + it->flags |= MTPDstickerSet_ClientFlag::f_featured; + if (it->flags & MTPDstickerSet_ClientFlag::f_unread) { + ++unreadCount; + } + } + } + Global::SetFeaturedStickerSetsUnreadCount(unreadCount); } int32 countStickersHash(bool checkOfficial) { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index f4b456789e..4b55121dc7 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3488,7 +3488,6 @@ void MainWidget::inviteCheckDone(QString hash, const MTPChatInvite &invite) { switch (invite.type()) { case mtpc_chatInvite: { auto &d(invite.c_chatInvite()); - ((d.is_channel() && !d.is_megagroup()) ? lng_group_invite_want_join_channel : lng_group_invite_want_join)(lt_title, qs(d.vtitle)), lang(lng_group_invite_join); QVector participants; if (d.has_participants()) { @@ -3500,7 +3499,7 @@ void MainWidget::inviteCheckDone(QString hash, const MTPChatInvite &invite) { } } } - auto box = std_::make_unique(qs(d.vtitle), d.vphoto, 3, participants); + auto box = std_::make_unique(qs(d.vtitle), d.vphoto, d.vparticipants_count.v, participants); _inviteHash = hash; Ui::showLayer(box.release()); } break; diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index d1179d198a..6f98b58912 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -549,7 +549,7 @@ chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#2d492881 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants:flags.4?Vector = ChatInvite; +chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp index 5669a5323b..61c72b6955 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp +++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp @@ -4350,7 +4350,8 @@ void _serialize_chatInvite(MTPStringLogger &to, int32 stage, int32 lev, Types &t case 4: to.add(" megagroup: "); ++stages.back(); if (flag & MTPDchatInvite::Flag::f_megagroup) { to.add("YES [ BY BIT 3 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; case 5: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 6: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 7: to.add(" participants: "); ++stages.back(); if (flag & MTPDchatInvite::Flag::f_participants) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break; + case 7: to.add(" participants_count: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 8: to.add(" participants: "); ++stages.back(); if (flag & MTPDchatInvite::Flag::f_participants) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h index e0e2cb8975..ce9c712345 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.h +++ b/Telegram/SourceFiles/mtproto/scheme_auto.h @@ -398,7 +398,7 @@ enum { mtpc_chatInviteEmpty = 0x69df3769, mtpc_chatInviteExported = 0xfc2e05bc, mtpc_chatInviteAlready = 0x5a686d7c, - mtpc_chatInvite = 0x2d492881, + mtpc_chatInvite = 0xdb74f558, mtpc_inputStickerSetEmpty = 0xffb62b95, mtpc_inputStickerSetID = 0x9de7a269, mtpc_inputStickerSetShortName = 0x861cc8a0, @@ -13160,12 +13160,13 @@ public: MTPDchatInvite() { } - MTPDchatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, const MTPVector &_participants) : vflags(_flags), vtitle(_title), vphoto(_photo), vparticipants(_participants) { + MTPDchatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, const MTPVector &_participants) : vflags(_flags), vtitle(_title), vphoto(_photo), vparticipants_count(_participants_count), vparticipants(_participants) { } MTPflags vflags; MTPstring vtitle; MTPChatPhoto vphoto; + MTPint vparticipants_count; MTPVector vparticipants; }; @@ -23580,8 +23581,8 @@ public: inline static MTPchatInvite new_chatInviteAlready(const MTPChat &_chat) { return MTPchatInvite(new MTPDchatInviteAlready(_chat)); } - inline static MTPchatInvite new_chatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, const MTPVector &_participants) { - return MTPchatInvite(new MTPDchatInvite(_flags, _title, _photo, _participants)); + inline static MTPchatInvite new_chatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, const MTPVector &_participants) { + return MTPchatInvite(new MTPDchatInvite(_flags, _title, _photo, _participants_count, _participants)); } inline static MTPinputStickerSet new_inputStickerSetEmpty() { return MTPinputStickerSet(mtpc_inputStickerSetEmpty); @@ -32441,7 +32442,7 @@ inline uint32 MTPchatInvite::innerLength() const { } case mtpc_chatInvite: { const MTPDchatInvite &v(c_chatInvite()); - return v.vflags.innerLength() + v.vtitle.innerLength() + v.vphoto.innerLength() + (v.has_participants() ? v.vparticipants.innerLength() : 0); + return v.vflags.innerLength() + v.vtitle.innerLength() + v.vphoto.innerLength() + v.vparticipants_count.innerLength() + (v.has_participants() ? v.vparticipants.innerLength() : 0); } } return 0; @@ -32464,6 +32465,7 @@ inline void MTPchatInvite::read(const mtpPrime *&from, const mtpPrime *end, mtpT v.vflags.read(from, end); v.vtitle.read(from, end); v.vphoto.read(from, end); + v.vparticipants_count.read(from, end); if (v.has_participants()) { v.vparticipants.read(from, end); } else { v.vparticipants = MTPVector(); } } break; default: throw mtpErrorUnexpected(cons, "MTPchatInvite"); @@ -32480,6 +32482,7 @@ inline void MTPchatInvite::write(mtpBuffer &to) const { v.vflags.write(to); v.vtitle.write(to); v.vphoto.write(to); + v.vparticipants_count.write(to); if (v.has_participants()) v.vparticipants.write(to); } break; } @@ -32499,8 +32502,8 @@ inline MTPchatInvite MTP_chatInviteAlready(const MTPChat &_chat) { return MTP::internal::TypeCreator::new_chatInviteAlready(_chat); } Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDchatInvite::Flags) -inline MTPchatInvite MTP_chatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, const MTPVector &_participants) { - return MTP::internal::TypeCreator::new_chatInvite(_flags, _title, _photo, _participants); +inline MTPchatInvite MTP_chatInvite(const MTPflags &_flags, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, const MTPVector &_participants) { + return MTP::internal::TypeCreator::new_chatInvite(_flags, _title, _photo, _participants_count, _participants); } inline uint32 MTPinputStickerSet::innerLength() const { diff --git a/Telegram/SourceFiles/ui/flatbutton.cpp b/Telegram/SourceFiles/ui/flatbutton.cpp index 365e5297ef..df5a762be9 100644 --- a/Telegram/SourceFiles/ui/flatbutton.cpp +++ b/Telegram/SourceFiles/ui/flatbutton.cpp @@ -349,6 +349,7 @@ void BoxButton::setText(const QString &text) { _fullText = text; _textWidth = _st.font->width(_text); resizeToText(); + update(); } void BoxButton::resizeToText() { From 95c050081c6039014f59480b5eb3b9fb2fd02b4d Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 15 Jul 2016 18:58:52 +0300 Subject: [PATCH 08/13] Cloud recent sticker sets supported. --- Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/apiwrap.cpp | 2 +- Telegram/SourceFiles/app.cpp | 1 + Telegram/SourceFiles/boxes/stickersetbox.cpp | 114 +++++++++++++++--- Telegram/SourceFiles/boxes/stickersetbox.h | 13 +- Telegram/SourceFiles/dropdown.cpp | 62 ++++++---- Telegram/SourceFiles/facades.cpp | 2 + Telegram/SourceFiles/facades.h | 7 +- Telegram/SourceFiles/history.cpp | 4 +- Telegram/SourceFiles/historywidget.cpp | 107 ++++++++++++++-- Telegram/SourceFiles/historywidget.h | 4 + Telegram/SourceFiles/localstorage.cpp | 33 +++-- Telegram/SourceFiles/localstorage.h | 1 + Telegram/SourceFiles/mainwidget.cpp | 107 ++++++++-------- Telegram/SourceFiles/mtproto/core_types.h | 5 +- .../serialize/serialize_document.cpp | 2 +- Telegram/SourceFiles/settingswidget.cpp | 24 ---- Telegram/SourceFiles/settingswidget.h | 1 - 18 files changed, 342 insertions(+), 149 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index d05f7de460..35d1ebca29 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -689,6 +689,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_stickers_packs" = "Sticker Packs"; "lng_stickers_reorder" = "Click and drag to reorder sticker packs"; "lng_stickers_featured" = "Featured Stickers"; +"lng_stickers_clear_recent" = "Clear"; +"lng_stickers_clear_recent_sure" = "Are you sure you want to clear your frequently used stickers list?"; "lng_stickers_remove" = "Delete"; "lng_stickers_return" = "Undo"; "lng_stickers_restore" = "Restore"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index e6c12b071b..8d3a886c9a 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -937,7 +937,7 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) it->hash = s.vhash.v; it->shortName = qs(s.vshort_name); it->title = stickerSetTitle(s); - auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded); + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_special); it->flags = s.vflags.v | clientFlags; it->flags &= ~MTPDstickerSet_ClientFlag::f_not_loaded; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index ee5b159b70..0c61a589dc 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2012,6 +2012,7 @@ namespace { Global::SetStickerSets(Stickers::Sets()); Global::SetStickerSetsOrder(Stickers::Order()); Global::SetLastStickersUpdate(0); + Global::SetLastRecentStickersUpdate(0); Global::SetFeaturedStickerSetsOrder(Stickers::Order()); Global::SetFeaturedStickerSetsUnreadCount(0); Global::SetLastFeaturedStickersUpdate(0); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 18d5a9741f..a55c26bb77 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -87,7 +87,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { auto &sets = Global::RefStickerSets(); auto it = sets.find(_setId); if (it != sets.cend()) { - auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_unread); + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_special); _setFlags |= clientFlags; it->flags = _setFlags; it->stickers = _pack; @@ -418,6 +418,7 @@ StickersInner::StickersInner(StickersBox::Section section) : TWidget() , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _a_shifting(animation(this, &StickersInner::step_shifting)) , _itemsTop(st::membersPadding.top()) +, _clearWidth(st::normalFont->width(lang(lng_stickers_clear_recent))) , _removeWidth(st::normalFont->width(lang(lng_stickers_remove))) , _returnWidth(st::normalFont->width(lang(lng_stickers_return))) , _restoreWidth(st::normalFont->width(lang(lng_stickers_restore))) @@ -500,8 +501,8 @@ void StickersInner::paintRow(Painter &p, int32 index) { } else { p.setPen(st::btnDefLink.color); } - int32 remWidth = s->disabled ? (s->official ? _restoreWidth : _returnWidth) : _removeWidth; - QString remText = lang(s->disabled ? (s->official ? lng_stickers_restore : lng_stickers_return) : lng_stickers_remove); + int32 remWidth = s->recent ? _clearWidth : (s->disabled ? (s->official ? _restoreWidth : _returnWidth) : _removeWidth); + QString remText = lang(s->recent ? lng_stickers_clear_recent : (s->disabled ? (s->official ? lng_stickers_restore : lng_stickers_return) : lng_stickers_remove)); p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), remText, remWidth); if (index == _above) { @@ -581,7 +582,7 @@ void StickersInner::mousePressEvent(QMouseEvent *e) { if (_actionSel >= 0) { _actionDown = _actionSel; update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); - } else if (_selected >= 0 && _section == Section::Installed) { + } else if (_selected >= 0 && _section == Section::Installed && !_rows.at(_selected)->recent) { _above = _dragging = _started = _selected; _dragStart = mapFromGlobal(_mouse); } @@ -599,8 +600,12 @@ void StickersInner::onUpdateSelected() { if (_dragging >= 0) { int32 shift = 0; uint64 ms = getms(); + int firstSetIndex = 0; + if (_rows.at(firstSetIndex)->recent) { + ++firstSetIndex; + } if (_dragStart.y() > local.y() && _dragging > 0) { - shift = -floorclamp(_dragStart.y() - local.y() + (_rowHeight / 2), _rowHeight, 0, _dragging); + shift = -floorclamp(_dragStart.y() - local.y() + (_rowHeight / 2), _rowHeight, 0, _dragging - firstSetIndex); for (int32 from = _dragging, to = _dragging + shift; from > to; --from) { qSwap(_rows[from], _rows[from - 1]); _rows.at(from)->yadd = anim::ivalue(_rows.at(from)->yadd.current() - _rowHeight, 0); @@ -635,7 +640,7 @@ void StickersInner::onUpdateSelected() { selected = floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1); if (_section == Section::Installed) { - int remw = _rows.at(selected)->disabled ? (_rows.at(selected)->official ? _restoreWidth : _returnWidth) : _removeWidth; + int remw = _rows.at(selected)->recent ? _clearWidth : (_rows.at(selected)->disabled ? (_rows.at(selected)->official ? _restoreWidth : _returnWidth) : _removeWidth); QRect rem(myrtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - remw, st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, remw, st::normalFont->height)); actionSel = rem.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1; } else if (_rows.at(selected)->installed) { @@ -666,6 +671,34 @@ void StickersInner::onUpdateSelected() { } } +void StickersInner::onClearRecent() { + if (_clearBox) { + _clearBox->onClose(); + } + + auto &sets = Global::RefStickerSets(); + sets.remove(Stickers::CloudRecentSetId); + sets.remove(Stickers::CustomSetId); + + auto &recent = cGetRecentStickers(); + if (!recent.isEmpty()) { + recent.clear(); + Local::writeUserSettings(); + } + + Local::writeStickers(); + emit App::main()->updateStickers(); + rebuild(); + + MTP::send(MTPmessages_ClearRecentStickers()); +} + +void StickersInner::onClearBoxDestroyed(QObject *box) { + if (box == _clearBox) { + _clearBox = nullptr; + } +} + float64 StickersInner::aboveShadowOpacity() const { if (_above < 0) return 0; @@ -688,7 +721,14 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) { onUpdateSelected(); if (_actionDown == _actionSel && _actionSel >= 0) { if (_section == Section::Installed) { - _rows[_actionDown]->disabled = !_rows[_actionDown]->disabled; + if (_rows[_actionDown]->recent) { + _clearBox = new ConfirmBox(lang(lng_stickers_clear_recent_sure), lang(lng_stickers_clear_recent)); + connect(_clearBox, SIGNAL(confirmed()), this, SLOT(onClearRecent())); + connect(_clearBox, SIGNAL(destroyed(QObject*)), this, SLOT(onClearBoxDestroyed(QObject*))); + Ui::showLayer(_clearBox, KeepOtherLayers); + } else { + _rows[_actionDown]->disabled = !_rows[_actionDown]->disabled; + } } else { installSet(_rows[_actionDown]->id); } @@ -876,7 +916,7 @@ void StickersInner::rebuild() { int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); if (_section == Section::Installed) { - namew -= qMax(qMax(_returnWidth, _removeWidth), _restoreWidth); + namew -= qMax(qMax(qMax(_returnWidth, _removeWidth), _restoreWidth), _clearWidth); } else { namew -= _addWidth - st::defaultActiveButton.width; } @@ -886,12 +926,54 @@ void StickersInner::rebuild() { _animStartTimes.reserve(order.size()); auto &sets = Global::StickerSets(); + auto cloudIt = sets.constFind(Stickers::CloudRecentSetId); + if (cloudIt != sets.cend() && !cloudIt->stickers.isEmpty()) { + DocumentData *sticker = cloudIt->stickers.at(0); + int32 pixw = 0, pixh = 0; + if (sticker) { + pixw = sticker->thumb->width(); + pixh = sticker->thumb->height(); + if (pixw > st::contactsPhotoSize) { + if (pixw > pixh) { + pixh = (pixh * st::contactsPhotoSize) / pixw; + pixw = st::contactsPhotoSize; + } else { + pixw = (pixw * st::contactsPhotoSize) / pixh; + pixh = st::contactsPhotoSize; + } + } else if (pixh > st::contactsPhotoSize) { + pixw = (pixw * st::contactsPhotoSize) / pixh; + pixh = st::contactsPhotoSize; + } + } + QString title = cloudIt->title; + int32 titleWidth = st::contactsNameFont->width(title); + if (titleWidth > namew) { + title = st::contactsNameFont->elided(title, namew); + } + int count = cloudIt->stickers.size(); + int added = 0; + auto customIt = sets.constFind(Stickers::CustomSetId); + if (customIt != sets.cend()) { + added = customIt->stickers.size(); + for_const (auto &sticker, cGetRecentStickers()) { + if (customIt->stickers.indexOf(sticker.first) < 0) { + ++added; + } + } + } else { + added = cGetRecentStickers().size(); + } + rows.push_back(new StickerSetRow(cloudIt->id, cloudIt->stickers.front(), count + added, title, true, true, false, false, true, pixw, pixh)); + _animStartTimes.push_back(0); + } for_const (auto setId, order) { auto it = sets.constFind(setId); if (it == sets.cend()) { continue; } + bool recent = false; bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); bool disabled = (_section == Section::Installed) && (it->flags & MTPDstickerSet::Flag::f_disabled); bool official = (it->flags & MTPDstickerSet::Flag::f_official); @@ -924,7 +1006,7 @@ void StickersInner::rebuild() { if (titleWidth > namew) { title = st::contactsNameFont->elided(title, namew); } - (disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, installed, official, unread, disabled, pixw, pixh)); + (disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, installed, official, unread, disabled, recent, pixw, pixh)); _animStartTimes.push_back(0); if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { App::api()->scheduleStickerSetRequest(it->id, it->access); @@ -973,6 +1055,9 @@ QVector StickersInner::getOrder() const { continue; } } + if (_rows.at(i)->recent) { + continue; + } result.push_back(_rows.at(i)->id); } return result; @@ -1167,7 +1252,7 @@ void StickersBox::onSave() { } bool writeRecent = false; - RecentStickerPack &recent(cGetRecentStickers()); + auto &recent = cGetRecentStickers(); auto &sets = Global::RefStickerSets(); QVector reorder = _inner->getOrder(), disabled = _inner->getDisabledSets(); @@ -1191,7 +1276,7 @@ void StickersBox::onSave() { _disenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); int removeIndex = Global::StickerSetsOrder().indexOf(it->id); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); - if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)) { + if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { sets.erase(it); } else { it->flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet::Flag::f_disabled); @@ -1221,10 +1306,9 @@ void StickersBox::onSave() { } } for (auto it = sets.begin(); it != sets.cend();) { - if (it->id == Stickers::CustomSetId - || it->id == Stickers::RecentSetId - || (it->flags & MTPDstickerSet_ClientFlag::f_featured) - || (it->flags & MTPDstickerSet::Flag::f_installed)) { + if ((it->flags & MTPDstickerSet_ClientFlag::f_featured) + || (it->flags & MTPDstickerSet::Flag::f_installed) + || (it->flags & MTPDstickerSet_ClientFlag::f_special)) { ++it; } else { it = sets.erase(it); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 28bddfac0c..70f65e3c32 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -22,6 +22,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "abstractbox.h" +class ConfirmBox; + class StickerSetInner : public TWidget, public RPCSender { Q_OBJECT @@ -221,6 +223,8 @@ signals: public slots: void onUpdateSelected(); + void onClearRecent(); + void onClearBoxDestroyed(QObject *box); private: void paintFeaturedButton(Painter &p) const; @@ -240,7 +244,7 @@ private: int32 _rowHeight; struct StickerSetRow { - StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, bool installed, bool official, bool unread, bool disabled, int32 pixw, int32 pixh) : id(id) + StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, bool installed, bool official, bool unread, bool disabled, bool recent, int32 pixw, int32 pixh) : id(id) , sticker(sticker) , count(count) , title(title) @@ -248,6 +252,7 @@ private: , official(official) , unread(unread) , disabled(disabled) + , recent(recent) , pixw(pixw) , pixh(pixh) , yadd(0, 0) { @@ -256,7 +261,7 @@ private: DocumentData *sticker; int32 count; QString title; - bool installed, official, unread, disabled; + bool installed, official, unread, disabled, recent; int32 pixw, pixh; anim::ivalue yadd; }; @@ -274,7 +279,9 @@ private: int _actionSel = -1; int _actionDown = -1; - int _removeWidth, _returnWidth, _restoreWidth; + int _clearWidth, _removeWidth, _returnWidth, _restoreWidth; + + ConfirmBox *_clearBox = nullptr; QString _addText; int _addWidth; diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 029c912a7e..1c63f49bac 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -714,7 +714,7 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) { } EmojiPanInner::EmojiPanInner() : TWidget() -, _maxHeight(int(st::emojiPanMaxHeight)) +, _maxHeight(int(st::emojiPanMaxHeight) - st::rbEmoji.height) , _a_selected(animation(this, &EmojiPanInner::step_selected)) , _top(0) , _selected(-1) @@ -1230,7 +1230,7 @@ StickerPanInner::StickerPanInner() : TWidget() , _pressedSel(-1) , _settings(this, lang(lng_stickers_you_have)) , _previewShown(false) { - setMaxHeight(st::emojiPanMaxHeight); + setMaxHeight(st::emojiPanMaxHeight - st::rbEmoji.height); setMouseTracking(true); setFocusPolicy(Qt::NoFocus); @@ -2111,37 +2111,49 @@ void StickerPanInner::refreshRecent() { void StickerPanInner::refreshRecentStickers(bool performResize) { _custom.clear(); clearSelection(true); - auto customIt = Global::StickerSets().constFind(Stickers::CustomSetId); - if (cGetRecentStickers().isEmpty() && (customIt == Global::StickerSets().cend() || customIt->stickers.isEmpty())) { + auto &sets = Global::StickerSets(); + auto &recent = cGetRecentStickers(); + auto customIt = sets.constFind(Stickers::CustomSetId); + auto cloudIt = sets.constFind(Stickers::CloudRecentSetId); + if (recent.isEmpty() + && (customIt == sets.cend() || customIt->stickers.isEmpty()) + && (cloudIt == sets.cend() || cloudIt->stickers.isEmpty())) { if (!_sets.isEmpty() && _sets.at(0).id == Stickers::RecentSetId) { _sets.pop_front(); } } else { - StickerPack recent; - int32 customCnt = (customIt == Global::StickerSets().cend() ? 0 : customIt->stickers.size()); - QMap recentOnly; - recent.reserve(cGetRecentStickers().size() + customCnt); - _custom.reserve(cGetRecentStickers().size() + customCnt); - for (int32 i = 0, l = cGetRecentStickers().size(); i < l; ++i) { - DocumentData *s = cGetRecentStickers().at(i).first; - recent.push_back(s); - recentOnly.insert(s, true); + StickerPack recentPack; + int customCnt = (customIt == sets.cend()) ? 0 : customIt->stickers.size(); + int cloudCnt = (cloudIt == sets.cend()) ? 0 : cloudIt->stickers.size(); + recentPack.reserve(cloudCnt + recent.size() + customCnt); + _custom.reserve(cloudCnt + recent.size() + customCnt); + if (cloudCnt > 0) { + for_const (auto sticker, cloudIt->stickers) { + recentPack.push_back(sticker); + _custom.push_back(false); + } + } + for_const (auto &recentSticker, recent) { + auto sticker = recentSticker.first; + recentPack.push_back(sticker); _custom.push_back(false); } - for (int32 i = 0; i < customCnt; ++i) { - DocumentData *s = customIt->stickers.at(i); - if (recentOnly.contains(s)) { - _custom[recent.indexOf(s)] = true; - } else { - recent.push_back(s); - _custom.push_back(true); + if (customCnt > 0) { + for_const (auto &sticker, customIt->stickers) { + auto index = recentPack.indexOf(sticker); + if (index >= cloudCnt) { + _custom[index] = true; // mark stickers from recent as custom + } else { + recentPack.push_back(sticker); + _custom.push_back(true); + } } } if (_sets.isEmpty() || _sets.at(0).id != Stickers::RecentSetId) { - _sets.push_back(DisplayedSet(Stickers::RecentSetId, MTPDstickerSet::Flag::f_official, lang(lng_emoji_category0), recent.size() * 2, recent)); + _sets.push_back(DisplayedSet(Stickers::RecentSetId, MTPDstickerSet::Flag::f_official | MTPDstickerSet_ClientFlag::f_special, lang(lng_emoji_category0), recentPack.size() * 2, recentPack)); } else { - _sets[0].pack = recent; - _sets[0].hovers.resize(recent.size() * 2); + _sets[0].pack = recentPack; + _sets[0].hovers.resize(recentPack.size() * 2); } } @@ -3244,7 +3256,7 @@ void EmojiPan::step_icons(uint64 ms, bool timer) { } if (_iconsStartAnim) { - float64 dt = (ms - _iconsStartAnim) / st::stickerIconMove; + float64 dt = (ms - _iconsStartAnim) / float64(st::stickerIconMove); if (dt >= 1) { _iconsStartAnim = 0; _iconsX.finish(); @@ -3669,7 +3681,7 @@ void EmojiPan::onRemoveSetSure() { } } it->flags &= ~MTPDstickerSet::Flag::f_installed; - if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)) { + if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { Global::RefStickerSets().erase(it); } int removeIndex = Global::StickerSetsOrder().indexOf(_removingSetId); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 7dfa5513c3..d4e7318c0d 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -564,6 +564,7 @@ struct Data { Stickers::Sets StickerSets; Stickers::Order StickerSetsOrder; uint64 LastStickersUpdate = 0; + uint64 LastRecentStickersUpdate = 0; Stickers::Order FeaturedStickerSetsOrder; int FeaturedStickerSetsUnreadCount = 0; uint64 LastFeaturedStickersUpdate = 0; @@ -635,6 +636,7 @@ DefineRefVar(Global, PendingItemsMap, PendingRepaintItems); DefineVar(Global, Stickers::Sets, StickerSets); DefineVar(Global, Stickers::Order, StickerSetsOrder); DefineVar(Global, uint64, LastStickersUpdate); +DefineVar(Global, uint64, LastRecentStickersUpdate); DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder); DefineVar(Global, int, FeaturedStickerSetsUnreadCount); DefineVar(Global, uint64, LastFeaturedStickersUpdate); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index cd9acceeb2..d0d09ff296 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -183,8 +183,10 @@ enum Flags { namespace Stickers { static const uint64 DefaultSetId = 0; // for backward compatibility -static const uint64 CustomSetId = 0xFFFFFFFFFFFFFFFFULL, RecentSetId = 0xFFFFFFFFFFFFFFFEULL; -static const uint64 NoneSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel +static const uint64 CustomSetId = 0xFFFFFFFFFFFFFFFFULL; +static const uint64 RecentSetId = 0xFFFFFFFFFFFFFFFEULL; // for emoji/stickers panel, should not appear in Sets +static const uint64 NoneSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel, should not appear in Sets +static const uint64 CloudRecentSetId = 0xFFFFFFFFFFFFFFFCULL; // for cloud-stored recent stickers struct Set { Set(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, MTPDstickerSet::Flags flags) : id(id) @@ -262,6 +264,7 @@ DeclareRefVar(PendingItemsMap, PendingRepaintItems); DeclareVar(Stickers::Sets, StickerSets); DeclareVar(Stickers::Order, StickerSetsOrder); DeclareVar(uint64, LastStickersUpdate); +DeclareVar(uint64, LastRecentStickersUpdate); DeclareVar(Stickers::Order, FeaturedStickerSetsOrder); DeclareVar(int, FeaturedStickerSetsUnreadCount); DeclareVar(uint64, LastFeaturedStickersUpdate); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index a5c8b8bd2f..9534dd7460 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -4076,10 +4076,10 @@ void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection, bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width)); - QPixmap thumb = loaded ? _data->thumb->pixSingle(ImageRoundRadius::Small, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(ImageRoundRadius::Small, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize); + QPixmap thumb = loaded ? _data->thumb->pixSingle(ImageRoundRadius::Large, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(ImageRoundRadius::Small, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize); p.drawPixmap(rthumb.topLeft(), thumb); if (selected) { - App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners); + App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners); } if (radial || (!loaded && !_data->loading())) { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 27f01b9a48..08523d6892 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3530,6 +3530,11 @@ void HistoryWidget::updateStickers() { _stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_int(Local::countStickersHash(true))), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed)); } } + if (!Global::LastRecentStickersUpdate() || now >= Global::LastRecentStickersUpdate() + StickersUpdateTimeout) { + if (!_recentStickersUpdateRequest) { + _recentStickersUpdateRequest = MTP::send(MTPmessages_GetRecentStickers(MTP_int(Local::countRecentStickersHash())), rpcDone(&HistoryWidget::recentStickersGot), rpcFail(&HistoryWidget::recentStickersFailed)); + } + } if (!Global::LastFeaturedStickersUpdate() || now >= Global::LastFeaturedStickersUpdate() + StickersUpdateTimeout) { if (!_featuredStickersUpdateRequest) { _featuredStickersUpdateRequest = MTP::send(MTPmessages_GetFeaturedStickers(MTP_int(Local::countFeaturedStickersHash())), rpcDone(&HistoryWidget::featuredStickersGot), rpcFail(&HistoryWidget::featuredStickersFailed)); @@ -3671,7 +3676,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { 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); + 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; if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) { it->count = set.vcount.v; @@ -3692,6 +3697,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { 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); 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) { @@ -3702,7 +3708,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { } } } - if (installed || featured) { + if (installed || featured || special) { ++it; } else { it = sets.erase(it); @@ -3736,6 +3742,92 @@ bool HistoryWidget::stickersFailed(const RPCError &error) { return true; } +void HistoryWidget::recentStickersGot(const MTPmessages_RecentStickers &stickers) { + Global::SetLastRecentStickersUpdate(getms(true)); + _recentStickersUpdateRequest = 0; + + if (stickers.type() != mtpc_messages_recentStickers) return; + auto &d = stickers.c_messages_recentStickers(); + + auto &sets = Global::RefStickerSets(); + auto it = sets.find(Stickers::CloudRecentSetId); + + auto &d_docs = d.vstickers.c_vector().v; + if (d_docs.isEmpty()) { + if (it != sets.cend()) { + sets.erase(it); + } + } else { + if (it == sets.cend()) { + it = sets.insert(Stickers::CloudRecentSetId, Stickers::Set(Stickers::CloudRecentSetId, 0, lang(lng_emoji_category0), QString(), 0, 0, qFlags(MTPDstickerSet_ClientFlag::f_special))); + } else { + it->title = lang(lng_emoji_category0); + } + it->hash = d.vhash.v; + + auto custom = sets.find(Stickers::CustomSetId); + + StickerPack pack; + pack.reserve(d_docs.size()); + for (int32 i = 0, l = d_docs.size(); i != l; ++i) { + DocumentData *doc = App::feedDocument(d_docs.at(i)); + if (!doc || !doc->sticker()) continue; + + pack.push_back(doc); + if (custom != sets.cend()) { + int32 index = custom->stickers.indexOf(doc); + if (index >= 0) { + custom->stickers.removeAt(index); + } + } + } + if (custom != sets.cend() && custom->stickers.isEmpty()) { + sets.erase(custom); + custom = sets.end(); + } + + bool writeRecent = false; + RecentStickerPack &recent(cGetRecentStickers()); + for (RecentStickerPack::iterator 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(); + } + } + + 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())); + } + + Local::writeStickers(); + + if (App::main()) emit App::main()->stickersUpdated(); +} + +bool HistoryWidget::recentStickersFailed(const RPCError &error) { + if (MTP::isDefaultHandledError(error)) return false; + + LOG(("App Fail: Failed to get recent stickers!")); + + Global::SetLastRecentStickersUpdate(getms(true)); + _recentStickersUpdateRequest = 0; + return true; +} + void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stickers) { Global::SetLastFeaturedStickersUpdate(getms(true)); _featuredStickersUpdateRequest = 0; @@ -3764,16 +3856,16 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic auto it = sets.find(set.vid.v); QString title = stickerSetTitle(set); if (it == sets.cend()) { - auto clientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded; + auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded; if (unread.contains(set.vid.v) || !(set.vflags.v & MTPDstickerSet::Flag::f_installed)) { - clientFlags |= MTPDstickerSet_ClientFlag::f_unread; + 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 | clientFlags)); + 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); + 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)) { @@ -3798,7 +3890,8 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic 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); - if (installed || featured) { + bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special); + if (installed || featured || special) { if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { ++unreadCount; } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index ff68e4e3eb..ee979a570e 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -1005,6 +1005,10 @@ private: void stickersGot(const MTPmessages_AllStickers &stickers); bool stickersFailed(const RPCError &error); + mtpRequestId _recentStickersUpdateRequest = 0; + void recentStickersGot(const MTPmessages_RecentStickers &stickers); + bool recentStickersFailed(const RPCError &error); + mtpRequestId _featuredStickersUpdateRequest = 0; void featuredStickersGot(const MTPmessages_FeaturedStickers &stickers); bool featuredStickersFailed(const RPCError &error); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index b4e1417a9e..68a443ca00 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3052,7 +3052,7 @@ namespace Local { quint32 size = sizeof(quint32) + Serialize::bytearraySize(hashToWrite); for_const (auto &set, sets) { bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded); - if (notLoaded) { + if (notLoaded && !(set.flags & MTPDstickerSet_ClientFlag::f_special)) { if (!(set.flags & MTPDstickerSet::Flag::f_disabled) || (set.flags & MTPDstickerSet::Flag::f_official) || (set.flags & MTPDstickerSet_ClientFlag::f_featured)) { // waiting to receive @@ -3118,8 +3118,8 @@ namespace Local { auto &recent = cRefRecentStickers(); recent.clear(); - auto &def = sets.insert(Stickers::DefaultSetId, Stickers::Set(Stickers::DefaultSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet::Flag::f_official | MTPDstickerSet::Flag::f_installed)).value(); - auto &custom = sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, MTPDstickerSet::Flag::f_installed)).value(); + auto &def = sets.insert(Stickers::DefaultSetId, Stickers::Set(Stickers::DefaultSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet::Flag::f_official | MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_special)).value(); + auto &custom = sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_special)).value(); QMap read; while (!stickers.stream.atEnd()) { @@ -3220,12 +3220,16 @@ namespace Local { if (setId == Stickers::DefaultSetId) { setTitle = lang(lng_stickers_default_set); - setFlags |= qFlags(MTPDstickerSet::Flag::f_official); + setFlags |= qFlags(MTPDstickerSet::Flag::f_official | MTPDstickerSet_ClientFlag::f_special); if (stickers.version < 9058) { order.push_front(setId); } } else if (setId == Stickers::CustomSetId) { setTitle = lang(lng_custom_stickers); + setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); + } else if (setId == Stickers::CloudRecentSetId) { + setTitle = lang(lng_emoji_category0); // Frequently used + setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); } else if (setId) { if (stickers.version < 9058) { order.push_back(setId); @@ -3328,6 +3332,20 @@ namespace Local { return (!checkOfficial || (!foundBad && foundOfficial)) ? int32(acc & 0x7FFFFFFF) : 0; } + int32 countRecentStickersHash() { + uint32 acc = 0; + auto &sets = Global::StickerSets(); + auto it = sets.constFind(Stickers::CloudRecentSetId); + if (it != sets.cend()) { + for_const (auto doc, it->stickers) { + auto docId = doc->id; + acc = (acc * 20261) + uint32(docId >> 32); + acc = (acc * 20261) + uint32(docId & 0xFFFFFFFF); + } + } + return int32(acc & 0x7FFFFFFF); + } + int32 countFeaturedStickersHash() { uint32 acc = 0; auto &sets = Global::StickerSets(); @@ -3346,10 +3364,9 @@ namespace Local { int32 countSavedGifsHash() { uint32 acc = 0; - const SavedGifs &saved(cSavedGifs()); - for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) { - uint64 docId = (*i)->id; - + auto &saved = cSavedGifs(); + for_const (auto doc, saved) { + auto docId = doc->id; acc = (acc * 20261) + uint32(docId >> 32); acc = (acc * 20261) + uint32(docId & 0xFFFFFFFF); } diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index 204ac320ad..a4909037d0 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -156,6 +156,7 @@ namespace Local { void writeStickers(); void readStickers(); int32 countStickersHash(bool checkOfficial = false); + int32 countRecentStickersHash(); int32 countFeaturedStickersHash(); void writeSavedGifs(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4b55121dc7..3391afaa2c 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -301,11 +301,6 @@ void MainWidget::finishForwarding(History *history, bool silent) { FullMsgId newId(peerToChannel(history->peer->id), clientMsgId()); HistoryMessage *msg = static_cast(_toForward.cbegin().value()); history->addNewForwarded(newId.msg, flags, date(MTP_int(unixtime())), showFromName ? MTP::authedId() : 0, msg); - if (HistoryMedia *media = msg->getMedia()) { - if (media->type() == MediaTypeSticker) { - App::main()->incrementSticker(media->getDocument()); - } - } App::historyRegRandom(randomId, newId); } if (forwardFrom != i.value()->history()->peer) { @@ -3679,71 +3674,60 @@ void MainWidget::updateNotifySetting(PeerData *peer, NotifySettingStatus notify, void MainWidget::incrementSticker(DocumentData *sticker) { if (!sticker || !sticker->sticker()) return; + if (sticker->sticker()->set.type() == mtpc_inputStickerSetEmpty) return; - RecentStickerPack &recent(cGetRecentStickers()); - RecentStickerPack::iterator i = recent.begin(), e = recent.end(); - for (; i != e; ++i) { + bool writeStickers = false; + auto &sets = Global::RefStickerSets(); + auto it = sets.find(Stickers::CloudRecentSetId); + if (it == sets.cend()) { + if (it == sets.cend()) { + it = sets.insert(Stickers::CloudRecentSetId, Stickers::Set(Stickers::CloudRecentSetId, 0, lang(lng_emoji_category0), QString(), 0, 0, qFlags(MTPDstickerSet_ClientFlag::f_special))); + } else { + it->title = lang(lng_emoji_category0); + } + } + auto index = it->stickers.indexOf(sticker); + if (index > 0) { + it->stickers.removeAt(index); + } + if (index) { + it->stickers.push_front(sticker); + writeStickers = true; + } + + // Remove that sticker from old recent, now it is in cloud recent stickers. + bool writeRecent = false; + auto &recent = cGetRecentStickers(); + for (auto i = recent.begin(), e = recent.end(); i != e; ++i) { if (i->first == sticker) { - i->second = recent.begin()->second; // throw to the first place - //++i->second; - //if (i->second > 0x8000) { - // for (RecentStickerPack::iterator j = recent.begin(); j != e; ++j) { - // if (j->second > 1) { - // j->second /= 2; - // } else { - // j->second = 1; - // } - // } - //} - for (; i != recent.begin(); --i) { - if ((i - 1)->second > i->second) { - break; - } - qSwap(*i, *(i - 1)); - } + writeRecent = true; + recent.erase(i); break; } } - if (i == e) { - while (recent.size() >= StickerPanPerRow * StickerPanRowsPerPage) recent.pop_back(); - recent.push_front(qMakePair(sticker, recent.isEmpty() ? 1 : recent.begin()->second)); - //recent.push_back(qMakePair(sticker, 1)); - //for (i = recent.end() - 1; i != recent.begin(); --i) { - // if ((i - 1)->second > i->second) { - // break; - // } - // qSwap(*i, *(i - 1)); - //} + while (!recent.isEmpty() && it->stickers.size() + recent.size() > StickerPanPerRow * StickerPanRowsPerPage) { + writeRecent = true; + recent.pop_back(); } - Local::writeUserSettings(); - - bool found = false; - uint64 setId = 0; - QString setName; - switch (sticker->sticker()->set.type()) { - case mtpc_inputStickerSetID: setId = sticker->sticker()->set.c_inputStickerSetID().vid.v; break; - case mtpc_inputStickerSetShortName: setName = qs(sticker->sticker()->set.c_inputStickerSetShortName().vshort_name).toLower().trimmed(); break; + if (writeRecent) { + Local::writeUserSettings(); } - Stickers::Sets &sets(Global::RefStickerSets()); - for (auto i = sets.cbegin(); i != sets.cend(); ++i) { - if (i->id == Stickers::CustomSetId || i->id == Stickers::DefaultSetId || (setId && i->id == setId) || (!setName.isEmpty() && i->shortName.toLower().trimmed() == setName)) { - for (int32 j = 0, l = i->stickers.size(); j < l; ++j) { - if (i->stickers.at(j) == sticker) { - found = true; - break; - } + + // Remove that sticker from custom stickers, now it is in cloud recent stickers. + auto custom = sets.find(Stickers::CustomSetId); + if (custom != sets.cend()) { + int removeIndex = custom->stickers.indexOf(sticker); + if (removeIndex >= 0) { + custom->stickers.removeAt(removeIndex); + if (custom->stickers.isEmpty()) { + sets.erase(custom); } - if (found) break; + writeStickers = true; } } - if (!found) { - Stickers::Sets::iterator it = sets.find(Stickers::CustomSetId); - if (it == sets.cend()) { - it = sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, MTPDstickerSet::Flag::f_installed)); - } - it->stickers.push_back(sticker); - ++it->count; + + if (writeStickers) { Local::writeStickers(); } _history->updateRecentStickers(); @@ -4770,6 +4754,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { App::main()->updateStickers(); } break; + case mtpc_updateRecentStickers: { + Global::SetLastStickersUpdate(0); + App::main()->updateStickers(); + } break; + case mtpc_updateReadFeaturedStickers: { for (auto &set : Global::RefStickerSets()) { if (set.flags & MTPDstickerSet_ClientFlag::f_unread) { diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index 1438fe2126..846b8ef712 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -1066,8 +1066,11 @@ enum class MTPDstickerSet_ClientFlag : int32 { // sticker set is an unread featured set f_unread = (1 << 28), + // special set like recent or custom stickers + f_special = (1 << 27), + // update this when adding new client side flags - MIN_FIELD = (1 << 28), + MIN_FIELD = (1 << 27), }; DEFINE_MTP_CLIENT_FLAGS(MTPDstickerSet) diff --git a/Telegram/SourceFiles/serialize/serialize_document.cpp b/Telegram/SourceFiles/serialize/serialize_document.cpp index 6f489e690a..62230b8abd 100644 --- a/Telegram/SourceFiles/serialize/serialize_document.cpp +++ b/Telegram/SourceFiles/serialize/serialize_document.cpp @@ -93,7 +93,7 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream & if (typeOfSet == StickerSetTypeEmpty) { attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetEmpty())); } else if (info) { - if (info->setId == Stickers::DefaultSetId || info->setId == Stickers::CustomSetId) { + if (info->setId == Stickers::DefaultSetId || info->setId == Stickers::CloudRecentSetId || info->setId == Stickers::CustomSetId) { typeOfSet = StickerSetTypeEmpty; } diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index afb3112e21..aa8ce61751 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -849,16 +849,10 @@ void SettingsInner::keyPressEvent(QKeyEvent *e) { connect(box.get(), SIGNAL(confirmed()), this, SLOT(onSwitchModerateMode())); Ui::showLayer(box.release()); break; - } else if (str == qstr("clearstickers")) { - auto box = std_::make_unique(qsl("Clear frequently used stickers list?")); - connect(box.get(), SIGNAL(confirmed()), this, SLOT(onClearStickers())); - Ui::showLayer(box.release()); - break; } else if ( qsl("debugmode").startsWith(str) || qsl("testmode").startsWith(str) || qsl("loadlang").startsWith(str) || - qsl("clearstickers").startsWith(str) || qsl("moderate").startsWith(str) || qsl("debugfiles").startsWith(str) || qsl("workmode").startsWith(str) || @@ -1267,24 +1261,6 @@ void SettingsInner::onShowSessions() { Ui::showLayer(box); } -void SettingsInner::onClearStickers() { - auto &recent(cGetRecentStickers()); - if (!recent.isEmpty()) { - recent.clear(); - Local::writeUserSettings(); - } - auto &sets(Global::RefStickerSets()); - auto it = sets.find(Stickers::CustomSetId); - if (it != sets.cend()) { - sets.erase(it); - Local::writeStickers(); - } - if (auto m = App::main()) { - emit m->stickersUpdated(); - } - Ui::hideLayer(); -} - void SettingsInner::onSwitchModerateMode() { Global::SetModerateModeEnabled(!Global::ModerateModeEnabled()); Local::writeUserSettings(); diff --git a/Telegram/SourceFiles/settingswidget.h b/Telegram/SourceFiles/settingswidget.h index d88df93c80..4d125b4a6a 100644 --- a/Telegram/SourceFiles/settingswidget.h +++ b/Telegram/SourceFiles/settingswidget.h @@ -187,7 +187,6 @@ public slots: void onUpdateLocalStorage(); private slots: - void onClearStickers(); void onSwitchModerateMode(); void onAskQuestion(); From b35c99cb0c6fa0747aafc74ab599ee91cb91a975 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 18 Jul 2016 18:39:10 +0300 Subject: [PATCH 09/13] When installing sticker set some sets can be archived. We show a box with them and describing what happend. Limit of the recent stickers count is taken from config now. --- Telegram/Resources/basic.style | 14 - Telegram/Resources/icons/stickers_add.png | Bin 0 -> 173 bytes Telegram/Resources/icons/stickers_add@2x.png | Bin 0 -> 120 bytes Telegram/Resources/langs/lang.strings | 3 +- Telegram/SourceFiles/boxes/boxes.style | 19 + Telegram/SourceFiles/boxes/stickersetbox.cpp | 373 +++++++++++------- Telegram/SourceFiles/boxes/stickersetbox.h | 32 +- Telegram/SourceFiles/dropdown.cpp | 2 +- Telegram/SourceFiles/facades.cpp | 27 ++ Telegram/SourceFiles/facades.h | 3 + .../history/field_autocomplete.cpp | 2 +- Telegram/SourceFiles/historywidget.cpp | 26 +- Telegram/SourceFiles/localstorage.cpp | 20 +- Telegram/SourceFiles/mainwidget.cpp | 2 +- Telegram/SourceFiles/mtproto/dcenter.cpp | 1 + Telegram/SourceFiles/mtproto/scheme.tl | 17 +- Telegram/SourceFiles/mtproto/scheme_auto.cpp | 111 ++++-- Telegram/SourceFiles/mtproto/scheme_auto.h | 314 ++++++++++++++- Telegram/SourceFiles/structs.cpp | 4 +- 19 files changed, 730 insertions(+), 240 deletions(-) create mode 100644 Telegram/Resources/icons/stickers_add.png create mode 100644 Telegram/Resources/icons/stickers_add@2x.png diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index 5b66706fed..94f8555f62 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -1845,20 +1845,6 @@ stickersReorderFg: #777; stickersRowDisabledOpacity: 0.4; stickersRowDuration: 200; -stickersFeaturedHeight: 32px; -stickersFeaturedFont: contactsNameFont; -stickersFeaturedPosition: point(16px, 6px); -stickersFeaturedBadgeFont: semiboldFont; -stickersFeaturedBadgeSize: 21px; -stickersFeaturedPen: contactsNewItemFg; -stickersFeaturedUnreadBg: msgFileInBg; -stickersFeaturedUnreadSize: 5px; -stickersFeaturedUnreadSkip: 5px; -stickersFeaturedUnreadTop: 7px; -stickersFeaturedInstalled: icon { - { "mediaview_save_check", #40ace3 } -}; - emojiScroll: flatScroll(solidScroll) { deltat: 48px; } diff --git a/Telegram/Resources/icons/stickers_add.png b/Telegram/Resources/icons/stickers_add.png new file mode 100644 index 0000000000000000000000000000000000000000..ac6c2a1666abbeccdade0028480f8c5590ec26f9 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a)45>FS$5RHjbCwOxmHsE1BuIRm= z`NVho+4>6auTE9Cq2oNod*Bc*{d@24mf9=#=Dfhj*lrIGrFa5LXO6}phJGDzg=YM7o X<_U1o_;D#7Xg`CetDnm{r-UW|xgkR3 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/stickers_add@2x.png b/Telegram/Resources/icons/stickers_add@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..de8948d663ddb4e7365afe1988d7aca89c556440 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj_MR?|As(G?rxXB~)z4*}Q$iB}($gji literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 35d1ebca29..bfbde65f1b 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -682,7 +682,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_stickers_add_pack" = "Add stickers"; "lng_stickers_share_pack" = "Share Stickers"; "lng_stickers_not_found" = "Sticker pack not found."; -"lng_stickers_too_many_packs" = "You have too many sticker packs. Please remove some first."; +"lng_stickers_packs_archived" = "Some of your unused stickers have been archived to make room for the sets you've activated."; +"lng_stickers_archived" = "Archived stickers"; "lng_stickers_copied" = "Sticker pack link copied to clipboard."; "lng_stickers_default_set" = "Great Minds"; "lng_stickers_you_have" = "Manage and reorder sticker packs"; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 42c691542f..54f43ec254 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -48,3 +48,22 @@ confirmInviteUserName: flatLabel(labelDefFlat) { maxHeight: 20px; } confirmInviteUserNameTop: 227px; + +stickersAddIcon: icon { + { "stickers_add", #ffffff }, +}; +stickersAddSize: size(30px, 24px); + +stickersFeaturedHeight: 32px; +stickersFeaturedFont: contactsNameFont; +stickersFeaturedPosition: point(16px, 6px); +stickersFeaturedBadgeFont: semiboldFont; +stickersFeaturedBadgeSize: 21px; +stickersFeaturedPen: contactsNewItemFg; +stickersFeaturedUnreadBg: msgFileInBg; +stickersFeaturedUnreadSize: 5px; +stickersFeaturedUnreadSkip: 5px; +stickersFeaturedUnreadTop: 7px; +stickersFeaturedInstalled: icon { + { "mediaview_save_check", #40ace3 } +}; diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index a55c26bb77..6f863e5386 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -29,6 +29,40 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "apiwrap.h" #include "localstorage.h" #include "dialogs/dialogs_layout.h" +#include "styles/style_boxes.h" + +namespace Stickers { + +void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { + auto &v = d.vsets.c_vector().v; + auto &sets = Global::RefStickerSets(); + auto &order = Global::RefStickerSetsOrder(); + Stickers::Order archived; + archived.reserve(v.size()); + QMap setsToRequest; + for_const (auto &stickerSet, v) { + if (stickerSet.type() == mtpc_stickerSet) { + auto set = Stickers::feedSet(stickerSet.c_stickerSet()); + if (set->stickers.isEmpty()) { + setsToRequest.insert(set->id, set->access); + } + auto index = order.indexOf(set->id); + if (index >= 0) { + order.removeAt(index); + } + archived.push_back(set->id); + } + } + if (!setsToRequest.isEmpty()) { + for (auto i = setsToRequest.cbegin(), e = setsToRequest.cend(); i != e; ++i) { + App::api()->scheduleStickerSetRequest(i.key(), i.value()); + } + App::api()->requestStickerSets(); + } + Ui::showLayer(new StickersBox(archived), KeepOtherLayers); +} + +} // namespace Stickers StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget() , _input(set) { @@ -117,10 +151,10 @@ bool StickerSetInner::failedSet(const RPCError &error) { return true; } -void StickerSetInner::installDone(const MTPBool &result) { +void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &result) { auto &sets = Global::RefStickerSets(); - _setFlags &= ~MTPDstickerSet::Flag::f_disabled; + _setFlags &= ~MTPDstickerSet::Flag::f_archived; _setFlags |= MTPDstickerSet::Flag::f_installed; auto it = sets.find(_setId); if (it == sets.cend()) { @@ -150,6 +184,11 @@ void StickerSetInner::installDone(const MTPBool &result) { sets.erase(custom); } } + + if (result.type() == mtpc_messages_stickerSetInstallResultArchive) { + Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); + } + Local::writeStickers(); emit App::main()->stickersUpdated(); emit installed(_setId); @@ -158,11 +197,7 @@ void StickerSetInner::installDone(const MTPBool &result) { bool StickerSetInner::installFail(const RPCError &error) { if (MTP::isDefaultHandledError(error)) return false; - if (error.type() == qstr("STICKERSETS_TOO_MUCH")) { - Ui::showLayer(new InformBox(lang(lng_stickers_too_many_packs)), KeepOtherLayers); - } else { - Ui::showLayer(new InformBox(lang(lng_stickers_not_found))); - } + Ui::showLayer(new InformBox(lang(lng_stickers_not_found))); return true; } @@ -265,7 +300,7 @@ bool StickerSetInner::loaded() const { int32 StickerSetInner::notInstalled() const { if (!_loaded) return 0; auto it = Global::StickerSets().constFind(_setId); - if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_installed) || (it->flags & MTPDstickerSet::Flag::f_disabled)) return _pack.size(); + if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_installed) || (it->flags & MTPDstickerSet::Flag::f_archived)) return _pack.size(); return 0; } @@ -425,6 +460,26 @@ StickersInner::StickersInner(StickersBox::Section section) : TWidget() , _addText(lang(lng_stickers_add).toUpper()) , _addWidth(st::defaultActiveButton.font->width(_addText)) , _aboveShadow(st::boxShadow) { + setup(); +} + +StickersInner::StickersInner(const Stickers::Order &archivedIds) : TWidget() +, _section(StickersBox::Section::ArchivedPart) +, _archivedIds(archivedIds) +, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) +, _a_shifting(animation(this, &StickersInner::step_shifting)) +, _itemsTop(st::membersPadding.top()) +, _clearWidth(st::normalFont->width(lang(lng_stickers_clear_recent))) +, _removeWidth(st::normalFont->width(lang(lng_stickers_remove))) +, _returnWidth(st::normalFont->width(lang(lng_stickers_return))) +, _restoreWidth(st::normalFont->width(lang(lng_stickers_restore))) +, _addText(lang(lng_stickers_add).toUpper()) +, _addWidth(st::defaultActiveButton.font->width(_addText)) +, _aboveShadow(st::boxShadow) { + setup(); +} + +void StickersInner::setup() { connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); setMouseTracking(true); } @@ -520,26 +575,28 @@ void StickersInner::paintRow(Painter &p, int32 index) { p.fillRect(row, st::white); p.setOpacity(1); } - } else if (s->installed) { - int addw = _addWidth - st::defaultActiveButton.width; + } else if (s->installed && !s->disabled) { + int addw = st::stickersAddSize.width(); int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (addw + st::stickersFeaturedInstalled.width()) / 2); int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2; st::stickersFeaturedInstalled.paint(p, QPoint(checkx, checky), width()); } else { - int addw = _addWidth - st::defaultActiveButton.width; + int addw = st::stickersAddSize.width(); int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw; - int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2; - QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.height)); + int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersAddSize.height()) / 2; + QRect add(myrtlrect(addx, addy, addw, st::stickersAddSize.height())); auto textBg = (_actionSel == index) ? st::defaultActiveButton.textBgOver : st::defaultActiveButton.textBg; App::roundRect(p, add, textBg, ImageRoundRadius::Small); - p.setFont(st::defaultActiveButton.font); - p.setPen(st::defaultActiveButton.textFg); - int textTop = (_actionSel == index && _actionDown == index) ? st::defaultActiveButton.downTextTop : st::defaultActiveButton.textTop; - p.drawTextLeft(addx - st::defaultActiveButton.width / 2, addy + textTop, width(), _addText, _addWidth); + int iconx = addx + (st::stickersAddSize.width() - st::stickersAddIcon.width()) / 2; + int icony = addy + (st::stickersAddSize.height() - st::stickersAddIcon.height()) / 2; + icony += (_actionSel == index && _actionDown == index) ? (st::defaultActiveButton.downTextTop - st::defaultActiveButton.textTop) : 0; + st::stickersAddIcon.paint(p, QPoint(iconx, icony), width()); } - if (s->disabled) p.setOpacity(st::stickersRowDisabledOpacity); + if (s->disabled && _section == Section::Installed) { + p.setOpacity(st::stickersRowDisabledOpacity); + } if (s->sticker) { s->sticker->thumb->load(); QPixmap pix(s->sticker->thumb->pix(s->pixw, s->pixh)); @@ -643,13 +700,13 @@ void StickersInner::onUpdateSelected() { int remw = _rows.at(selected)->recent ? _clearWidth : (_rows.at(selected)->disabled ? (_rows.at(selected)->official ? _restoreWidth : _returnWidth) : _removeWidth); QRect rem(myrtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - remw, st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, remw, st::normalFont->height)); actionSel = rem.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1; - } else if (_rows.at(selected)->installed) { + } else if (_rows.at(selected)->installed && !_rows.at(selected)->disabled) { actionSel = -1; } else { - int addw = _addWidth - st::defaultActiveButton.width; + int addw = st::stickersAddSize.width(); int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw; - int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2; - QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.height)); + int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersAddSize.height()) / 2; + QRect add(myrtlrect(addx, addy, addw, st::stickersAddSize.height())); actionSel = add.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1; } } else if (_featuredHeight && QRect(0, st::membersPadding.top(), width(), _featuredHeight).contains(local)) { @@ -661,7 +718,7 @@ void StickersInner::onUpdateSelected() { if ((_selected == -1) != (selected == -1)) { update(); } - if (_section == Section::Featured && ((_selected >= 0 || _pressed >= 0) != (selected >= 0 || _pressed >= 0))) { + if (_section != Section::Installed && ((_selected >= 0 || _pressed >= 0) != (selected >= 0 || _pressed >= 0))) { setCursor((selected >= 0 || _pressed >= 0) ? style::cur_pointer : style::cur_default); } _selected = selected; @@ -711,7 +768,7 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) { auto pressed = _pressed; _pressed = -2; - if (_section == Section::Featured && _selected < 0 && pressed >= 0) { + if (_section != Section::Installed && _selected < 0 && pressed >= 0) { setCursor(style::cur_default); } @@ -746,7 +803,7 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) { if (_selected == -1) { _selected = -2; Ui::showLayer(new StickersBox(Section::Featured), KeepOtherLayers); - } else if (_selected >= 0 && _section == Section::Featured) { + } else if (_selected >= 0 && _section != Section::Installed) { auto &sets = Global::RefStickerSets(); auto it = sets.find(_rows.at(pressed)->id); if (it != sets.cend()) { @@ -774,9 +831,9 @@ void StickersInner::installSet(uint64 setId) { return; } - MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), RPCDoneHandlerPtr(), rpcFail(&StickersInner::installFail, setId)); + MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), rpcDone(&StickersInner::installDone), rpcFail(&StickersInner::installFail, setId)); - it->flags &= ~(MTPDstickerSet::Flag::f_disabled | MTPDstickerSet_ClientFlag::f_unread); + it->flags &= ~(MTPDstickerSet::Flag::f_archived | MTPDstickerSet_ClientFlag::f_unread); it->flags |= MTPDstickerSet::Flag::f_installed; auto &order = Global::RefStickerSetsOrder(); @@ -802,6 +859,24 @@ void StickersInner::installSet(uint64 setId) { emit App::main()->stickersUpdated(); } +void StickersInner::installDone(const MTPmessages_StickerSetInstallResult &result) { + if (result.type() == mtpc_messages_stickerSetInstallResultArchive) { + Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); + Local::writeStickers(); + emit App::main()->stickersUpdated(); + } + + // TEST DATA ONLY + //MTPVector v = MTP_vector(0); + //for (auto &set : Global::RefStickerSets()) { + // if (rand() < RAND_MAX / 2) { + // set.flags |= MTPDstickerSet::Flag::f_archived; + // v._vector().v.push_back(MTP_stickerSet(MTP_flags(set.flags), MTP_long(set.id), MTP_long(set.access), MTP_string(set.title), MTP_string(set.shortName), MTP_int(set.count), MTP_int(set.hash))); + // } + //} + //Stickers::applyArchivedResult(MTP_messages_stickerSetInstallResultArchive(v).c_messages_stickerSetInstallResultArchive()); +} + bool StickersInner::installFail(uint64 setId, const RPCError &error) { if (MTP::isDefaultHandledError(error)) return false; @@ -823,11 +898,7 @@ bool StickersInner::installFail(uint64 setId, const RPCError &error) { Local::writeStickers(); emit App::main()->stickersUpdated(); - if (error.type() == qstr("STICKERSETS_TOO_MUCH")) { - Ui::showLayer(new InformBox(lang(lng_stickers_too_many_packs)), KeepOtherLayers); - } else { - Ui::showLayer(new InformBox(lang(lng_stickers_not_found)), KeepOtherLayers); - } + Ui::showLayer(new InformBox(lang(lng_stickers_not_found)), KeepOtherLayers); return true; } @@ -884,12 +955,12 @@ void StickersInner::clear() { _aboveShadowFadeStart = 0; _aboveShadowFadeOpacity = anim::fvalue(0, 0); _a_shifting.stop(); -_above = _dragging = _started = -1; -_selected = -2; -_pressed = -2; -_actionDown = -1; -setActionSel(-1); -update(); + _above = _dragging = _started = -1; + _selected = -2; + _pressed = -2; + _actionDown = -1; + setActionSel(-1); + update(); } void StickersInner::setActionSel(int32 actionSel) { @@ -922,50 +993,23 @@ void StickersInner::rebuild() { } clear(); - auto &order = (_section == Section::Installed) ? Global::StickerSetsOrder() : Global::FeaturedStickerSetsOrder(); - _animStartTimes.reserve(order.size()); + auto &order = ([this]() { + if (_section == Section::Installed) { + return Global::StickerSetsOrder(); + } else if (_section == Section::Featured) { + return Global::FeaturedStickerSetsOrder(); + } + return _archivedIds; + })(); + _rows.reserve(order.size() + 1); + _animStartTimes.reserve(order.size() + 1); auto &sets = Global::StickerSets(); - auto cloudIt = sets.constFind(Stickers::CloudRecentSetId); - if (cloudIt != sets.cend() && !cloudIt->stickers.isEmpty()) { - DocumentData *sticker = cloudIt->stickers.at(0); - int32 pixw = 0, pixh = 0; - if (sticker) { - pixw = sticker->thumb->width(); - pixh = sticker->thumb->height(); - if (pixw > st::contactsPhotoSize) { - if (pixw > pixh) { - pixh = (pixh * st::contactsPhotoSize) / pixw; - pixw = st::contactsPhotoSize; - } else { - pixw = (pixw * st::contactsPhotoSize) / pixh; - pixh = st::contactsPhotoSize; - } - } else if (pixh > st::contactsPhotoSize) { - pixw = (pixw * st::contactsPhotoSize) / pixh; - pixh = st::contactsPhotoSize; - } + if (_section == Section::Installed) { + auto cloudIt = sets.constFind(Stickers::CloudRecentSetId); + if (cloudIt != sets.cend() && !cloudIt->stickers.isEmpty()) { + rebuildAppendSet(cloudIt.value(), namew); } - QString title = cloudIt->title; - int32 titleWidth = st::contactsNameFont->width(title); - if (titleWidth > namew) { - title = st::contactsNameFont->elided(title, namew); - } - int count = cloudIt->stickers.size(); - int added = 0; - auto customIt = sets.constFind(Stickers::CustomSetId); - if (customIt != sets.cend()) { - added = customIt->stickers.size(); - for_const (auto &sticker, cGetRecentStickers()) { - if (customIt->stickers.indexOf(sticker.first) < 0) { - ++added; - } - } - } else { - added = cGetRecentStickers().size(); - } - rows.push_back(new StickerSetRow(cloudIt->id, cloudIt->stickers.front(), count + added, title, true, true, false, false, true, pixw, pixh)); - _animStartTimes.push_back(0); } for_const (auto setId, order) { auto it = sets.constFind(setId); @@ -973,47 +1017,13 @@ void StickersInner::rebuild() { continue; } - bool recent = false; - bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); - bool disabled = (_section == Section::Installed) && (it->flags & MTPDstickerSet::Flag::f_disabled); - bool official = (it->flags & MTPDstickerSet::Flag::f_official); - bool unread = (_section == Section::Featured) && _unreadSets.contains(it->id); - if (!unread && _section == Section::Featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { - unread = true; - _unreadSets.insert(it->id); - } + rebuildAppendSet(it.value(), namew); - DocumentData *sticker = it->stickers.isEmpty() ? 0 : it->stickers.at(0); - int32 pixw = 0, pixh = 0; - if (sticker) { - pixw = sticker->thumb->width(); - pixh = sticker->thumb->height(); - if (pixw > st::contactsPhotoSize) { - if (pixw > pixh) { - pixh = (pixh * st::contactsPhotoSize) / pixw; - pixw = st::contactsPhotoSize; - } else { - pixw = (pixw * st::contactsPhotoSize) / pixh; - pixh = st::contactsPhotoSize; - } - } else if (pixh > st::contactsPhotoSize) { - pixw = (pixw * st::contactsPhotoSize) / pixh; - pixh = st::contactsPhotoSize; - } - } - QString title = it->title; - int32 titleWidth = st::contactsNameFont->width(title); - if (titleWidth > namew) { - title = st::contactsNameFont->elided(title, namew); - } - (disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, installed, official, unread, disabled, recent, pixw, pixh)); - _animStartTimes.push_back(0); if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { App::api()->scheduleStickerSetRequest(it->id, it->access); } } App::api()->requestStickerSets(); - _rows = rows + rowsDisabled; resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom()); if (_section == Section::Featured && Global::FeaturedStickerSetsUnreadCount()) { @@ -1025,6 +1035,68 @@ void StickersInner::rebuild() { } } +void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) { + bool recent = (set.id == Stickers::CloudRecentSetId); + bool installed = true; + bool official = true; + bool unread = false; + bool disabled = false; + if (!recent) { + installed = (set.flags & MTPDstickerSet::Flag::f_installed); + official = (set.flags & MTPDstickerSet::Flag::f_official); + disabled = (set.flags & MTPDstickerSet::Flag::f_archived); + if (_section == Section::Featured) { + unread = _unreadSets.contains(set.id); + if (!unread && (set.flags & MTPDstickerSet_ClientFlag::f_unread)) { + unread = true; + _unreadSets.insert(set.id); + } + } else if (_section == Section::Installed && disabled) { + return; + } + } + + auto sticker = set.stickers.at(0); + int32 pixw = 0, pixh = 0; + if (sticker) { + pixw = sticker->thumb->width(); + pixh = sticker->thumb->height(); + if (pixw > st::contactsPhotoSize) { + if (pixw > pixh) { + pixh = (pixh * st::contactsPhotoSize) / pixw; + pixw = st::contactsPhotoSize; + } else { + pixw = (pixw * st::contactsPhotoSize) / pixh; + pixh = st::contactsPhotoSize; + } + } else if (pixh > st::contactsPhotoSize) { + pixw = (pixw * st::contactsPhotoSize) / pixh; + pixh = st::contactsPhotoSize; + } + } + QString title = set.title; + int32 titleWidth = st::contactsNameFont->width(title); + if (titleWidth > maxNameWidth) { + title = st::contactsNameFont->elided(title, maxNameWidth); + } + int count = set.stickers.size(), added = 0; + if (recent) { + auto customIt = Global::StickerSets().constFind(Stickers::CustomSetId); + if (customIt != Global::StickerSets().cend()) { + added = customIt->stickers.size(); + for_const (auto &sticker, cGetRecentStickers()) { + if (customIt->stickers.indexOf(sticker.first) < 0) { + ++added; + } + } + } else { + added = cGetRecentStickers().size(); + } + } + _rows.push_back(new StickerSetRow(set.id, sticker, count + added, title, installed, official, unread, disabled, recent, pixw, pixh)); + _animStartTimes.push_back(0); +} + void StickersInner::readFeaturedDone(const MTPBool &result) { Local::writeStickers(); emit App::main()->stickersUpdated(); @@ -1045,8 +1117,8 @@ bool StickersInner::readFeaturedFail(const RPCError &error) { return true; } -QVector StickersInner::getOrder() const { - QVector result; +Stickers::Order StickersInner::getOrder() const { + Stickers::Order result; result.reserve(_rows.size()); for (int32 i = 0, l = _rows.size(); i < l; ++i) { if (_rows.at(i)->disabled) { @@ -1063,8 +1135,8 @@ QVector StickersInner::getOrder() const { return result; } -QVector StickersInner::getDisabledSets() const { - QVector result; +Stickers::Order StickersInner::getDisabledSets() const { + Stickers::Order result; result.reserve(_rows.size()); for (int32 i = 0, l = _rows.size(); i < l; ++i) { if (_rows.at(i)->disabled) { @@ -1087,15 +1159,24 @@ StickersInner::~StickersInner() { StickersBox::StickersBox(Section section) : ItemListBox(st::boxScroll) , _section(section) , _inner(section) -, _reorderRequest(0) -, _topShadow(this, st::contactsAboutShadow) -, _scrollDelta(0) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) , _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) { + setup(); +} +StickersBox::StickersBox(const Stickers::Order &archivedIds) : ItemListBox(st::boxScroll) +, _section(Section::ArchivedPart) +, _inner(archivedIds) +, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) +, _about(st::boxTextFont, lang(lng_stickers_packs_archived), _defaultOptions, _aboutWidth) { + setup(); +} + +void StickersBox::setup() { int bottomSkip = st::boxPadding.bottom(); if (_section == Section::Installed) { _aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom(); + _topShadow = new PlainShadow(this, st::contactsAboutShadow); _save = new BoxButton(this, lang(lng_settings_save), st::defaultBoxButton); connect(_save, SIGNAL(clicked()), this, SLOT(onSave())); @@ -1105,6 +1186,12 @@ StickersBox::StickersBox(Section section) : ItemListBox(st::boxScroll) _bottomShadow = new ScrollableBoxShadow(this); bottomSkip = st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom(); + } else if (_section == Section::ArchivedPart) { + _aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom(); + _topShadow = new PlainShadow(this, st::contactsAboutShadow); + + _save = new BoxButton(this, lang(lng_box_ok), st::defaultBoxButton); + connect(_save, SIGNAL(clicked()), this, SLOT(onClose())); } ItemListBox::init(_inner, bottomSkip, st::boxTitleHeight + _aboutHeight); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); @@ -1130,7 +1217,7 @@ int32 StickersBox::countHeight() const { return st::boxTitleHeight + _aboutHeight + _inner->height() + bottomSkip; } -void StickersBox::disenableDone(const MTPBool & result, mtpRequestId req) { +void StickersBox::disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req) { _disenableRequests.remove(req); if (_disenableRequests.isEmpty()) { saveOrder(); @@ -1178,7 +1265,15 @@ void StickersBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, lang(lng_stickers_packs)); + auto title = ([this]() { + if (_section == Section::Installed) { + return lang(lng_stickers_packs); + } else if (_section == Section::Featured) { + return lang(lng_stickers_featured); + } + return lang(lng_stickers_archived); + })(); + paintTitle(p, title); p.translate(0, st::boxTitleHeight); if (_aboutHeight > 0) { @@ -1207,10 +1302,14 @@ void StickersBox::closePressed() { void StickersBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); _inner->resize(width(), _inner->height()); - _topShadow.setGeometry(0, st::boxTitleHeight + _aboutHeight, width(), st::lineWidth); _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); + if (_topShadow) { + _topShadow->setGeometry(0, st::boxTitleHeight + _aboutHeight, width(), st::lineWidth); + } if (_save) { _save->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save->height()); + } + if (_cancel) { _cancel->moveToRight(st::boxButtonPadding.right() + _save->width() + st::boxButtonPadding.left(), _save->y()); _bottomShadow->setGeometry(0, height() - st::boxButtonPadding.bottom() - _save->height() - st::boxButtonPadding.top() - st::lineWidth, width(), st::lineWidth); } @@ -1255,7 +1354,7 @@ void StickersBox::onSave() { auto &recent = cGetRecentStickers(); auto &sets = Global::RefStickerSets(); - QVector reorder = _inner->getOrder(), disabled = _inner->getDisabledSets(); + auto reorder = _inner->getOrder(), disabled = _inner->getDisabledSets(); for (int32 i = 0, l = disabled.size(); i < l; ++i) { auto it = sets.find(disabled.at(i)); if (it != sets.cend()) { @@ -1267,11 +1366,11 @@ void StickersBox::onSave() { ++i; } } - if (!(it->flags & MTPDstickerSet::Flag::f_disabled)) { + 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 (it->flags & MTPDstickerSet::Flag::f_official) { _disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolTrue()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); - it->flags |= MTPDstickerSet::Flag::f_disabled; + it->flags |= MTPDstickerSet::Flag::f_archived; } else { _disenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); int removeIndex = Global::StickerSetsOrder().indexOf(it->id); @@ -1279,7 +1378,7 @@ void StickersBox::onSave() { if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { sets.erase(it); } else { - it->flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet::Flag::f_disabled); + it->flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet::Flag::f_archived); } } } @@ -1296,10 +1395,10 @@ void StickersBox::onSave() { for (int i = 0, l = reorder.size(); i < l; ++i) { auto it = sets.find(reorder.at(i)); if (it != sets.cend()) { - if ((it->flags & MTPDstickerSet::Flag::f_disabled) && !disabled.contains(it->id)) { + if ((it->flags & MTPDstickerSet::Flag::f_archived) && !disabled.contains(it->id)) { MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName)); _disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolFalse()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); - it->flags &= ~MTPDstickerSet::Flag::f_disabled; + it->flags &= ~MTPDstickerSet::Flag::f_archived; } order.push_back(reorder.at(i)); it->flags |= MTPDstickerSet::Flag::f_installed; @@ -1327,9 +1426,13 @@ void StickersBox::onSave() { } void StickersBox::hideAll() { - _topShadow.hide(); + if (_topShadow) { + _topShadow->hide(); + } if (_save) { _save->hide(); + } + if (_cancel) { _cancel->hide(); _bottomShadow->hide(); } @@ -1337,9 +1440,13 @@ void StickersBox::hideAll() { } void StickersBox::showAll() { - _topShadow.show(); + if (_topShadow) { + _topShadow->show(); + } if (_save) { _save->show(); + } + if (_cancel) { _cancel->show(); _bottomShadow->show(); } @@ -1353,7 +1460,7 @@ int32 stickerPacksCount(bool includeDisabledOfficial) { for (int i = 0, l = order.size(); i < l; ++i) { auto it = sets.constFind(order.at(i)); if (it != sets.cend()) { - if (!(it->flags & MTPDstickerSet::Flag::f_disabled) || ((it->flags & MTPDstickerSet::Flag::f_official) && includeDisabledOfficial)) { + if (!(it->flags & MTPDstickerSet::Flag::f_archived) || ((it->flags & MTPDstickerSet::Flag::f_official) && includeDisabledOfficial)) { ++result; } } diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 70f65e3c32..44d60e770e 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -64,7 +64,7 @@ private: void gotSet(const MTPmessages_StickerSet &set); bool failedSet(const RPCError &error); - void installDone(const MTPBool &result); + void installDone(const MTPmessages_StickerSetInstallResult &result); bool installFail(const RPCError &error); StickerPack _pack; @@ -130,19 +130,21 @@ class StickersBox : public ItemListBox, public RPCSender { Q_OBJECT public: - enum class Section { Installed, Featured, + Archived, + ArchivedPart, }; StickersBox(Section section = Section::Installed); + StickersBox(const Stickers::Order &archivedIds); + void resizeEvent(QResizeEvent *e); void paintEvent(QPaintEvent *e); void closePressed(); public slots: - void onStickersUpdated(); void onCheckDraggingScroll(int localY); @@ -152,15 +154,14 @@ public slots: void onSave(); protected: - void hideAll(); void showAll(); private: - + void setup(); int32 countHeight() const; - void disenableDone(const MTPBool &result, mtpRequestId req); + void disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req); bool disenableFail(const RPCError &error, mtpRequestId req); void reorderDone(const MTPBool &result); bool reorderFail(const RPCError &result); @@ -172,12 +173,12 @@ private: ChildWidget _save = { nullptr }; ChildWidget _cancel = { nullptr }; QMap _disenableRequests; - mtpRequestId _reorderRequest; - PlainShadow _topShadow; + mtpRequestId _reorderRequest = 0; + ChildWidget _topShadow = { nullptr }; ChildWidget _bottomShadow = { nullptr }; QTimer _scrollTimer; - int32 _scrollDelta; + int32 _scrollDelta = 0; int _aboutWidth = 0; Text _about; @@ -195,6 +196,7 @@ class StickersInner : public TWidget, public RPCSender { public: using Section = StickersBox::Section; StickersInner(Section section); + StickersInner(const Stickers::Order &archivedIds); void rebuild(); bool savingStart() { @@ -203,8 +205,8 @@ public: return true; } - QVector getOrder() const; - QVector getDisabledSets() const; + Stickers::Order getOrder() const; + Stickers::Order getDisabledSets() const; void setVisibleScrollbar(int32 width); @@ -227,6 +229,7 @@ public slots: void onClearBoxDestroyed(QObject *box); private: + void setup(); void paintFeaturedButton(Painter &p) const; void step_shifting(uint64 ms, bool timer); @@ -236,11 +239,13 @@ private: float64 aboveShadowOpacity() const; void installSet(uint64 setId); + void installDone(const MTPmessages_StickerSetInstallResult &result); bool installFail(uint64 setId, const RPCError &error); void readFeaturedDone(const MTPBool &result); bool readFeaturedFail(const RPCError &error); Section _section; + Stickers::Order _archivedIds; int32 _rowHeight; struct StickerSetRow { @@ -265,7 +270,10 @@ private: int32 pixw, pixh; anim::ivalue yadd; }; - typedef QList StickerSetRows; + using StickerSetRows = QList; + + void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth); + StickerSetRows _rows; QList _animStartTimes; uint64 _aboveShadowFadeStart = 0; diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 1c63f49bac..6d86f12d4e 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -2088,7 +2088,7 @@ bool StickerPanInner::ui_isInlineItemBeingChosen() { void StickerPanInner::appendSet(uint64 setId) { auto &sets = Global::StickerSets(); auto it = sets.constFind(setId); - if (it == sets.cend() || (it->flags & MTPDstickerSet::Flag::f_disabled) || it->stickers.isEmpty()) return; + if (it == sets.cend() || (it->flags & MTPDstickerSet::Flag::f_archived) || it->stickers.isEmpty()) return; StickerPack pack; pack.reserve(it->stickers.size()); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index d4e7318c0d..80c4335273 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -520,6 +520,31 @@ DefineVar(Sandbox, ConnectionProxy, PreLaunchProxy); } // namespace Sandbox +namespace Stickers { + +Set *feedSet(const MTPDstickerSet &set) { + auto &sets = Global::RefStickerSets(); + auto it = sets.find(set.vid.v); + auto title = stickerSetTitle(set); + if (it == sets.cend()) { + 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 | MTPDstickerSet_ClientFlag::f_not_loaded)); + } 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; + 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 + } + } + return &it.value(); +} + +} // namespace Stickers + namespace Global { namespace internal { @@ -556,6 +581,7 @@ struct Data { int32 PushChatLimit = 2; int32 SavedGifsLimit = 200; int32 EditTimeLimit = 172800; + int32 StickersRecentLimit = 30; HiddenPinnedMessagesMap HiddenPinnedMessages; @@ -628,6 +654,7 @@ DefineVar(Global, int32, PushChatPeriod); DefineVar(Global, int32, PushChatLimit); DefineVar(Global, int32, SavedGifsLimit); DefineVar(Global, int32, EditTimeLimit); +DefineVar(Global, int32, StickersRecentLimit); DefineVar(Global, HiddenPinnedMessagesMap, HiddenPinnedMessages); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index d0d09ff296..d99b54bb80 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -214,6 +214,8 @@ inline MTPInputStickerSet inputSetId(const Set &set) { return MTP_inputStickerSetShortName(MTP_string(set.shortName)); } +Set *feedSet(const MTPDstickerSet &set); + } // namespace Stickers namespace Global { @@ -254,6 +256,7 @@ DeclareVar(int32, PushChatPeriod); DeclareVar(int32, PushChatLimit); DeclareVar(int32, SavedGifsLimit); DeclareVar(int32, EditTimeLimit); +DeclareVar(int32, StickersRecentLimit); typedef QMap HiddenPinnedMessagesMap; DeclareVar(HiddenPinnedMessagesMap, HiddenPinnedMessages); diff --git a/Telegram/SourceFiles/history/field_autocomplete.cpp b/Telegram/SourceFiles/history/field_autocomplete.cpp index 49cb16fde4..a2aebf4a2c 100644 --- a/Telegram/SourceFiles/history/field_autocomplete.cpp +++ b/Telegram/SourceFiles/history/field_autocomplete.cpp @@ -161,7 +161,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { if (it->emoji.isEmpty()) { setsToRequest.insert(it->id, it->access); it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; - } else if (!(it->flags & MTPDstickerSet::Flag::f_disabled)) { + } else if (!(it->flags & MTPDstickerSet::Flag::f_archived)) { StickersByEmojiMap::const_iterator i = it->emoji.constFind(emojiGetNoColor(_emoji)); if (i != it->emoji.cend()) { srows += *i; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 08523d6892..0e2bcfacb5 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3667,27 +3667,11 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { } for_const (auto &setData, d_sets) { if (setData.type() == mtpc_stickerSet) { - const auto &set(setData.c_stickerSet()); - auto it = sets.find(set.vid.v); - QString title = stickerSetTitle(set); - if (it == sets.cend()) { - 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 | MTPDstickerSet_ClientFlag::f_not_loaded)); - } 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; - 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 - } - } - if (!(it->flags & MTPDstickerSet::Flag::f_disabled) || (it->flags & MTPDstickerSet::Flag::f_official)) { - 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 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); } } } diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 68a443ca00..6ebdbea102 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -541,6 +541,7 @@ namespace { dbiHiddenPinnedMessages = 0x39, dbiDialogsMode = 0x40, dbiModerateMode = 0x41, + dbiStickersRecentLimit = 0x43, dbiEncryptedWithSalt = 333, dbiEncrypted = 444, @@ -834,6 +835,14 @@ namespace { Global::SetSavedGifsLimit(limit); } break; + case dbiStickersRecentLimit: { + qint32 limit; + stream >> limit; + if (!_checkStreamStatus(stream)) return false; + + Global::SetStickersRecentLimit(limit); + } break; + case dbiMegagroupSizeMax: { qint32 maxSize; stream >> maxSize; @@ -2175,12 +2184,13 @@ namespace Local { size += Serialize::stringSize(proxy.host) + sizeof(qint32) + Serialize::stringSize(proxy.user) + Serialize::stringSize(proxy.password); } - size += sizeof(quint32) + sizeof(qint32) * 6; + size += sizeof(quint32) + sizeof(qint32) * 7; EncryptedDescriptor data(size); data.stream << quint32(dbiChatSizeMax) << qint32(Global::ChatSizeMax()); data.stream << quint32(dbiMegagroupSizeMax) << qint32(Global::MegagroupSizeMax()); data.stream << quint32(dbiSavedGifsLimit) << qint32(Global::SavedGifsLimit()); + data.stream << quint32(dbiStickersRecentLimit) << qint32(Global::StickersRecentLimit()); data.stream << quint32(dbiAutoStart) << qint32(cAutoStart()); data.stream << quint32(dbiStartMinimized) << qint32(cStartMinimized()); data.stream << quint32(dbiSendToMenu) << qint32(cSendToMenu()); @@ -3053,7 +3063,7 @@ namespace Local { for_const (auto &set, sets) { bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded); if (notLoaded && !(set.flags & MTPDstickerSet_ClientFlag::f_special)) { - if (!(set.flags & MTPDstickerSet::Flag::f_disabled) + if (!(set.flags & MTPDstickerSet::Flag::f_archived) || (set.flags & MTPDstickerSet::Flag::f_official) || (set.flags & MTPDstickerSet_ClientFlag::f_featured)) { // waiting to receive return; @@ -3155,7 +3165,9 @@ namespace Local { custom.stickers.push_back(doc); ++custom.count; } - if (recent.size() < StickerPanPerRow * StickerPanRowsPerPage && qAbs(value) > 1) recent.push_back(qMakePair(doc, qAbs(value))); + if (recent.size() < Global::StickersRecentLimit() && qAbs(value) > 1) { + recent.push_back(qMakePair(doc, qAbs(value))); + } } if (def.stickers.isEmpty()) { sets.remove(Stickers::DefaultSetId); @@ -3324,7 +3336,7 @@ namespace Local { } else if (j->flags & MTPDstickerSet::Flag::f_official) { foundOfficial = true; } - if (!(j->flags & MTPDstickerSet::Flag::f_disabled)) { + if (!(j->flags & MTPDstickerSet::Flag::f_archived)) { acc = (acc * 20261) + j->hash; } } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 3391afaa2c..9c5c00f3dc 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3705,7 +3705,7 @@ void MainWidget::incrementSticker(DocumentData *sticker) { break; } } - while (!recent.isEmpty() && it->stickers.size() + recent.size() > StickerPanPerRow * StickerPanRowsPerPage) { + while (!recent.isEmpty() && it->stickers.size() + recent.size() > Global::StickersRecentLimit()) { writeRecent = true; recent.pop_back(); } diff --git a/Telegram/SourceFiles/mtproto/dcenter.cpp b/Telegram/SourceFiles/mtproto/dcenter.cpp index 7043e26b99..f15fd2fc46 100644 --- a/Telegram/SourceFiles/mtproto/dcenter.cpp +++ b/Telegram/SourceFiles/mtproto/dcenter.cpp @@ -170,6 +170,7 @@ namespace { Global::SetPushChatLimit(data.vpush_chat_limit.v); // ? Global::SetSavedGifsLimit(data.vsaved_gifs_limit.v); Global::SetEditTimeLimit(data.vedit_time_limit.v); // ? + Global::SetStickersRecentLimit(data.vstickers_recent_limit.v); configLoadedOnce = true; Local::writeSettings(); diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index 6f98b58912..168945f8d5 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -418,7 +418,7 @@ upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true id:int ip_address:string port:int = DcOption; -config#c9411388 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int disabled_features:Vector = Config; +config#f401a4bf date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; @@ -555,7 +555,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -stickerSet#cd303b41 flags:# installed:flags.0?true disabled:flags.1?true official:flags.2?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; +stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; @@ -672,7 +672,7 @@ auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -messages.botCallbackAnswer#31fde6e4 flags:# alert:flags.1?true allow_pip:flags.2?true message:flags.0?string url:flags.3?string = messages.BotCallbackAnswer; +messages.botCallbackAnswer#31fde6e4 flags:# alert:flags.1?true message:flags.0?string url:flags.3?string = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; @@ -704,6 +704,11 @@ messages.featuredStickers#ed6392b7 hash:int sets:Vector unread:Vecto messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; +messages.archivedStickers#f3475c0c count:int sets:Vector = messages.ArchivedStickers; + +messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; +messages.stickerSetInstallResultArchive#192c8a4e sets:Vector = messages.StickerSetInstallResult; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -814,7 +819,7 @@ messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; -messages.installStickerSet#7b30c3a6 stickerset:InputStickerSet disabled:Bool = Bool; +messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; @@ -834,15 +839,17 @@ messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEdi messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#a6e94f04 peer:InputPeer msg_id:int data:bytes = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#70dc0fa3 flags:# alert:flags.1?true allow_pip:flags.2?true query_id:long message:flags.0?string url:flags.3?string = Bool; +messages.setBotCallbackAnswer#70dc0fa3 flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.3?string = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#e21cbb = Bool; messages.getRecentStickers#99197c2c hash:int = messages.RecentStickers; +messages.saveRecentSticker#348e39bf id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#ab02e5d2 = Bool; messages.getUnusedStickers#a978d356 limit:int = Vector; +messages.getArchivedStickers#906e241f offset_id:long limit:int = messages.ArchivedStickers; updates.getState#edd4882a = updates.State; updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp index 61c72b6955..65e157812f 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp +++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp @@ -3329,7 +3329,8 @@ void _serialize_config(MTPStringLogger &to, int32 stage, int32 lev, Types &types case 17: to.add(" saved_gifs_limit: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 18: to.add(" edit_time_limit: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 19: to.add(" rating_e_decay: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 20: to.add(" disabled_features: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 20: to.add(" stickers_recent_limit: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 21: to.add(" disabled_features: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -4399,7 +4400,7 @@ void _serialize_stickerSet(MTPStringLogger &to, int32 stage, int32 lev, Types &t switch (stage) { case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 1: to.add(" installed: "); ++stages.back(); if (flag & MTPDstickerSet::Flag::f_installed) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 2: to.add(" disabled: "); ++stages.back(); if (flag & MTPDstickerSet::Flag::f_disabled) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; + case 2: to.add(" archived: "); ++stages.back(); if (flag & MTPDstickerSet::Flag::f_archived) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; case 3: to.add(" official: "); ++stages.back(); if (flag & MTPDstickerSet::Flag::f_official) { to.add("YES [ BY BIT 2 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; case 4: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 5: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; @@ -5599,9 +5600,8 @@ void _serialize_messages_botCallbackAnswer(MTPStringLogger &to, int32 stage, int switch (stage) { case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 1: to.add(" alert: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_alert) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; - case 2: to.add(" allow_pip: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_allow_pip) { to.add("YES [ BY BIT 2 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; - case 3: to.add(" message: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 4: to.add(" url: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; + case 2: to.add(" message: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; + case 3: to.add(" url: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -5797,6 +5797,37 @@ void _serialize_messages_recentStickers(MTPStringLogger &to, int32 stage, int32 } } +void _serialize_messages_archivedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_archivedStickers"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" count: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" sets: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + +void _serialize_messages_stickerSetInstallResultSuccess(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + to.add("{ messages_stickerSetInstallResultSuccess }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); +} + +void _serialize_messages_stickerSetInstallResultArchive(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_stickerSetInstallResultArchive"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" sets: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -6264,20 +6295,6 @@ void _serialize_messages_readEncryptedHistory(MTPStringLogger &to, int32 stage, } } -void _serialize_messages_installStickerSet(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { - if (stage) { - to.add(",\n").addSpaces(lev); - } else { - to.add("{ messages_installStickerSet"); - to.add("\n").addSpaces(lev); - } - switch (stage) { - case 0: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 1: to.add(" disabled: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; - } -} - void _serialize_messages_uninstallStickerSet(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -6387,10 +6404,9 @@ void _serialize_messages_setBotCallbackAnswer(MTPStringLogger &to, int32 stage, switch (stage) { case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 1: to.add(" alert: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_alert) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; - case 2: to.add(" allow_pip: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_allow_pip) { to.add("YES [ BY BIT 2 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; - case 3: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 4: to.add(" message: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 5: to.add(" url: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; + case 2: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 3: to.add(" message: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; + case 4: to.add(" url: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -6419,6 +6435,20 @@ void _serialize_messages_readFeaturedStickers(MTPStringLogger &to, int32 stage, to.add("{ messages_readFeaturedStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } +void _serialize_messages_saveRecentSticker(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_saveRecentSticker"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" unsave: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_messages_clearRecentStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ messages_clearRecentStickers }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -7985,6 +8015,20 @@ void _serialize_messages_getStickerSet(MTPStringLogger &to, int32 stage, int32 l } } +void _serialize_messages_installStickerSet(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_installStickerSet"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" archived: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_messages_getDocumentByHash(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -8128,6 +8172,20 @@ void _serialize_messages_getUnusedStickers(MTPStringLogger &to, int32 stage, int } } +void _serialize_messages_getArchivedStickers(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_getArchivedStickers"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" offset_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_updates_getState(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ updates_getState }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -8804,6 +8862,9 @@ namespace { _serializers.insert(mtpc_messages_featuredStickers, _serialize_messages_featuredStickers); _serializers.insert(mtpc_messages_recentStickersNotModified, _serialize_messages_recentStickersNotModified); _serializers.insert(mtpc_messages_recentStickers, _serialize_messages_recentStickers); + _serializers.insert(mtpc_messages_archivedStickers, _serialize_messages_archivedStickers); + _serializers.insert(mtpc_messages_stickerSetInstallResultSuccess, _serialize_messages_stickerSetInstallResultSuccess); + _serializers.insert(mtpc_messages_stickerSetInstallResultArchive, _serialize_messages_stickerSetInstallResultArchive); _serializers.insert(mtpc_req_pq, _serialize_req_pq); _serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params); @@ -8841,7 +8902,6 @@ namespace { _serializers.insert(mtpc_messages_discardEncryption, _serialize_messages_discardEncryption); _serializers.insert(mtpc_messages_setEncryptedTyping, _serialize_messages_setEncryptedTyping); _serializers.insert(mtpc_messages_readEncryptedHistory, _serialize_messages_readEncryptedHistory); - _serializers.insert(mtpc_messages_installStickerSet, _serialize_messages_installStickerSet); _serializers.insert(mtpc_messages_uninstallStickerSet, _serialize_messages_uninstallStickerSet); _serializers.insert(mtpc_messages_editChatAdmin, _serialize_messages_editChatAdmin); _serializers.insert(mtpc_messages_reorderStickerSets, _serialize_messages_reorderStickerSets); @@ -8851,6 +8911,7 @@ namespace { _serializers.insert(mtpc_messages_setBotCallbackAnswer, _serialize_messages_setBotCallbackAnswer); _serializers.insert(mtpc_messages_saveDraft, _serialize_messages_saveDraft); _serializers.insert(mtpc_messages_readFeaturedStickers, _serialize_messages_readFeaturedStickers); + _serializers.insert(mtpc_messages_saveRecentSticker, _serialize_messages_saveRecentSticker); _serializers.insert(mtpc_messages_clearRecentStickers, _serialize_messages_clearRecentStickers); _serializers.insert(mtpc_upload_saveFilePart, _serialize_upload_saveFilePart); _serializers.insert(mtpc_upload_saveBigFilePart, _serialize_upload_saveBigFilePart); @@ -8963,6 +9024,7 @@ namespace { _serializers.insert(mtpc_channels_exportInvite, _serialize_channels_exportInvite); _serializers.insert(mtpc_messages_checkChatInvite, _serialize_messages_checkChatInvite); _serializers.insert(mtpc_messages_getStickerSet, _serialize_messages_getStickerSet); + _serializers.insert(mtpc_messages_installStickerSet, _serialize_messages_installStickerSet); _serializers.insert(mtpc_messages_getDocumentByHash, _serialize_messages_getDocumentByHash); _serializers.insert(mtpc_messages_searchGifs, _serialize_messages_searchGifs); _serializers.insert(mtpc_messages_getSavedGifs, _serialize_messages_getSavedGifs); @@ -8973,6 +9035,7 @@ namespace { _serializers.insert(mtpc_messages_getFeaturedStickers, _serialize_messages_getFeaturedStickers); _serializers.insert(mtpc_messages_getRecentStickers, _serialize_messages_getRecentStickers); _serializers.insert(mtpc_messages_getUnusedStickers, _serialize_messages_getUnusedStickers); + _serializers.insert(mtpc_messages_getArchivedStickers, _serialize_messages_getArchivedStickers); _serializers.insert(mtpc_updates_getState, _serialize_updates_getState); _serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference); _serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference); diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h index ce9c712345..3ad9425ebf 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.h +++ b/Telegram/SourceFiles/mtproto/scheme_auto.h @@ -306,7 +306,7 @@ enum { mtpc_photos_photo = 0x20212ca8, mtpc_upload_file = 0x96a18d5, mtpc_dcOption = 0x5d8c6cc, - mtpc_config = 0xc9411388, + mtpc_config = 0xf401a4bf, mtpc_nearestDc = 0x8e1a1775, mtpc_help_appUpdate = 0x8987f311, mtpc_help_noAppUpdate = 0xc45a6536, @@ -507,6 +507,9 @@ enum { mtpc_messages_featuredStickers = 0xed6392b7, mtpc_messages_recentStickersNotModified = 0xb17f890, mtpc_messages_recentStickers = 0x5ce20970, + mtpc_messages_archivedStickers = 0xf3475c0c, + mtpc_messages_stickerSetInstallResultSuccess = 0x38641628, + mtpc_messages_stickerSetInstallResultArchive = 0x192c8a4e, mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsgs = 0x3dc4b4f0, mtpc_initConnection = 0x69796de9, @@ -610,7 +613,7 @@ enum { mtpc_messages_checkChatInvite = 0x3eadb1bb, mtpc_messages_importChatInvite = 0x6c50051c, mtpc_messages_getStickerSet = 0x2619a90e, - mtpc_messages_installStickerSet = 0x7b30c3a6, + mtpc_messages_installStickerSet = 0xc78fe460, mtpc_messages_uninstallStickerSet = 0xf96e55de, mtpc_messages_startBot = 0xe6df7378, mtpc_messages_getMessagesViews = 0xc4c8a55d, @@ -637,8 +640,10 @@ enum { mtpc_messages_getFeaturedStickers = 0x2dacca4f, mtpc_messages_readFeaturedStickers = 0xe21cbb, mtpc_messages_getRecentStickers = 0x99197c2c, + mtpc_messages_saveRecentSticker = 0x348e39bf, mtpc_messages_clearRecentStickers = 0xab02e5d2, mtpc_messages_getUnusedStickers = 0xa978d356, + mtpc_messages_getArchivedStickers = 0x906e241f, mtpc_updates_getState = 0xedd4882a, mtpc_updates_getDifference = 0xa041495, mtpc_updates_getChannelDifference = 0xbb32d7c0, @@ -1370,6 +1375,12 @@ class MTPDmessages_featuredStickers; class MTPmessages_recentStickers; class MTPDmessages_recentStickers; +class MTPmessages_archivedStickers; +class MTPDmessages_archivedStickers; + +class MTPmessages_stickerSetInstallResult; +class MTPDmessages_stickerSetInstallResultArchive; + // Boxed types definitions typedef MTPBoxed MTPResPQ; @@ -1546,6 +1557,8 @@ typedef MTPBoxed MTPcontacts_TopPeers; typedef MTPBoxed MTPDraftMessage; typedef MTPBoxed MTPmessages_FeaturedStickers; typedef MTPBoxed MTPmessages_RecentStickers; +typedef MTPBoxed MTPmessages_ArchivedStickers; +typedef MTPBoxed MTPmessages_StickerSetInstallResult; // Type classes definitions @@ -9625,6 +9638,74 @@ private: }; typedef MTPBoxed MTPmessages_RecentStickers; +class MTPmessages_archivedStickers : private mtpDataOwner { +public: + MTPmessages_archivedStickers(); + MTPmessages_archivedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_archivedStickers) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmessages_archivedStickers &_messages_archivedStickers() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmessages_archivedStickers*)data; + } + const MTPDmessages_archivedStickers &c_messages_archivedStickers() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmessages_archivedStickers*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_archivedStickers); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_archivedStickers(MTPDmessages_archivedStickers *_data); + + friend class MTP::internal::TypeCreator; +}; +typedef MTPBoxed MTPmessages_ArchivedStickers; + +class MTPmessages_stickerSetInstallResult : private mtpDataOwner { +public: + MTPmessages_stickerSetInstallResult() : mtpDataOwner(0), _type(0) { + } + MTPmessages_stickerSetInstallResult(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDmessages_stickerSetInstallResultArchive &_messages_stickerSetInstallResultArchive() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_stickerSetInstallResultArchive) throw mtpErrorWrongTypeId(_type, mtpc_messages_stickerSetInstallResultArchive); + split(); + return *(MTPDmessages_stickerSetInstallResultArchive*)data; + } + const MTPDmessages_stickerSetInstallResultArchive &c_messages_stickerSetInstallResultArchive() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messages_stickerSetInstallResultArchive) throw mtpErrorWrongTypeId(_type, mtpc_messages_stickerSetInstallResultArchive); + return *(const MTPDmessages_stickerSetInstallResultArchive*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_stickerSetInstallResult(mtpTypeId type); + explicit MTPmessages_stickerSetInstallResult(MTPDmessages_stickerSetInstallResultArchive *_data); + + friend class MTP::internal::TypeCreator; + + mtpTypeId _type; +}; +typedef MTPBoxed MTPmessages_StickerSetInstallResult; + // Type constructors with data class MTPDresPQ : public mtpDataImpl { @@ -12362,7 +12443,7 @@ class MTPDconfig : public mtpDataImpl { public: MTPDconfig() { } - MTPDconfig(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, MTPint _rating_e_decay, const MTPVector &_disabled_features) : vdate(_date), vexpires(_expires), vtest_mode(_test_mode), vthis_dc(_this_dc), vdc_options(_dc_options), vchat_size_max(_chat_size_max), vmegagroup_size_max(_megagroup_size_max), vforwarded_count_max(_forwarded_count_max), vonline_update_period_ms(_online_update_period_ms), voffline_blur_timeout_ms(_offline_blur_timeout_ms), voffline_idle_timeout_ms(_offline_idle_timeout_ms), vonline_cloud_timeout_ms(_online_cloud_timeout_ms), vnotify_cloud_delay_ms(_notify_cloud_delay_ms), vnotify_default_delay_ms(_notify_default_delay_ms), vchat_big_size(_chat_big_size), vpush_chat_period_ms(_push_chat_period_ms), vpush_chat_limit(_push_chat_limit), vsaved_gifs_limit(_saved_gifs_limit), vedit_time_limit(_edit_time_limit), vrating_e_decay(_rating_e_decay), vdisabled_features(_disabled_features) { + MTPDconfig(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, MTPint _rating_e_decay, MTPint _stickers_recent_limit, const MTPVector &_disabled_features) : vdate(_date), vexpires(_expires), vtest_mode(_test_mode), vthis_dc(_this_dc), vdc_options(_dc_options), vchat_size_max(_chat_size_max), vmegagroup_size_max(_megagroup_size_max), vforwarded_count_max(_forwarded_count_max), vonline_update_period_ms(_online_update_period_ms), voffline_blur_timeout_ms(_offline_blur_timeout_ms), voffline_idle_timeout_ms(_offline_idle_timeout_ms), vonline_cloud_timeout_ms(_online_cloud_timeout_ms), vnotify_cloud_delay_ms(_notify_cloud_delay_ms), vnotify_default_delay_ms(_notify_default_delay_ms), vchat_big_size(_chat_big_size), vpush_chat_period_ms(_push_chat_period_ms), vpush_chat_limit(_push_chat_limit), vsaved_gifs_limit(_saved_gifs_limit), vedit_time_limit(_edit_time_limit), vrating_e_decay(_rating_e_decay), vstickers_recent_limit(_stickers_recent_limit), vdisabled_features(_disabled_features) { } MTPint vdate; @@ -12385,6 +12466,7 @@ public: MTPint vsaved_gifs_limit; MTPint vedit_time_limit; MTPint vrating_e_decay; + MTPint vstickers_recent_limit; MTPVector vdisabled_features; }; @@ -13195,7 +13277,7 @@ class MTPDstickerSet : public mtpDataImpl { public: enum class Flag : int32 { f_installed = (1 << 0), - f_disabled = (1 << 1), + f_archived = (1 << 1), f_official = (1 << 2), MAX_FIELD = (1 << 2), @@ -13204,7 +13286,7 @@ public: friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } bool is_installed() const { return vflags.v & Flag::f_installed; } - bool is_disabled() const { return vflags.v & Flag::f_disabled; } + bool is_archived() const { return vflags.v & Flag::f_archived; } bool is_official() const { return vflags.v & Flag::f_official; } MTPDstickerSet() { @@ -14374,7 +14456,6 @@ class MTPDmessages_botCallbackAnswer : public mtpDataImpl(v)); } bool is_alert() const { return vflags.v & Flag::f_alert; } - bool is_allow_pip() const { return vflags.v & Flag::f_allow_pip; } bool has_message() const { return vflags.v & Flag::f_message; } bool has_url() const { return vflags.v & Flag::f_url; } @@ -14540,6 +14620,27 @@ public: MTPVector vstickers; }; +class MTPDmessages_archivedStickers : public mtpDataImpl { +public: + MTPDmessages_archivedStickers() { + } + MTPDmessages_archivedStickers(MTPint _count, const MTPVector &_sets) : vcount(_count), vsets(_sets) { + } + + MTPint vcount; + MTPVector vsets; +}; + +class MTPDmessages_stickerSetInstallResultArchive : public mtpDataImpl { +public: + MTPDmessages_stickerSetInstallResultArchive() { + } + MTPDmessages_stickerSetInstallResultArchive(const MTPVector &_sets) : vsets(_sets) { + } + + MTPVector vsets; +}; + // RPC methods class MTPreq_pq { // RPC method 'req_pq' @@ -19336,32 +19437,32 @@ public: class MTPmessages_installStickerSet { // RPC method 'messages.installStickerSet' public: MTPInputStickerSet vstickerset; - MTPBool vdisabled; + MTPBool varchived; MTPmessages_installStickerSet() { } MTPmessages_installStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_installStickerSet) { read(from, end, cons); } - MTPmessages_installStickerSet(const MTPInputStickerSet &_stickerset, MTPBool _disabled) : vstickerset(_stickerset), vdisabled(_disabled) { + MTPmessages_installStickerSet(const MTPInputStickerSet &_stickerset, MTPBool _archived) : vstickerset(_stickerset), varchived(_archived) { } uint32 innerLength() const { - return vstickerset.innerLength() + vdisabled.innerLength(); + return vstickerset.innerLength() + varchived.innerLength(); } mtpTypeId type() const { return mtpc_messages_installStickerSet; } void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_installStickerSet) { vstickerset.read(from, end); - vdisabled.read(from, end); + varchived.read(from, end); } void write(mtpBuffer &to) const { vstickerset.write(to); - vdisabled.write(to); + varchived.write(to); } - typedef MTPBool ResponseType; + typedef MTPmessages_StickerSetInstallResult ResponseType; }; class MTPmessages_InstallStickerSet : public MTPBoxed { public: @@ -19371,7 +19472,7 @@ public: } MTPmessages_InstallStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { } - MTPmessages_InstallStickerSet(const MTPInputStickerSet &_stickerset, MTPBool _disabled) : MTPBoxed(MTPmessages_installStickerSet(_stickerset, _disabled)) { + MTPmessages_InstallStickerSet(const MTPInputStickerSet &_stickerset, MTPBool _archived) : MTPBoxed(MTPmessages_installStickerSet(_stickerset, _archived)) { } }; @@ -20332,7 +20433,6 @@ class MTPmessages_setBotCallbackAnswer { // RPC method 'messages.setBotCallbackA public: enum class Flag : int32 { f_alert = (1 << 1), - f_allow_pip = (1 << 2), f_message = (1 << 0), f_url = (1 << 3), @@ -20342,7 +20442,6 @@ public: friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } bool is_alert() const { return vflags.v & Flag::f_alert; } - bool is_allow_pip() const { return vflags.v & Flag::f_allow_pip; } bool has_message() const { return vflags.v & Flag::f_message; } bool has_url() const { return vflags.v & Flag::f_url; } @@ -20640,6 +20739,48 @@ public: } }; +class MTPmessages_saveRecentSticker { // RPC method 'messages.saveRecentSticker' +public: + MTPInputDocument vid; + MTPBool vunsave; + + MTPmessages_saveRecentSticker() { + } + MTPmessages_saveRecentSticker(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_saveRecentSticker) { + read(from, end, cons); + } + MTPmessages_saveRecentSticker(const MTPInputDocument &_id, MTPBool _unsave) : vid(_id), vunsave(_unsave) { + } + + uint32 innerLength() const { + return vid.innerLength() + vunsave.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_saveRecentSticker; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_saveRecentSticker) { + vid.read(from, end); + vunsave.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + vunsave.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPmessages_SaveRecentSticker : public MTPBoxed { +public: + MTPmessages_SaveRecentSticker() { + } + MTPmessages_SaveRecentSticker(const MTPmessages_saveRecentSticker &v) : MTPBoxed(v) { + } + MTPmessages_SaveRecentSticker(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SaveRecentSticker(const MTPInputDocument &_id, MTPBool _unsave) : MTPBoxed(MTPmessages_saveRecentSticker(_id, _unsave)) { + } +}; + class MTPmessages_clearRecentStickers { // RPC method 'messages.clearRecentStickers' public: MTPmessages_clearRecentStickers() { @@ -20710,6 +20851,48 @@ public: } }; +class MTPmessages_getArchivedStickers { // RPC method 'messages.getArchivedStickers' +public: + MTPlong voffset_id; + MTPint vlimit; + + MTPmessages_getArchivedStickers() { + } + MTPmessages_getArchivedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getArchivedStickers) { + read(from, end, cons); + } + MTPmessages_getArchivedStickers(const MTPlong &_offset_id, MTPint _limit) : voffset_id(_offset_id), vlimit(_limit) { + } + + uint32 innerLength() const { + return voffset_id.innerLength() + vlimit.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_getArchivedStickers; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getArchivedStickers) { + voffset_id.read(from, end); + vlimit.read(from, end); + } + void write(mtpBuffer &to) const { + voffset_id.write(to); + vlimit.write(to); + } + + typedef MTPmessages_ArchivedStickers ResponseType; +}; +class MTPmessages_GetArchivedStickers : public MTPBoxed { +public: + MTPmessages_GetArchivedStickers() { + } + MTPmessages_GetArchivedStickers(const MTPmessages_getArchivedStickers &v) : MTPBoxed(v) { + } + MTPmessages_GetArchivedStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetArchivedStickers(const MTPlong &_offset_id, MTPint _limit) : MTPBoxed(MTPmessages_getArchivedStickers(_offset_id, _limit)) { + } +}; + class MTPupdates_getState { // RPC method 'updates.getState' public: MTPupdates_getState() { @@ -23305,8 +23488,8 @@ public: inline static MTPdcOption new_dcOption(const MTPflags &_flags, MTPint _id, const MTPstring &_ip_address, MTPint _port) { return MTPdcOption(new MTPDdcOption(_flags, _id, _ip_address, _port)); } - inline static MTPconfig new_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, MTPint _rating_e_decay, const MTPVector &_disabled_features) { - return MTPconfig(new MTPDconfig(_date, _expires, _test_mode, _this_dc, _dc_options, _chat_size_max, _megagroup_size_max, _forwarded_count_max, _online_update_period_ms, _offline_blur_timeout_ms, _offline_idle_timeout_ms, _online_cloud_timeout_ms, _notify_cloud_delay_ms, _notify_default_delay_ms, _chat_big_size, _push_chat_period_ms, _push_chat_limit, _saved_gifs_limit, _edit_time_limit, _rating_e_decay, _disabled_features)); + inline static MTPconfig new_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, MTPint _rating_e_decay, MTPint _stickers_recent_limit, const MTPVector &_disabled_features) { + return MTPconfig(new MTPDconfig(_date, _expires, _test_mode, _this_dc, _dc_options, _chat_size_max, _megagroup_size_max, _forwarded_count_max, _online_update_period_ms, _offline_blur_timeout_ms, _offline_idle_timeout_ms, _online_cloud_timeout_ms, _notify_cloud_delay_ms, _notify_default_delay_ms, _chat_big_size, _push_chat_period_ms, _push_chat_limit, _saved_gifs_limit, _edit_time_limit, _rating_e_decay, _stickers_recent_limit, _disabled_features)); } inline static MTPnearestDc new_nearestDc(const MTPstring &_country, MTPint _this_dc, MTPint _nearest_dc) { return MTPnearestDc(new MTPDnearestDc(_country, _this_dc, _nearest_dc)); @@ -23908,6 +24091,15 @@ public: inline static MTPmessages_recentStickers new_messages_recentStickers(MTPint _hash, const MTPVector &_stickers) { return MTPmessages_recentStickers(new MTPDmessages_recentStickers(_hash, _stickers)); } + inline static MTPmessages_archivedStickers new_messages_archivedStickers(MTPint _count, const MTPVector &_sets) { + return MTPmessages_archivedStickers(new MTPDmessages_archivedStickers(_count, _sets)); + } + inline static MTPmessages_stickerSetInstallResult new_messages_stickerSetInstallResultSuccess() { + return MTPmessages_stickerSetInstallResult(mtpc_messages_stickerSetInstallResultSuccess); + } + inline static MTPmessages_stickerSetInstallResult new_messages_stickerSetInstallResultArchive(const MTPVector &_sets) { + return MTPmessages_stickerSetInstallResult(new MTPDmessages_stickerSetInstallResultArchive(_sets)); + } }; } // namespace internal @@ -30246,7 +30438,7 @@ inline MTPconfig::MTPconfig() : mtpDataOwner(new MTPDconfig()) { inline uint32 MTPconfig::innerLength() const { const MTPDconfig &v(c_config()); - return v.vdate.innerLength() + v.vexpires.innerLength() + v.vtest_mode.innerLength() + v.vthis_dc.innerLength() + v.vdc_options.innerLength() + v.vchat_size_max.innerLength() + v.vmegagroup_size_max.innerLength() + v.vforwarded_count_max.innerLength() + v.vonline_update_period_ms.innerLength() + v.voffline_blur_timeout_ms.innerLength() + v.voffline_idle_timeout_ms.innerLength() + v.vonline_cloud_timeout_ms.innerLength() + v.vnotify_cloud_delay_ms.innerLength() + v.vnotify_default_delay_ms.innerLength() + v.vchat_big_size.innerLength() + v.vpush_chat_period_ms.innerLength() + v.vpush_chat_limit.innerLength() + v.vsaved_gifs_limit.innerLength() + v.vedit_time_limit.innerLength() + v.vrating_e_decay.innerLength() + v.vdisabled_features.innerLength(); + return v.vdate.innerLength() + v.vexpires.innerLength() + v.vtest_mode.innerLength() + v.vthis_dc.innerLength() + v.vdc_options.innerLength() + v.vchat_size_max.innerLength() + v.vmegagroup_size_max.innerLength() + v.vforwarded_count_max.innerLength() + v.vonline_update_period_ms.innerLength() + v.voffline_blur_timeout_ms.innerLength() + v.voffline_idle_timeout_ms.innerLength() + v.vonline_cloud_timeout_ms.innerLength() + v.vnotify_cloud_delay_ms.innerLength() + v.vnotify_default_delay_ms.innerLength() + v.vchat_big_size.innerLength() + v.vpush_chat_period_ms.innerLength() + v.vpush_chat_limit.innerLength() + v.vsaved_gifs_limit.innerLength() + v.vedit_time_limit.innerLength() + v.vrating_e_decay.innerLength() + v.vstickers_recent_limit.innerLength() + v.vdisabled_features.innerLength(); } inline mtpTypeId MTPconfig::type() const { return mtpc_config; @@ -30276,6 +30468,7 @@ inline void MTPconfig::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI v.vsaved_gifs_limit.read(from, end); v.vedit_time_limit.read(from, end); v.vrating_e_decay.read(from, end); + v.vstickers_recent_limit.read(from, end); v.vdisabled_features.read(from, end); } inline void MTPconfig::write(mtpBuffer &to) const { @@ -30300,12 +30493,13 @@ inline void MTPconfig::write(mtpBuffer &to) const { v.vsaved_gifs_limit.write(to); v.vedit_time_limit.write(to); v.vrating_e_decay.write(to); + v.vstickers_recent_limit.write(to); v.vdisabled_features.write(to); } inline MTPconfig::MTPconfig(MTPDconfig *_data) : mtpDataOwner(_data) { } -inline MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, MTPint _rating_e_decay, const MTPVector &_disabled_features) { - return MTP::internal::TypeCreator::new_config(_date, _expires, _test_mode, _this_dc, _dc_options, _chat_size_max, _megagroup_size_max, _forwarded_count_max, _online_update_period_ms, _offline_blur_timeout_ms, _offline_idle_timeout_ms, _online_cloud_timeout_ms, _notify_cloud_delay_ms, _notify_default_delay_ms, _chat_big_size, _push_chat_period_ms, _push_chat_limit, _saved_gifs_limit, _edit_time_limit, _rating_e_decay, _disabled_features); +inline MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, MTPint _rating_e_decay, MTPint _stickers_recent_limit, const MTPVector &_disabled_features) { + return MTP::internal::TypeCreator::new_config(_date, _expires, _test_mode, _this_dc, _dc_options, _chat_size_max, _megagroup_size_max, _forwarded_count_max, _online_update_period_ms, _offline_blur_timeout_ms, _offline_idle_timeout_ms, _online_cloud_timeout_ms, _notify_cloud_delay_ms, _notify_default_delay_ms, _chat_big_size, _push_chat_period_ms, _push_chat_limit, _saved_gifs_limit, _edit_time_limit, _rating_e_decay, _stickers_recent_limit, _disabled_features); } inline MTPnearestDc::MTPnearestDc() : mtpDataOwner(new MTPDnearestDc()) { @@ -35354,6 +35548,84 @@ inline MTPmessages_recentStickers MTP_messages_recentStickersNotModified() { inline MTPmessages_recentStickers MTP_messages_recentStickers(MTPint _hash, const MTPVector &_stickers) { return MTP::internal::TypeCreator::new_messages_recentStickers(_hash, _stickers); } + +inline MTPmessages_archivedStickers::MTPmessages_archivedStickers() : mtpDataOwner(new MTPDmessages_archivedStickers()) { +} + +inline uint32 MTPmessages_archivedStickers::innerLength() const { + const MTPDmessages_archivedStickers &v(c_messages_archivedStickers()); + return v.vcount.innerLength() + v.vsets.innerLength(); +} +inline mtpTypeId MTPmessages_archivedStickers::type() const { + return mtpc_messages_archivedStickers; +} +inline void MTPmessages_archivedStickers::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_messages_archivedStickers) throw mtpErrorUnexpected(cons, "MTPmessages_archivedStickers"); + + if (!data) setData(new MTPDmessages_archivedStickers()); + MTPDmessages_archivedStickers &v(_messages_archivedStickers()); + v.vcount.read(from, end); + v.vsets.read(from, end); +} +inline void MTPmessages_archivedStickers::write(mtpBuffer &to) const { + const MTPDmessages_archivedStickers &v(c_messages_archivedStickers()); + v.vcount.write(to); + v.vsets.write(to); +} +inline MTPmessages_archivedStickers::MTPmessages_archivedStickers(MTPDmessages_archivedStickers *_data) : mtpDataOwner(_data) { +} +inline MTPmessages_archivedStickers MTP_messages_archivedStickers(MTPint _count, const MTPVector &_sets) { + return MTP::internal::TypeCreator::new_messages_archivedStickers(_count, _sets); +} + +inline uint32 MTPmessages_stickerSetInstallResult::innerLength() const { + switch (_type) { + case mtpc_messages_stickerSetInstallResultArchive: { + const MTPDmessages_stickerSetInstallResultArchive &v(c_messages_stickerSetInstallResultArchive()); + return v.vsets.innerLength(); + } + } + return 0; +} +inline mtpTypeId MTPmessages_stickerSetInstallResult::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPmessages_stickerSetInstallResult::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_messages_stickerSetInstallResultSuccess: _type = cons; break; + case mtpc_messages_stickerSetInstallResultArchive: _type = cons; { + if (!data) setData(new MTPDmessages_stickerSetInstallResultArchive()); + MTPDmessages_stickerSetInstallResultArchive &v(_messages_stickerSetInstallResultArchive()); + v.vsets.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPmessages_stickerSetInstallResult"); + } +} +inline void MTPmessages_stickerSetInstallResult::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_messages_stickerSetInstallResultArchive: { + const MTPDmessages_stickerSetInstallResultArchive &v(c_messages_stickerSetInstallResultArchive()); + v.vsets.write(to); + } break; + } +} +inline MTPmessages_stickerSetInstallResult::MTPmessages_stickerSetInstallResult(mtpTypeId type) : mtpDataOwner(0), _type(type) { + switch (type) { + case mtpc_messages_stickerSetInstallResultSuccess: break; + case mtpc_messages_stickerSetInstallResultArchive: setData(new MTPDmessages_stickerSetInstallResultArchive()); break; + default: throw mtpErrorBadTypeId(type, "MTPmessages_stickerSetInstallResult"); + } +} +inline MTPmessages_stickerSetInstallResult::MTPmessages_stickerSetInstallResult(MTPDmessages_stickerSetInstallResultArchive *_data) : mtpDataOwner(_data), _type(mtpc_messages_stickerSetInstallResultArchive) { +} +inline MTPmessages_stickerSetInstallResult MTP_messages_stickerSetInstallResultSuccess() { + return MTP::internal::TypeCreator::new_messages_stickerSetInstallResultSuccess(); +} +inline MTPmessages_stickerSetInstallResult MTP_messages_stickerSetInstallResultArchive(const MTPVector &_sets) { + return MTP::internal::TypeCreator::new_messages_stickerSetInstallResultArchive(_sets); +} inline MTPDmessage::Flags mtpCastFlags(MTPDmessageService::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } inline MTPDmessage::Flags mtpCastFlags(MTPflags flags) { return mtpCastFlags(flags.v); } inline MTPDmessage::Flags mtpCastFlags(MTPDupdateShortMessage::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index cd57d76aa8..166952ee9e 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -890,13 +890,13 @@ bool StickerData::setInstalled() const { switch (set.type()) { case mtpc_inputStickerSetID: { auto it = Global::StickerSets().constFind(set.c_inputStickerSetID().vid.v); - return (it != Global::StickerSets().cend()) && !(it->flags & MTPDstickerSet::Flag::f_disabled) && (it->flags & MTPDstickerSet::Flag::f_installed); + 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(); for (auto it = Global::StickerSets().cbegin(), e = Global::StickerSets().cend(); it != e; ++it) { if (it->shortName.toLower() == name) { - return !(it->flags & MTPDstickerSet::Flag::f_disabled) && (it->flags & MTPDstickerSet::Flag::f_installed); + return !(it->flags & MTPDstickerSet::Flag::f_archived) && (it->flags & MTPDstickerSet::Flag::f_installed); } } } break; From 81850b78c74a06c4d4e37563f6b9420135ca9ea1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 21 Jul 2016 13:09:47 +0300 Subject: [PATCH 10/13] Writing installed, featured, recent and archived stickers separately. --- Telegram/SourceFiles/apiwrap.cpp | 9 +- Telegram/SourceFiles/app.cpp | 16 +- Telegram/SourceFiles/boxes/stickersetbox.cpp | 49 +- Telegram/SourceFiles/boxes/stickersetbox.h | 2 + Telegram/SourceFiles/dropdown.cpp | 16 +- Telegram/SourceFiles/historywidget.cpp | 16 +- Telegram/SourceFiles/localstorage.cpp | 526 +++++++++++-------- Telegram/SourceFiles/localstorage.h | 10 +- Telegram/SourceFiles/mainwidget.cpp | 33 +- 9 files changed, 423 insertions(+), 254 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 8d3a886c9a..9ffde78812 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -1005,7 +1005,14 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) Local::writeUserSettings(); } - Local::writeStickers(); + if (it->flags & MTPDstickerSet::Flag::f_installed) { + if (!(it->flags & MTPDstickerSet::Flag::f_archived)) { + Local::writeInstalledStickers(); + } + } + if (it->flags & MTPDstickerSet_ClientFlag::f_featured) { + Local::writeFeaturedStickers(); + } if (App::main()) emit App::main()->stickersUpdated(); } diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 0c61a589dc..f3c85d3e23 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -1734,8 +1734,20 @@ namespace { App::main()->incrementSticker(result); } if (versionChanged) { - if (result->sticker()) { - Local::writeStickers(); + if (result->sticker() && result->sticker()->set.type() == mtpc_inputStickerSetID) { + auto it = Global::StickerSets().constFind(result->sticker()->set.c_inputStickerSetID().vid.v); + if (it != Global::StickerSets().cend()) { + if (it->id == Stickers::CloudRecentSetId) { + Local::writeRecentStickers(); + } else if (it->flags & MTPDstickerSet::Flag::f_archived) { + Local::writeArchivedStickers(); + } else if (it->flags & MTPDstickerSet::Flag::f_installed) { + Local::writeInstalledStickers(); + } + if (it->flags & MTPDstickerSet_ClientFlag::f_featured) { + Local::writeFeaturedStickers(); + } + } } auto &items = App::documentItems(); auto i = items.constFind(result); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 6f863e5386..a1df6f9573 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -35,7 +35,6 @@ namespace Stickers { void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { auto &v = d.vsets.c_vector().v; - auto &sets = Global::RefStickerSets(); auto &order = Global::RefStickerSetsOrder(); Stickers::Order archived; archived.reserve(v.size()); @@ -189,7 +188,7 @@ void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &res Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); } - Local::writeStickers(); + Local::writeInstalledStickers(); emit App::main()->stickersUpdated(); emit installed(_setId); } @@ -734,8 +733,8 @@ void StickersInner::onClearRecent() { } auto &sets = Global::RefStickerSets(); - sets.remove(Stickers::CloudRecentSetId); - sets.remove(Stickers::CustomSetId); + bool removedCloud = (sets.remove(Stickers::CloudRecentSetId) != 0); + bool removedCustom = (sets.remove(Stickers::CustomSetId) != 0); auto &recent = cGetRecentStickers(); if (!recent.isEmpty()) { @@ -743,7 +742,8 @@ void StickersInner::onClearRecent() { Local::writeUserSettings(); } - Local::writeStickers(); + if (removedCustom) Local::writeInstalledStickers(); + if (removedCloud) Local::writeRecentStickers(); emit App::main()->updateStickers(); rebuild(); @@ -833,8 +833,10 @@ void StickersInner::installSet(uint64 setId) { MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()), rpcDone(&StickersInner::installDone), rpcFail(&StickersInner::installFail, setId)); + auto flags = it->flags; it->flags &= ~(MTPDstickerSet::Flag::f_archived | MTPDstickerSet_ClientFlag::f_unread); it->flags |= MTPDstickerSet::Flag::f_installed; + auto changedFlags = flags ^ it->flags; auto &order = Global::RefStickerSetsOrder(); int insertAtIndex = 0, currentIndex = order.indexOf(setId); @@ -855,14 +857,16 @@ void StickersInner::installSet(uint64 setId) { sets.erase(custom); } } - Local::writeStickers(); + Local::writeInstalledStickers(); + if (changedFlags & MTPDstickerSet_ClientFlag::f_unread) Local::writeFeaturedStickers(); emit App::main()->stickersUpdated(); } void StickersInner::installDone(const MTPmessages_StickerSetInstallResult &result) { if (result.type() == mtpc_messages_stickerSetInstallResultArchive) { Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); - Local::writeStickers(); + Local::writeInstalledStickers(); + Local::writeArchivedStickers(); emit App::main()->stickersUpdated(); } @@ -895,7 +899,7 @@ bool StickersInner::installFail(uint64 setId, const RPCError &error) { order.removeAt(currentIndex); } - Local::writeStickers(); + Local::writeInstalledStickers(); emit App::main()->stickersUpdated(); Ui::showLayer(new InformBox(lang(lng_stickers_not_found)), KeepOtherLayers); @@ -1098,7 +1102,7 @@ void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) } void StickersInner::readFeaturedDone(const MTPBool &result) { - Local::writeStickers(); + Local::writeFeaturedStickers(); emit App::main()->stickersUpdated(); } @@ -1121,13 +1125,7 @@ Stickers::Order StickersInner::getOrder() const { Stickers::Order result; result.reserve(_rows.size()); for (int32 i = 0, l = _rows.size(); i < l; ++i) { - if (_rows.at(i)->disabled) { - auto it = Global::StickerSets().constFind(_rows.at(i)->id); - if (it == Global::StickerSets().cend() || !(it->flags & MTPDstickerSet::Flag::f_official)) { - continue; - } - } - if (_rows.at(i)->recent) { + if (_rows.at(i)->disabled || _rows.at(i)->recent) { continue; } result.push_back(_rows.at(i)->id); @@ -1161,6 +1159,9 @@ StickersBox::StickersBox(Section section) : ItemListBox(st::boxScroll) , _inner(section) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) , _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) { + if (section == Section::Archived) { + Local::readArchivedStickers(); + } setup(); } @@ -1169,6 +1170,7 @@ StickersBox::StickersBox(const Stickers::Order &archivedIds) : ItemListBox(st::b , _inner(archivedIds) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) , _about(st::boxTextFont, lang(lng_stickers_packs_archived), _defaultOptions, _aboutWidth) { + Local::readArchivedStickers(); setup(); } @@ -1299,6 +1301,14 @@ void StickersBox::closePressed() { } } +StickersBox::~StickersBox() { + if (_section == Section::Featured) { + Local::writeFeaturedStickers(); + } else if (_section == Section::Archived) { + Local::writeArchivedStickers(); + } +} + void StickersBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); _inner->resize(width(), _inner->height()); @@ -1387,7 +1397,9 @@ void StickersBox::onSave() { // Clear all installed flags, set only for sets from order. for (auto &set : sets) { - set.flags &= ~MTPDstickerSet::Flag::f_installed; + if (!(set.flags & MTPDstickerSet::Flag::f_archived)) { + set.flags &= ~MTPDstickerSet::Flag::f_installed; + } } auto &order(Global::RefStickerSetsOrder()); @@ -1407,6 +1419,7 @@ void StickersBox::onSave() { for (auto it = sets.begin(); it != sets.cend();) { if ((it->flags & MTPDstickerSet_ClientFlag::f_featured) || (it->flags & MTPDstickerSet::Flag::f_installed) + || (it->flags & MTPDstickerSet::Flag::f_archived) || (it->flags & MTPDstickerSet_ClientFlag::f_special)) { ++it; } else { @@ -1414,7 +1427,7 @@ void StickersBox::onSave() { } } - Local::writeStickers(); + Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); emit App::main()->stickersUpdated(); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 44d60e770e..4dfc9fcb1a 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -144,6 +144,8 @@ public: void closePressed(); + ~StickersBox(); + public slots: void onStickersUpdated(); diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 6d86f12d4e..a3327c6085 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -1518,7 +1518,7 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) { if (it->stickers.isEmpty()) { sets.erase(it); } - Local::writeStickers(); + Local::writeInstalledStickers(); refresh = true; break; } @@ -3651,8 +3651,9 @@ void EmojiPan::onSwitch() { } void EmojiPan::onRemoveSet(quint64 setId) { - auto it = Global::StickerSets().constFind(setId); - if (it != Global::StickerSets().cend() && !(it->flags & MTPDstickerSet::Flag::f_official)) { + auto &sets = Global::StickerSets(); + auto it = sets.constFind(setId); + if (it != sets.cend() && !(it->flags & MTPDstickerSet::Flag::f_official)) { _removingSetId = it->id; ConfirmBox *box = new ConfirmBox(lng_stickers_remove_pack(lt_sticker_pack, it->title), lang(lng_box_remove)); connect(box, SIGNAL(confirmed()), this, SLOT(onRemoveSetSure())); @@ -3663,8 +3664,9 @@ void EmojiPan::onRemoveSet(quint64 setId) { void EmojiPan::onRemoveSetSure() { Ui::hideLayer(); - auto it = Global::RefStickerSets().find(_removingSetId); - if (it != Global::RefStickerSets().cend() && !(it->flags & MTPDstickerSet::Flag::f_official)) { + auto &sets = Global::RefStickerSets(); + auto it = sets.find(_removingSetId); + if (it != sets.cend() && !(it->flags & MTPDstickerSet::Flag::f_official)) { if (it->id && it->access) { MTP::send(MTPmessages_UninstallStickerSet(MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)))); } else if (!it->shortName.isEmpty()) { @@ -3682,12 +3684,12 @@ void EmojiPan::onRemoveSetSure() { } it->flags &= ~MTPDstickerSet::Flag::f_installed; if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { - Global::RefStickerSets().erase(it); + sets.erase(it); } int removeIndex = Global::StickerSetsOrder().indexOf(_removingSetId); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); refreshStickers(); - Local::writeStickers(); + Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); } _removingSetId = 0; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 0e2bcfacb5..59630d7fc1 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3663,7 +3663,9 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { auto &sets = Global::RefStickerSets(); QMap setsToRequest; for (auto &set : sets) { - set.flags &= ~MTPDstickerSet::Flag::f_installed; // mark for removing + if (!(set.flags & MTPDstickerSet::Flag::f_archived)) { + set.flags &= ~MTPDstickerSet::Flag::f_installed; // mark for removing + } } for_const (auto &setData, d_sets) { if (setData.type() == mtpc_stickerSet) { @@ -3682,6 +3684,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { 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) { @@ -3692,7 +3695,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { } } } - if (installed || featured || special) { + if (installed || featured || special || archived) { ++it; } else { it = sets.erase(it); @@ -3710,7 +3713,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { App::api()->requestStickerSets(); } - Local::writeStickers(); + Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); if (App::main()) emit App::main()->stickersUpdated(); @@ -3797,7 +3800,7 @@ void HistoryWidget::recentStickersGot(const MTPmessages_RecentStickers &stickers LOG(("API Error: received stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countRecentStickersHash())); } - Local::writeStickers(); + Local::writeRecentStickers(); if (App::main()) emit App::main()->stickersUpdated(); } @@ -3875,7 +3878,8 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured); bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special); - if (installed || featured || special) { + bool archived = (it->flags & MTPDstickerSet::Flag::f_archived); + if (installed || featured || special || archived) { if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { ++unreadCount; } @@ -3897,7 +3901,7 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic App::api()->requestStickerSets(); } - Local::writeStickers(); + Local::writeFeaturedStickers(); if (App::main()) emit App::main()->stickersUpdated(); } diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 6ebdbea102..c365e66067 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -479,11 +479,12 @@ namespace { lskBackground = 0x08, // no data lskUserSettings = 0x09, // no data lskRecentHashtagsAndBots = 0x0a, // no data - lskStickers = 0x0b, // no data + lskStickersOld = 0x0b, // no data lskSavedPeers = 0x0c, // no data lskReportSpamStatuses = 0x0d, // no data lskSavedGifsOld = 0x0e, // no data lskSavedGifs = 0x0f, // no data + lskStickersKeys = 0x10, // no data }; enum { @@ -571,7 +572,9 @@ namespace { uint64 _storageWebFilesSize = 0; FileKey _locationsKey = 0, _reportSpamStatusesKey = 0; - FileKey _recentStickersKeyOld = 0, _stickersKey = 0, _savedGifsKey = 0; + FileKey _recentStickersKeyOld = 0; + FileKey _installedStickersKey = 0, _featuredStickersKey = 0, _recentStickersKey = 0, _archivedStickersKey = 0; + FileKey _savedGifsKey = 0; FileKey _backgroundKey = 0; bool _backgroundWasRead = false; @@ -1724,7 +1727,9 @@ namespace { StorageMap imagesMap, stickerImagesMap, audiosMap; qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0; quint64 locationsKey = 0, reportSpamStatusesKey = 0; - quint64 recentStickersKeyOld = 0, stickersKey = 0, savedGifsKey = 0; + quint64 recentStickersKeyOld = 0; + quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, archivedStickersKey = 0; + quint64 savedGifsKey = 0; quint64 backgroundKey = 0, userSettingsKey = 0, recentHashtagsAndBotsKey = 0, savedPeersKey = 0; while (!map.stream.atEnd()) { quint32 keyType; @@ -1805,8 +1810,11 @@ namespace { case lskRecentHashtagsAndBots: { map.stream >> recentHashtagsAndBotsKey; } break; - case lskStickers: { - map.stream >> stickersKey; + case lskStickersOld: { + map.stream >> installedStickersKey; + } break; + case lskStickersKeys: { + map.stream >> installedStickersKey >> featuredStickersKey >> recentStickersKey >> archivedStickersKey; } break; case lskSavedGifsOld: { quint64 key; @@ -1841,7 +1849,10 @@ namespace { _locationsKey = locationsKey; _reportSpamStatusesKey = reportSpamStatusesKey; _recentStickersKeyOld = recentStickersKeyOld; - _stickersKey = stickersKey; + _installedStickersKey = installedStickersKey; + _featuredStickersKey = featuredStickersKey; + _recentStickersKey = recentStickersKey; + _archivedStickersKey = archivedStickersKey; _savedGifsKey = savedGifsKey; _savedPeersKey = savedPeersKey; _backgroundKey = backgroundKey; @@ -1914,7 +1925,9 @@ namespace { if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_reportSpamStatusesKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_recentStickersKeyOld) mapSize += sizeof(quint32) + sizeof(quint64); - if (_stickersKey) mapSize += sizeof(quint32) + sizeof(quint64); + if (_installedStickersKey || _featuredStickersKey || _recentStickersKey || _archivedStickersKey) { + mapSize += sizeof(quint32) + 4 * sizeof(quint64); + } if (_savedGifsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_savedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64); @@ -1960,8 +1973,9 @@ namespace { if (_recentStickersKeyOld) { mapData.stream << quint32(lskRecentStickersOld) << quint64(_recentStickersKeyOld); } - if (_stickersKey) { - mapData.stream << quint32(lskStickers) << quint64(_stickersKey); + if (_installedStickersKey || _featuredStickersKey || _recentStickersKey || _archivedStickersKey) { + mapData.stream << quint32(lskStickersKeys); + mapData.stream << quint64(_installedStickersKey) << quint64(_featuredStickersKey) << quint64(_recentStickersKey) << quint64(_archivedStickersKey); } if (_savedGifsKey) { mapData.stream << quint32(lskSavedGifs) << quint64(_savedGifsKey); @@ -2247,7 +2261,9 @@ namespace Local { _webFilesMap.clear(); _storageWebFilesSize = 0; _locationsKey = _reportSpamStatusesKey = 0; - _recentStickersKeyOld = _stickersKey = _savedGifsKey = 0; + _recentStickersKeyOld = 0; + _installedStickersKey = _featuredStickersKey = _recentStickersKey = _archivedStickersKey = 0; + _savedGifsKey = 0; _backgroundKey = _userSettingsKey = _recentHashtagsAndBotsKey = _savedPeersKey = 0; _oldMapVersion = _oldSettingsVersion = 0; _mapChanged = true; @@ -3017,26 +3033,23 @@ namespace Local { } } - void _writeStickerSet(QDataStream &stream, uint64 setId) { - auto it = Global::StickerSets().constFind(setId); - if (it == Global::StickerSets().cend()) return; - - bool notLoaded = (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded); + void _writeStickerSet(QDataStream &stream, const Stickers::Set &set) { + bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded); if (notLoaded) { - stream << quint64(it->id) << quint64(it->access) << it->title << it->shortName << qint32(-it->count) << qint32(it->hash) << qint32(it->flags); + stream << quint64(set.id) << quint64(set.access) << set.title << set.shortName << qint32(-set.count) << qint32(set.hash) << qint32(set.flags); return; } else { - if (it->stickers.isEmpty()) return; + if (set.stickers.isEmpty()) return; } - stream << quint64(it->id) << quint64(it->access) << it->title << it->shortName << qint32(it->stickers.size()) << qint32(it->hash) << qint32(it->flags); - for (StickerPack::const_iterator j = it->stickers.cbegin(), e = it->stickers.cend(); j != e; ++j) { + stream << quint64(set.id) << quint64(set.access) << set.title << set.shortName << qint32(set.stickers.size()) << qint32(set.hash) << qint32(set.flags); + for (StickerPack::const_iterator j = set.stickers.cbegin(), e = set.stickers.cend(); j != e; ++j) { Serialize::Document::writeToStream(stream, *j); } if (AppVersion > 9018) { - stream << qint32(it->emoji.size()); - for (StickersByEmojiMap::const_iterator j = it->emoji.cbegin(), e = it->emoji.cend(); j != e; ++j) { + stream << qint32(set.emoji.size()); + for (StickersByEmojiMap::const_iterator j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) { stream << emojiString(j.key()) << qint32(j->size()); for (int32 k = 0, l = j->size(); k < l; ++k) { stream << quint64(j->at(k)->id); @@ -3045,67 +3058,274 @@ namespace Local { } } - void writeStickers() { + // In generic method _writeStickerSets() we look through all the sets and call a + // callback on each set to see, if we write it, skip it or abort the whole write. + enum class StickerSetCheckResult { + Write, + Skip, + Abort, + }; + + // CheckSet is a functor on Stickers::Set, which returns a StickerSetCheckResult. + template + void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::Order &order) { if (!_working()) return; auto &sets = Global::StickerSets(); if (sets.isEmpty()) { - if (_stickersKey) { - clearKey(_stickersKey); - _stickersKey = 0; + if (stickersKey) { + clearKey(stickersKey); + stickersKey = 0; _mapChanged = true; } _writeMap(); - } else { - int32 setsCount = 0; - QByteArray hashToWrite; - quint32 size = sizeof(quint32) + Serialize::bytearraySize(hashToWrite); - for_const (auto &set, sets) { - bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded); - if (notLoaded && !(set.flags & MTPDstickerSet_ClientFlag::f_special)) { - if (!(set.flags & MTPDstickerSet::Flag::f_archived) - || (set.flags & MTPDstickerSet::Flag::f_official) - || (set.flags & MTPDstickerSet_ClientFlag::f_featured)) { // waiting to receive - return; - } - } else { - if (set.stickers.isEmpty()) continue; - } - - // id + access + title + shortName + stickersCount + hash + flags - size += sizeof(quint64) * 2 + Serialize::stringSize(set.title) + Serialize::stringSize(set.shortName) + sizeof(quint32) + sizeof(qint32) * 2; - for_const (auto &sticker, set.stickers) { - size += Serialize::Document::sizeInStream(sticker); - } - - if (AppVersion > 9018) { - size += sizeof(qint32); // emojiCount - for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) { - size += Serialize::stringSize(emojiString(j.key())) + sizeof(qint32) + (j->size() * sizeof(quint64)); - } - } - - ++setsCount; - } - size += sizeof(qint32) + (Global::StickerSetsOrder().size() * sizeof(quint64)); - size += sizeof(qint32) + (Global::FeaturedStickerSetsOrder().size() * sizeof(quint64)); - - if (!_stickersKey) { - _stickersKey = genKey(); - _mapChanged = true; - _writeMap(WriteMapFast); - } - EncryptedDescriptor data(size); - data.stream << quint32(setsCount) << hashToWrite; - for_const (auto &set, sets) { - _writeStickerSet(data.stream, set.id); - } - data.stream << Global::StickerSetsOrder(); - data.stream << Global::FeaturedStickerSetsOrder(); - - FileWriteDescriptor file(_stickersKey); - file.writeEncrypted(data); + return; } + int32 setsCount = 0; + QByteArray hashToWrite; + quint32 size = sizeof(quint32) + Serialize::bytearraySize(hashToWrite); + for_const (auto &set, sets) { + auto result = checkSet(set); + if (result == StickerSetCheckResult::Abort) { + return; + } else if (result == StickerSetCheckResult::Skip) { + continue; + } + + // id + access + title + shortName + stickersCount + hash + flags + size += sizeof(quint64) * 2 + Serialize::stringSize(set.title) + Serialize::stringSize(set.shortName) + sizeof(quint32) + sizeof(qint32) * 2; + for_const (auto &sticker, set.stickers) { + size += Serialize::Document::sizeInStream(sticker); + } + + size += sizeof(qint32); // emojiCount + for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) { + size += Serialize::stringSize(emojiString(j.key())) + sizeof(qint32) + (j->size() * sizeof(quint64)); + } + + ++setsCount; + } + if (!setsCount && order.isEmpty()) { + if (stickersKey) { + clearKey(stickersKey); + stickersKey = 0; + _mapChanged = true; + } + _writeMap(); + return; + } + size += sizeof(qint32) + (order.size() * sizeof(quint64)); + + if (!stickersKey) { + stickersKey = genKey(); + _mapChanged = true; + _writeMap(WriteMapFast); + } + EncryptedDescriptor data(size); + data.stream << quint32(setsCount) << hashToWrite; + for_const (auto &set, sets) { + auto result = checkSet(set); + if (result == StickerSetCheckResult::Abort) { + return; + } else if (result == StickerSetCheckResult::Skip) { + continue; + } + _writeStickerSet(data.stream, set); + } + data.stream << order; + + FileWriteDescriptor file(stickersKey); + file.writeEncrypted(data); + } + + void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr, MTPDstickerSet::Flags readingFlags = 0) { + FileReadDescriptor stickers; + if (!readEncryptedFile(stickers, stickersKey)) { + clearKey(stickersKey); + stickersKey = 0; + _writeMap(); + return; + } + + bool readingInstalled = (readingFlags == qFlags(MTPDstickerSet::Flag::f_installed)); + + auto &sets = Global::RefStickerSets(); + if (outOrder) outOrder->clear(); + + quint32 cnt; + QByteArray hash; + stickers.stream >> cnt >> hash; // ignore hash, it is counted + if (readingInstalled && stickers.version < 8019) { // bad data in old caches + cnt += 2; // try to read at least something + } + for (uint32 i = 0; i < cnt; ++i) { + quint64 setId = 0, setAccess = 0; + QString setTitle, setShortName; + qint32 scnt = 0; + stickers.stream >> setId >> setAccess >> setTitle >> setShortName >> scnt; + + qint32 setHash = 0, setFlags = 0; + if (stickers.version > 8033) { + stickers.stream >> setHash >> setFlags; + if (setFlags & qFlags(MTPDstickerSet_ClientFlag::f_not_loaded__old)) { + setFlags &= ~qFlags(MTPDstickerSet_ClientFlag::f_not_loaded__old); + setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_not_loaded); + } + } + if (readingInstalled && stickers.version < 9058) { + setFlags |= qFlags(MTPDstickerSet::Flag::f_installed); + } + + if (setId == Stickers::DefaultSetId) { + setTitle = lang(lng_stickers_default_set); + setFlags |= qFlags(MTPDstickerSet::Flag::f_official | MTPDstickerSet_ClientFlag::f_special); + if (readingInstalled && outOrder && stickers.version < 9058) { + outOrder->push_front(setId); + } + } else if (setId == Stickers::CustomSetId) { + setTitle = lang(lng_custom_stickers); + setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); + } else if (setId == Stickers::CloudRecentSetId) { + setTitle = lang(lng_emoji_category0); // Frequently used + setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); + } else if (setId) { + if (readingInstalled && outOrder && stickers.version < 9058) { + outOrder->push_back(setId); + } + } else { + continue; + } + + auto it = sets.find(setId); + if (it == sets.cend()) { + // We will set this flags from order lists when reading those stickers. + setFlags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_featured); + it = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))); + } + auto &set = it.value(); + + if (scnt < 0) { // disabled not loaded set + if (!set.count || set.stickers.isEmpty()) { + set.count = -scnt; + } + continue; + } + + bool fillStickers = set.stickers.isEmpty(); + if (fillStickers) { + set.stickers.reserve(scnt); + set.count = 0; + } + + Serialize::Document::StickerSetInfo info(setId, setAccess, setShortName); + OrderedSet read; + for (int32 j = 0; j < scnt; ++j) { + auto document = Serialize::Document::readStickerFromStream(stickers.version, stickers.stream, info); + if (!document || !document->sticker()) continue; + + if (read.contains(document->id)) continue; + read.insert(document->id); + + if (fillStickers) { + set.stickers.push_back(document); + ++set.count; + } + } + + if (stickers.version > 9018) { + qint32 emojiCount; + stickers.stream >> emojiCount; + for (int32 j = 0; j < emojiCount; ++j) { + QString emojiString; + qint32 stickersCount; + stickers.stream >> emojiString >> stickersCount; + StickerPack pack; + pack.reserve(stickersCount); + for (int32 k = 0; k < stickersCount; ++k) { + quint64 id; + stickers.stream >> id; + DocumentData *doc = App::document(id); + if (!doc || !doc->sticker()) continue; + + pack.push_back(doc); + } + if (fillStickers) { + if (auto e = emojiGetNoColor(emojiFromText(emojiString))) { + set.emoji.insert(e, pack); + } + } + } + } + } + + // Read orders of installed and featured stickers. + if (outOrder && stickers.version >= 9058) { + stickers.stream >> *outOrder; + } + + // Set flags that we dropped above from the order. + if (readingFlags && outOrder) { + for_const (auto setId, *outOrder) { + auto it = sets.find(setId); + if (it != sets.cend()) { + it->flags |= readingFlags; + } + } + } + } + + void writeInstalledStickers() { + _writeStickerSets(_installedStickersKey, [](const Stickers::Set &set) { + if (set.id == Stickers::CloudRecentSetId) { // separate file for recent + return StickerSetCheckResult::Skip; + } else if (set.flags & MTPDstickerSet_ClientFlag::f_special) { + if (set.stickers.isEmpty()) { // all other special are "installed" + return StickerSetCheckResult::Skip; + } + } else if (!(set.flags & MTPDstickerSet::Flag::f_installed) || (set.flags & MTPDstickerSet::Flag::f_archived)) { + return StickerSetCheckResult::Skip; + } else if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) { // waiting to receive + return StickerSetCheckResult::Abort; + } else if (set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, Global::StickerSetsOrder()); + } + + void writeFeaturedStickers() { + _writeStickerSets(_featuredStickersKey, [](const Stickers::Set &set) { + if (set.id == Stickers::CloudRecentSetId) { // separate file for recent + return StickerSetCheckResult::Skip; + } else if (set.flags & MTPDstickerSet_ClientFlag::f_special) { + return StickerSetCheckResult::Skip; + } else if (!(set.flags & MTPDstickerSet_ClientFlag::f_featured)) { + return StickerSetCheckResult::Skip; + } else if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) { // waiting to receive + return StickerSetCheckResult::Abort; + } else if (set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, Global::FeaturedStickerSetsOrder()); + } + + void writeRecentStickers() { + _writeStickerSets(_recentStickersKey, [](const Stickers::Set &set) { + if (set.id != Stickers::CloudRecentSetId || set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, Stickers::Order()); + } + + void writeArchivedStickers() { + _writeStickerSets(_archivedStickersKey, [](const Stickers::Set &set) { + if (!(set.flags & MTPDstickerSet::Flag::f_archived) || set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, Stickers::Order()); } void importOldRecentStickers() { @@ -3176,7 +3396,7 @@ namespace Local { } if (custom.stickers.isEmpty()) sets.remove(Stickers::CustomSetId); - writeStickers(); + writeInstalledStickers(); writeUserSettings(); clearKey(_recentStickersKeyOld); @@ -3184,145 +3404,41 @@ namespace Local { _writeMap(); } - void readStickers() { - if (!_stickersKey) { + void readInstalledStickers() { + if (!_installedStickersKey) { return importOldRecentStickers(); } - FileReadDescriptor stickers; - if (!readEncryptedFile(stickers, _stickersKey)) { - clearKey(_stickersKey); - _stickersKey = 0; - _writeMap(); - return; - } + Global::RefStickerSets().clear(); + _readStickerSets(_installedStickersKey, &Global::RefStickerSetsOrder(), qFlags(MTPDstickerSet::Flag::f_installed)); + } - auto &sets = Global::RefStickerSets(); - sets.clear(); + void readFeaturedStickers() { + _readStickerSets(_featuredStickersKey, &Global::RefFeaturedStickerSetsOrder(), qFlags(MTPDstickerSet_ClientFlag::f_featured)); - auto &order = Global::RefStickerSetsOrder(); - order.clear(); - - auto &featuredOrder = Global::RefFeaturedStickerSetsOrder(); - featuredOrder.clear(); - - quint32 cnt; - QByteArray hash; - stickers.stream >> cnt >> hash; // ignore hash, it is counted - if (stickers.version < 8019) { // bad data in old caches - cnt += 2; // try to read at least something - } - for (uint32 i = 0; i < cnt; ++i) { - quint64 setId = 0, setAccess = 0; - QString setTitle, setShortName; - qint32 scnt = 0; - stickers.stream >> setId >> setAccess >> setTitle >> setShortName >> scnt; - - qint32 setHash = 0, setFlags = 0; - if (stickers.version > 8033) { - stickers.stream >> setHash >> setFlags; - if (setFlags & qFlags(MTPDstickerSet_ClientFlag::f_not_loaded__old)) { - setFlags &= ~qFlags(MTPDstickerSet_ClientFlag::f_not_loaded__old); - setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_not_loaded); - } - } - if (stickers.version < 9058) { - setFlags |= qFlags(MTPDstickerSet::Flag::f_installed); - } - - if (setId == Stickers::DefaultSetId) { - setTitle = lang(lng_stickers_default_set); - setFlags |= qFlags(MTPDstickerSet::Flag::f_official | MTPDstickerSet_ClientFlag::f_special); - if (stickers.version < 9058) { - order.push_front(setId); - } - } else if (setId == Stickers::CustomSetId) { - setTitle = lang(lng_custom_stickers); - setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); - } else if (setId == Stickers::CloudRecentSetId) { - setTitle = lang(lng_emoji_category0); // Frequently used - setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); - } else if (setId) { - if (stickers.version < 9058) { - order.push_back(setId); - } - } else { - continue; - } - - auto &set = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))).value(); - // We will set this flags from order lists below. - set.flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_featured); - if (scnt < 0) { // disabled not loaded set - set.count = -scnt; - continue; - } - - set.stickers.reserve(scnt); - - Serialize::Document::StickerSetInfo info(setId, setAccess, setShortName); - OrderedSet read; - for (int32 j = 0; j < scnt; ++j) { - auto document = Serialize::Document::readStickerFromStream(stickers.version, stickers.stream, info); - if (!document || !document->sticker()) continue; - - if (read.contains(document->id)) continue; - read.insert(document->id); - - set.stickers.push_back(document); - ++set.count; - } - - if (stickers.version > 9018) { - qint32 emojiCount; - stickers.stream >> emojiCount; - for (int32 j = 0; j < emojiCount; ++j) { - QString emojiString; - qint32 stickersCount; - stickers.stream >> emojiString >> stickersCount; - StickerPack pack; - pack.reserve(stickersCount); - for (int32 k = 0; k < stickersCount; ++k) { - quint64 id; - stickers.stream >> id; - DocumentData *doc = App::document(id); - if (!doc || !doc->sticker()) continue; - - pack.push_back(doc); - } - if (EmojiPtr e = emojiGetNoColor(emojiFromText(emojiString))) { - set.emoji.insert(e, pack); - } - } - } - } - - // Read orders of installed and featured stickers. - if (stickers.version >= 9058) { - stickers.stream >> order; - stickers.stream >> featuredOrder; - } - - // Set flags and count unread featured sets. - for_const (auto setId, order) { - auto it = sets.find(setId); - if (it != sets.cend()) { - it->flags |= MTPDstickerSet::Flag::f_installed; - } - } + auto &sets = Global::StickerSets(); int unreadCount = 0; - for_const (auto setId, featuredOrder) { - auto it = sets.find(setId); - if (it != sets.cend()) { - it->flags |= MTPDstickerSet_ClientFlag::f_featured; - if (it->flags & MTPDstickerSet_ClientFlag::f_unread) { - ++unreadCount; - } + for_const (auto setId, Global::FeaturedStickerSetsOrder()) { + auto it = sets.constFind(setId); + if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { + ++unreadCount; } } Global::SetFeaturedStickerSetsUnreadCount(unreadCount); } + void readRecentStickers() { + _readStickerSets(_recentStickersKey); + } + + void readArchivedStickers() { + static bool archivedStickersRead = false; + if (!archivedStickersRead) { + _readStickerSets(_archivedStickersKey); + archivedStickersRead = true; + } + } + int32 countStickersHash(bool checkOfficial) { uint32 acc = 0; bool foundOfficial = false, foundBad = false;; @@ -3941,8 +4057,8 @@ namespace Local { _recentStickersKeyOld = 0; _mapChanged = true; } - if (_stickersKey) { - _stickersKey = 0; + if (_installedStickersKey || _featuredStickersKey || _recentStickersKey || _archivedStickersKey) { + _installedStickersKey = _featuredStickersKey = _recentStickersKey = _archivedStickersKey = 0; _mapChanged = true; } if (_recentHashtagsAndBotsKey) { diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index a4909037d0..786a108508 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -153,8 +153,14 @@ namespace Local { void cancelTask(TaskId id); - void writeStickers(); - void readStickers(); + void writeInstalledStickers(); + void writeFeaturedStickers(); + void writeRecentStickers(); + void writeArchivedStickers(); + void readInstalledStickers(); + void readFeaturedStickers(); + void readRecentStickers(); + void readArchivedStickers(); int32 countStickersHash(bool checkOfficial = false); int32 countRecentStickersHash(); int32 countFeaturedStickersHash(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 9c5c00f3dc..44d597b819 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3298,7 +3298,9 @@ void MainWidget::start(const MTPUser &user) { } _started = true; App::wnd()->sendServiceHistoryRequest(); - Local::readStickers(); + Local::readInstalledStickers(); + Local::readFeaturedStickers(); + Local::readRecentStickers(); Local::readSavedGifs(); _history->start(); } @@ -3676,7 +3678,7 @@ void MainWidget::incrementSticker(DocumentData *sticker) { if (!sticker || !sticker->sticker()) return; if (sticker->sticker()->set.type() == mtpc_inputStickerSetEmpty) return; - bool writeStickers = false; + bool writeRecentStickers = false; auto &sets = Global::RefStickerSets(); auto it = sets.find(Stickers::CloudRecentSetId); if (it == sets.cend()) { @@ -3692,29 +3694,30 @@ void MainWidget::incrementSticker(DocumentData *sticker) { } if (index) { it->stickers.push_front(sticker); - writeStickers = true; + writeRecentStickers = true; } // Remove that sticker from old recent, now it is in cloud recent stickers. - bool writeRecent = false; + bool writeOldRecent = false; auto &recent = cGetRecentStickers(); for (auto i = recent.begin(), e = recent.end(); i != e; ++i) { if (i->first == sticker) { - writeRecent = true; + writeOldRecent = true; recent.erase(i); break; } } while (!recent.isEmpty() && it->stickers.size() + recent.size() > Global::StickersRecentLimit()) { - writeRecent = true; + writeOldRecent = true; recent.pop_back(); } - if (writeRecent) { + if (writeOldRecent) { Local::writeUserSettings(); } // 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()) { int removeIndex = custom->stickers.indexOf(sticker); @@ -3723,12 +3726,15 @@ void MainWidget::incrementSticker(DocumentData *sticker) { if (custom->stickers.isEmpty()) { sets.erase(custom); } - writeStickers = true; + writeInstalledStickers = true; } } - if (writeStickers) { - Local::writeStickers(); + if (writeInstalledStickers) { + Local::writeInstalledStickers(); + } + if (writeRecentStickers) { + Local::writeRecentStickers(); } _history->updateRecentStickers(); } @@ -4673,6 +4679,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { it = sets.insert(s.vid.v, Stickers::Set(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v | MTPDstickerSet::Flag::f_installed)); } else { it->flags |= MTPDstickerSet::Flag::f_installed; + it->flags &= ~MTPDstickerSet::Flag::f_archived; } const auto &v(set.vdocuments.c_vector().v); @@ -4722,7 +4729,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { sets.erase(custom); } } - Local::writeStickers(); + Local::writeInstalledStickers(); emit stickersUpdated(); } } @@ -4744,7 +4751,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { App::main()->updateStickers(); } else { Global::SetStickerSetsOrder(result); - Local::writeStickers(); + Local::writeInstalledStickers(); emit stickersUpdated(); } } break; @@ -4767,7 +4774,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } if (Global::FeaturedStickerSetsUnreadCount()) { Global::SetFeaturedStickerSetsUnreadCount(0); - Local::writeStickers(); + Local::writeFeaturedStickers(); emit stickersUpdated(); } } break; From faad13d07e5c6542b4e172ccba91d612e02ff6fe Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 21 Jul 2016 16:57:31 +0300 Subject: [PATCH 11/13] Showing archived stickers button, archived stickers box with loading. --- Telegram/Resources/langs/lang.strings | 2 +- Telegram/SourceFiles/app.cpp | 1 + Telegram/SourceFiles/boxes/stickersetbox.cpp | 412 +++++++++++++++---- Telegram/SourceFiles/boxes/stickersetbox.h | 28 +- Telegram/SourceFiles/facades.cpp | 16 + Telegram/SourceFiles/facades.h | 1 + Telegram/SourceFiles/historywidget.cpp | 2 +- Telegram/SourceFiles/localstorage.cpp | 20 +- Telegram/SourceFiles/localstorage.h | 2 +- Telegram/SourceFiles/mainwidget.cpp | 21 +- 10 files changed, 395 insertions(+), 110 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index bfbde65f1b..43c72f429c 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -683,7 +683,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_stickers_share_pack" = "Share Stickers"; "lng_stickers_not_found" = "Sticker pack not found."; "lng_stickers_packs_archived" = "Some of your unused stickers have been archived to make room for the sets you've activated."; -"lng_stickers_archived" = "Archived stickers"; +"lng_stickers_archived" = "Archived Stickers"; "lng_stickers_copied" = "Sticker pack link copied to clipboard."; "lng_stickers_default_set" = "Great Minds"; "lng_stickers_you_have" = "Manage and reorder sticker packs"; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index f3c85d3e23..f8320b6230 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2028,6 +2028,7 @@ namespace { Global::SetFeaturedStickerSetsOrder(Stickers::Order()); Global::SetFeaturedStickerSetsUnreadCount(0); Global::SetLastFeaturedStickersUpdate(0); + Global::SetArchivedStickerSetsOrder(Stickers::Order()); cSetSavedGifs(SavedGifs()); cSetLastSavedGifsUpdate(0); cSetReportSpamStatuses(ReportSpamStatuses()); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index a1df6f9573..2d8d02d194 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -31,6 +31,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "dialogs/dialogs_layout.h" #include "styles/style_boxes.h" +namespace { + +constexpr int kArchivedLimitFirstRequest = 10; +constexpr int kArchivedLimitPerPage = 30; + +} // namespace + namespace Stickers { void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { @@ -58,6 +65,7 @@ void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { } App::api()->requestStickerSets(); } + Local::writeArchivedStickers(); Ui::showLayer(new StickersBox(archived), KeepOtherLayers); } @@ -153,6 +161,13 @@ bool StickerSetInner::failedSet(const RPCError &error) { void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &result) { auto &sets = Global::RefStickerSets(); + bool wasArchived = (_setFlags & MTPDstickerSet::Flag::f_archived); + if (wasArchived) { + auto index = Global::RefArchivedStickerSetsOrder().indexOf(_setId); + if (index >= 0) { + Global::RefArchivedStickerSetsOrder().removeAt(index); + } + } _setFlags &= ~MTPDstickerSet::Flag::f_archived; _setFlags |= MTPDstickerSet::Flag::f_installed; auto it = sets.find(_setId); @@ -186,6 +201,8 @@ void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &res if (result.type() == mtpc_messages_stickerSetInstallResultArchive) { Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); + } else if (wasArchived) { + Local::writeArchivedStickers(); } Local::writeInstalledStickers(); @@ -483,24 +500,22 @@ void StickersInner::setup() { setMouseTracking(true); } -void StickersInner::paintFeaturedButton(Painter &p) const { - if (!_featuredHeight) return; - - if (_selected == -1) { - p.fillRect(0, st::membersPadding.top(), width(), _featuredHeight, st::contactsBgOver); +void StickersInner::paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const { + if (selected) { + p.fillRect(0, y, width(), _buttonHeight, st::contactsBgOver); } p.setFont(st::stickersFeaturedFont); p.setPen(st::stickersFeaturedPen); - p.drawTextLeft(st::stickersFeaturedPosition.x(), st::membersPadding.top() + st::stickersFeaturedPosition.y(), width(), lang(lng_stickers_featured)); + p.drawTextLeft(st::stickersFeaturedPosition.x(), y + st::stickersFeaturedPosition.y(), width(), text); - if (auto unread = Global::FeaturedStickerSetsUnreadCount()) { + if (badgeCounter) { Dialogs::Layout::UnreadBadgeStyle unreadSt; unreadSt.sizeId = Dialogs::Layout::UnreadBadgeInStickersBox; unreadSt.size = st::stickersFeaturedBadgeSize; int unreadRight = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x()); if (rtl()) unreadRight = width() - unreadRight; - int unreadTop = st::membersPadding.top() + (_featuredHeight - st::stickersFeaturedBadgeSize) / 2; - Dialogs::Layout::paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, unreadSt); + int unreadTop = y + (_buttonHeight - st::stickersFeaturedBadgeSize) / 2; + Dialogs::Layout::paintUnreadCount(p, QString::number(badgeCounter), unreadRight, unreadTop, unreadSt); } } @@ -513,12 +528,22 @@ void StickersInner::paintEvent(QPaintEvent *e) { p.fillRect(r, st::white); p.setClipRect(r); - paintFeaturedButton(p); + int y = st::membersPadding.top(); + if (_hasFeaturedButton) { + auto selected = (_selected == -2); + paintButton(p, y, selected, lang(lng_stickers_featured), Global::FeaturedStickerSetsUnreadCount()); + y += _buttonHeight; + } + if (_hasArchivedButton) { + auto selected = (_selected == -1); + paintButton(p, y, selected, lang(lng_stickers_archived), 0); + y += _buttonHeight; + } if (_rows.isEmpty()) { p.setFont(st::noContactsFont); p.setPen(st::noContactsColor); - p.drawText(QRect(0, _featuredHeight, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); + p.drawText(QRect(0, y, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); } else { p.translate(0, _itemsTop); @@ -708,13 +733,15 @@ void StickersInner::onUpdateSelected() { QRect add(myrtlrect(addx, addy, addw, st::stickersAddSize.height())); actionSel = add.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1; } - } else if (_featuredHeight && QRect(0, st::membersPadding.top(), width(), _featuredHeight).contains(local)) { + } else if (_hasFeaturedButton && QRect(0, st::membersPadding.top(), width(), _buttonHeight).contains(local)) { + selected = -2; + } else if (_hasArchivedButton && QRect(0, st::membersPadding.top() + (_hasFeaturedButton ? _buttonHeight : 0), width(), _buttonHeight).contains(local)) { selected = -1; } else { - selected = -2; + selected = -3; } if (_selected != selected) { - if ((_selected == -1) != (selected == -1)) { + if (((_selected == -1) != (selected == -1)) || ((_selected == -2) != (selected == -2))) { update(); } if (_section != Section::Installed && ((_selected >= 0 || _pressed >= 0) != (selected >= 0 || _pressed >= 0))) { @@ -800,14 +827,17 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) { _dragging = _started = -1; } else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) { - if (_selected == -1) { - _selected = -2; + if (_selected == -2) { + _selected = -3; Ui::showLayer(new StickersBox(Section::Featured), KeepOtherLayers); + } else if (_selected == -1) { + _selected = -3; + Ui::showLayer(new StickersBox(Section::Archived), KeepOtherLayers); } else if (_selected >= 0 && _section != Section::Installed) { auto &sets = Global::RefStickerSets(); auto it = sets.find(_rows.at(pressed)->id); if (it != sets.cend()) { - _selected = -2; + _selected = -3; Ui::showLayer(new StickerSetBox(Stickers::inputSetId(*it)), KeepOtherLayers); } } @@ -859,6 +889,13 @@ void StickersInner::installSet(uint64 setId) { } Local::writeInstalledStickers(); if (changedFlags & MTPDstickerSet_ClientFlag::f_unread) Local::writeFeaturedStickers(); + if (changedFlags & MTPDstickerSet::Flag::f_archived) { + auto index = Global::RefArchivedStickerSetsOrder().indexOf(setId); + if (index >= 0) { + Global::RefArchivedStickerSetsOrder().removeAt(index); + Local::writeArchivedStickers(); + } + } emit App::main()->stickersUpdated(); } @@ -960,8 +997,8 @@ void StickersInner::clear() { _aboveShadowFadeOpacity = anim::fvalue(0, 0); _a_shifting.stop(); _above = _dragging = _started = -1; - _selected = -2; - _pressed = -2; + _selected = -3; + _pressed = -3; _actionDown = -1; setActionSel(-1); update(); @@ -979,22 +1016,24 @@ void StickersInner::setActionSel(int32 actionSel) { } void StickersInner::rebuild() { - QList rows, rowsDisabled; - + _hasFeaturedButton = _hasArchivedButton = false; _itemsTop = st::membersPadding.top(); - _featuredHeight = 0; - if (_section == Section::Installed && !Global::FeaturedStickerSetsOrder().isEmpty()) { - _featuredHeight = st::stickersFeaturedHeight; - _itemsTop += _featuredHeight + st::membersPadding.top(); + _buttonHeight = st::stickersFeaturedHeight; + if (_section == Section::Installed) { + if (!Global::FeaturedStickerSetsOrder().isEmpty()) { + _itemsTop += _buttonHeight; + _hasFeaturedButton = true; + } + if (!Global::ArchivedStickerSetsOrder().isEmpty()) { + _itemsTop += _buttonHeight; + _hasArchivedButton = true; + } + if (_itemsTop > st::membersPadding.top()) { + _itemsTop += st::membersPadding.top(); + } } - int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); - int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); - if (_section == Section::Installed) { - namew -= qMax(qMax(qMax(_returnWidth, _removeWidth), _restoreWidth), _clearWidth); - } else { - namew -= _addWidth - st::defaultActiveButton.width; - } + int maxNameWidth = countMaxNameWidth(); clear(); auto &order = ([this]() { @@ -1002,6 +1041,8 @@ void StickersInner::rebuild() { return Global::StickerSetsOrder(); } else if (_section == Section::Featured) { return Global::FeaturedStickerSetsOrder(); + } else if (_section == Section::Archived) { + return Global::ArchivedStickerSetsOrder(); } return _archivedIds; })(); @@ -1012,7 +1053,7 @@ void StickersInner::rebuild() { if (_section == Section::Installed) { auto cloudIt = sets.constFind(Stickers::CloudRecentSetId); if (cloudIt != sets.cend() && !cloudIt->stickers.isEmpty()) { - rebuildAppendSet(cloudIt.value(), namew); + rebuildAppendSet(cloudIt.value(), maxNameWidth); } } for_const (auto setId, order) { @@ -1021,14 +1062,14 @@ void StickersInner::rebuild() { continue; } - rebuildAppendSet(it.value(), namew); + rebuildAppendSet(it.value(), maxNameWidth); if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { App::api()->scheduleStickerSetRequest(it->id, it->access); } } App::api()->requestStickerSets(); - resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom()); + updateSize(); if (_section == Section::Featured && Global::FeaturedStickerSetsUnreadCount()) { Global::SetFeaturedStickerSetsUnreadCount(0); @@ -1039,52 +1080,106 @@ void StickersInner::rebuild() { } } -void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) { - bool recent = (set.id == Stickers::CloudRecentSetId); - bool installed = true; - bool official = true; - bool unread = false; - bool disabled = false; - if (!recent) { - installed = (set.flags & MTPDstickerSet::Flag::f_installed); - official = (set.flags & MTPDstickerSet::Flag::f_official); - disabled = (set.flags & MTPDstickerSet::Flag::f_archived); - if (_section == Section::Featured) { - unread = _unreadSets.contains(set.id); - if (!unread && (set.flags & MTPDstickerSet_ClientFlag::f_unread)) { - unread = true; - _unreadSets.insert(set.id); +void StickersInner::updateSize() { + resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom()); +} + +void StickersInner::updateRows() { + int maxNameWidth = countMaxNameWidth(); + auto &sets = Global::StickerSets(); + for_const (auto row, _rows) { + auto it = sets.constFind(row->id); + if (it != sets.cend()) { + auto &set = it.value(); + if (!row->sticker) { + DocumentData *sticker = nullptr; + int pixw = 0, pixh = 0; + fillSetCover(set, &sticker, &pixw, &pixh); + if (sticker) { + row->sticker = sticker; + row->pixw = pixw; + row->pixh = pixh; + } } - } else if (_section == Section::Installed && disabled) { - return; + fillSetFlags(set, &row->recent, &row->installed, &row->official, &row->unread, &row->disabled); + if (_section == Section::Installed) { + row->disabled = false; + } + row->title = fillSetTitle(set, maxNameWidth); + row->count = fillSetCount(set); } } + update(); +} - auto sticker = set.stickers.at(0); - int32 pixw = 0, pixh = 0; - if (sticker) { - pixw = sticker->thumb->width(); - pixh = sticker->thumb->height(); - if (pixw > st::contactsPhotoSize) { - if (pixw > pixh) { - pixh = (pixh * st::contactsPhotoSize) / pixw; - pixw = st::contactsPhotoSize; - } else { - pixw = (pixw * st::contactsPhotoSize) / pixh; - pixh = st::contactsPhotoSize; - } - } else if (pixh > st::contactsPhotoSize) { +bool StickersInner::appendSet(const Stickers::Set &set) { + for_const (auto row, _rows) { + if (row->id == set.id) { + return false; + } + } + rebuildAppendSet(set, countMaxNameWidth()); + return true; +} + +int StickersInner::countMaxNameWidth() const { + int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); + int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); + if (_section == Section::Installed) { + namew -= qMax(qMax(qMax(_returnWidth, _removeWidth), _restoreWidth), _clearWidth); + } else { + namew -= _addWidth - st::defaultActiveButton.width; + } + return namew; +} + +void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) { + bool recent = false, installed = false, official = false, unread = false, disabled = false; + fillSetFlags(set, &recent, &installed, &official, &unread, &disabled); + if (_section == Section::Installed && disabled) { + return; + } + + DocumentData *sticker = nullptr; + int pixw = 0, pixh = 0; + fillSetCover(set, &sticker, &pixw, &pixh); + + QString title = fillSetTitle(set, maxNameWidth); + int count = fillSetCount(set); + + _rows.push_back(new StickerSetRow(set.id, sticker, count, title, installed, official, unread, disabled, recent, pixw, pixh)); + _animStartTimes.push_back(0); +} + +void StickersInner::fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const { + if (set.stickers.isEmpty()) { + *outSticker = nullptr; + *outWidth = *outHeight = 0; + return; + } + auto sticker = *outSticker = set.stickers.front(); + + auto pixw = sticker->thumb->width(); + auto pixh = sticker->thumb->height(); + if (pixw > st::contactsPhotoSize) { + if (pixw > pixh) { + pixh = (pixh * st::contactsPhotoSize) / pixw; + pixw = st::contactsPhotoSize; + } else { pixw = (pixw * st::contactsPhotoSize) / pixh; pixh = st::contactsPhotoSize; } + } else if (pixh > st::contactsPhotoSize) { + pixw = (pixw * st::contactsPhotoSize) / pixh; + pixh = st::contactsPhotoSize; } - QString title = set.title; - int32 titleWidth = st::contactsNameFont->width(title); - if (titleWidth > maxNameWidth) { - title = st::contactsNameFont->elided(title, maxNameWidth); - } - int count = set.stickers.size(), added = 0; - if (recent) { + *outWidth = pixw; + *outHeight = pixh; +} + +int StickersInner::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 = Global::StickerSets().constFind(Stickers::CustomSetId); if (customIt != Global::StickerSets().cend()) { added = customIt->stickers.size(); @@ -1097,8 +1192,36 @@ void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) added = cGetRecentStickers().size(); } } - _rows.push_back(new StickerSetRow(set.id, sticker, count + added, title, installed, official, unread, disabled, recent, pixw, pixh)); - _animStartTimes.push_back(0); + return result + added; +} + +QString StickersInner::fillSetTitle(const Stickers::Set &set, int maxNameWidth) const { + auto result = set.title; + int32 titleWidth = st::contactsNameFont->width(result); + if (titleWidth > maxNameWidth) { + result = st::contactsNameFont->elided(result, maxNameWidth); + } + return result; +} + +void StickersInner::fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled) { + *outRecent = (set.id == Stickers::CloudRecentSetId); + *outInstalled = true; + *outOfficial = true; + *outUnread = false; + *outDisabled = false; + if (!*outRecent) { + *outInstalled = (set.flags & MTPDstickerSet::Flag::f_installed); + *outOfficial = (set.flags & MTPDstickerSet::Flag::f_official); + *outDisabled = (set.flags & MTPDstickerSet::Flag::f_archived); + if (_section == Section::Featured) { + *outUnread = _unreadSets.contains(set.id); + if (!*outUnread && (set.flags & MTPDstickerSet_ClientFlag::f_unread)) { + *outUnread = true; + _unreadSets.insert(set.id); + } + } + } } void StickersInner::readFeaturedDone(const MTPBool &result) { @@ -1158,10 +1281,7 @@ StickersBox::StickersBox(Section section) : ItemListBox(st::boxScroll) , _section(section) , _inner(section) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) -, _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) { - if (section == Section::Archived) { - Local::readArchivedStickers(); - } +, _about(st::boxTextFont, lang((section == Section::Archived) ? lng_stickers_packs_archived : lng_stickers_reorder), _defaultOptions, _aboutWidth) { setup(); } @@ -1170,11 +1290,87 @@ StickersBox::StickersBox(const Stickers::Order &archivedIds) : ItemListBox(st::b , _inner(archivedIds) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) , _about(st::boxTextFont, lang(lng_stickers_packs_archived), _defaultOptions, _aboutWidth) { - Local::readArchivedStickers(); setup(); } +void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result) { + _archivedRequestId = 0; + if (result.type() != mtpc_messages_archivedStickers) { + return; + } + + auto &stickers = result.c_messages_archivedStickers(); + auto &archived = Global::RefArchivedStickerSetsOrder(); + if (offsetId) { + auto index = archived.indexOf(offsetId); + if (index >= 0) { + archived = archived.mid(0, index + 1); + } + } else { + archived.clear(); + } + + bool addedSet = false; + auto &v = stickers.vsets.c_vector().v; + for_const (auto &stickerSet, v) { + if (stickerSet.type() != mtpc_stickerSet) continue; + + if (auto set = Stickers::feedSet(stickerSet.c_stickerSet())) { + auto index = archived.indexOf(set->id); + if (index != archived.size() - 1) { + if (index < archived.size() - 1) { + archived.removeAt(index); + } + archived.push_back(set->id); + } + if (_section == Section::Archived) { + if (_inner->appendSet(*set)) { + addedSet = true; + if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + App::api()->scheduleStickerSetRequest(set->id, set->access); + } + } + } + } + } + if (_section == Section::Installed && !archived.isEmpty()) { + Local::writeArchivedStickers(); + rebuildList(); + } else if (_section == Section::Archived) { + if (addedSet) { + _inner->updateSize(); + setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); + _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); + App::api()->requestStickerSets(); + } else { + _allArchivedLoaded = v.isEmpty() || (offsetId != 0); + } + } + checkLoadMoreArchived(); +} + void StickersBox::setup() { + if (_section == Section::Installed) { + Local::readArchivedStickers(); + if (Global::ArchivedStickerSetsOrder().isEmpty()) { + _archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_long(0), MTP_int(kArchivedLimitFirstRequest)), rpcDone(&StickersBox::getArchivedDone, 0ULL)); + } + } else if (_section == Section::Archived) { + // Reload the archived list. + _archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_long(0), MTP_int(kArchivedLimitFirstRequest)), rpcDone(&StickersBox::getArchivedDone, 0ULL)); + + auto &sets = Global::StickerSets(); + for_const (auto setId, Global::ArchivedStickerSetsOrder()) { + auto it = sets.constFind(setId); + if (it != sets.cend()) { + if (it->stickers.isEmpty() && (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + App::api()->scheduleStickerSetRequest(setId, it->access); + } + } + } + App::api()->requestStickerSets(); + } + int bottomSkip = st::boxPadding.bottom(); if (_section == Section::Installed) { _aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom(); @@ -1194,6 +1390,9 @@ void StickersBox::setup() { _save = new BoxButton(this, lang(lng_box_ok), st::defaultBoxButton); connect(_save, SIGNAL(clicked()), this, SLOT(onClose())); + } else if (_section == Section::Archived) { + _aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom(); + _topShadow = new PlainShadow(this, st::contactsAboutShadow); } ItemListBox::init(_inner, bottomSkip, st::boxTitleHeight + _aboutHeight); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); @@ -1204,13 +1403,40 @@ void StickersBox::setup() { connect(_inner, SIGNAL(checkDraggingScroll(int)), this, SLOT(onCheckDraggingScroll(int))); connect(_inner, SIGNAL(noDraggingScroll()), this, SLOT(onNoDraggingScroll())); connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer())); + connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); _scrollTimer.setSingleShot(false); - onStickersUpdated(); + rebuildList(); prepare(); } +void StickersBox::onScroll() { + checkLoadMoreArchived(); +} + +void StickersBox::checkLoadMoreArchived() { + if (_section != Section::Archived) return; + + int scrollTop = _scroll.scrollTop(), scrollTopMax = _scroll.scrollTopMax(); + if (scrollTop + PreloadHeightsCount * _scroll.height() >= scrollTopMax) { + if (!_archivedRequestId && !_allArchivedLoaded) { + uint64 lastId = 0; + for (auto setId = Global::ArchivedStickerSetsOrder().cend(), e = Global::ArchivedStickerSetsOrder().cbegin(); setId != e;) { + --setId; + auto it = Global::StickerSets().constFind(*setId); + if (it != Global::StickerSets().cend()) { + if (it->flags & MTPDstickerSet::Flag::f_archived) { + lastId = it->id; + break; + } + } + } + _archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_long(lastId), MTP_int(kArchivedLimitPerPage)), rpcDone(&StickersBox::getArchivedDone, lastId)); + } + } +} + int32 StickersBox::countHeight() const { int bottomSkip = st::boxPadding.bottom(); if (_section == Section::Installed) { @@ -1302,9 +1528,7 @@ void StickersBox::closePressed() { } StickersBox::~StickersBox() { - if (_section == Section::Featured) { - Local::writeFeaturedStickers(); - } else if (_section == Section::Archived) { + if (_section == Section::Archived) { Local::writeArchivedStickers(); } } @@ -1326,6 +1550,14 @@ void StickersBox::resizeEvent(QResizeEvent *e) { } void StickersBox::onStickersUpdated() { + if (_section == Section::Installed || _section == Section::Featured) { + rebuildList(); + } else { + _inner->updateRows(); + } +} + +void StickersBox::rebuildList() { _inner->rebuild(); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); @@ -1360,7 +1592,7 @@ void StickersBox::onSave() { return; } - bool writeRecent = false; + bool writeRecent = false, writeArchived = false; auto &recent = cGetRecentStickers(); auto &sets = Global::RefStickerSets(); @@ -1381,6 +1613,11 @@ void StickersBox::onSave() { if (it->flags & MTPDstickerSet::Flag::f_official) { _disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolTrue()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); it->flags |= MTPDstickerSet::Flag::f_archived; + auto index = Global::RefArchivedStickerSetsOrder().indexOf(it->id); + if (index < 0) { + Global::RefArchivedStickerSetsOrder().push_front(it->id); + writeArchived = true; + } } else { _disenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); int removeIndex = Global::StickerSetsOrder().indexOf(it->id); @@ -1388,6 +1625,9 @@ void StickersBox::onSave() { if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { sets.erase(it); } else { + if (it->flags & MTPDstickerSet::Flag::f_archived) { + writeArchived = true; + } it->flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet::Flag::f_archived); } } @@ -1411,6 +1651,7 @@ void StickersBox::onSave() { MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName)); _disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolFalse()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); it->flags &= ~MTPDstickerSet::Flag::f_archived; + writeArchived = true; } order.push_back(reorder.at(i)); it->flags |= MTPDstickerSet::Flag::f_installed; @@ -1429,6 +1670,7 @@ void StickersBox::onSave() { Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); + if (writeArchived) Local::writeArchivedStickers(); emit App::main()->stickersUpdated(); if (_disenableRequests.isEmpty()) { diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 4dfc9fcb1a..42d9e23cf1 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -155,6 +155,9 @@ public slots: void onSave(); +private slots: + void onScroll(); + protected: void hideAll(); void showAll(); @@ -162,6 +165,7 @@ protected: private: void setup(); int32 countHeight() const; + void rebuildList(); void disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req); bool disenableFail(const RPCError &error, mtpRequestId req); @@ -169,6 +173,9 @@ private: bool reorderFail(const RPCError &result); void saveOrder(); + void checkLoadMoreArchived(); + void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result); + Section _section; ChildWidget _inner; @@ -186,6 +193,9 @@ private: Text _about; int _aboutHeight = 0; + mtpRequestId _archivedRequestId = 0; + bool _allArchivedLoaded = false; + }; int32 stickerPacksCount(bool includeDisabledOfficial = false); @@ -201,6 +211,9 @@ public: StickersInner(const Stickers::Order &archivedIds); void rebuild(); + void updateSize(); + void updateRows(); // refresh only pack cover stickers + bool appendSet(const Stickers::Set &set); bool savingStart() { if (_saving) return false; _saving = true; @@ -232,7 +245,7 @@ public slots: private: void setup(); - void paintFeaturedButton(Painter &p) const; + void paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const; void step_shifting(uint64 ms, bool timer); void paintRow(Painter &p, int32 index); @@ -275,6 +288,12 @@ private: using StickerSetRows = QList; void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth); + void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const; + int fillSetCount(const Stickers::Set &set) const; + QString fillSetTitle(const Stickers::Set &set, int maxNameWidth) const; + void fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled); + + int countMaxNameWidth() const; StickerSetRows _rows; QList _animStartTimes; @@ -296,12 +315,15 @@ private: QString _addText; int _addWidth; - int _featuredHeight = 0; + int _buttonHeight = 0; + bool _hasFeaturedButton = false; + bool _hasArchivedButton = false; + // Remember all the unread set ids to display unread dots. OrderedSet _unreadSets; QPoint _mouse; - int _selected = -2; // -1 - featured stickers button + int _selected = -3; // -2 - featured stickers button, -1 - archived stickers button int _pressed = -2; QPoint _dragStart; int _started = -1; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 80c4335273..783ef5afb7 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -523,6 +523,8 @@ DefineVar(Sandbox, ConnectionProxy, PreLaunchProxy); namespace Stickers { Set *feedSet(const MTPDstickerSet &set) { + MTPDstickerSet::Flags flags = 0; + auto &sets = Global::RefStickerSets(); auto it = sets.find(set.vid.v); auto title = stickerSetTitle(set); @@ -532,6 +534,7 @@ Set *feedSet(const MTPDstickerSet &set) { it->access = set.vaccess_hash.v; it->title = title; it->shortName = qs(set.vshort_name); + flags = it->flags; 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; if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) { @@ -540,6 +543,17 @@ Set *feedSet(const MTPDstickerSet &set) { it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; // need to request this set } } + auto changedFlags = (flags ^ it->flags); + if (changedFlags & MTPDstickerSet::Flag::f_archived) { + auto index = Global::ArchivedStickerSetsOrder().indexOf(it->id); + if (it->flags & MTPDstickerSet::Flag::f_archived) { + if (index < 0) { + Global::RefArchivedStickerSetsOrder().push_front(it->id); + } + } else if (index >= 0) { + Global::RefArchivedStickerSetsOrder().removeAt(index); + } + } return &it.value(); } @@ -594,6 +608,7 @@ struct Data { Stickers::Order FeaturedStickerSetsOrder; int FeaturedStickerSetsUnreadCount = 0; uint64 LastFeaturedStickersUpdate = 0; + Stickers::Order ArchivedStickerSetsOrder; MTP::DcOptions DcOptions; @@ -667,6 +682,7 @@ DefineVar(Global, uint64, LastRecentStickersUpdate); DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder); DefineVar(Global, int, FeaturedStickerSetsUnreadCount); DefineVar(Global, uint64, LastFeaturedStickersUpdate); +DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder); DefineVar(Global, MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index d99b54bb80..bd07881b2c 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -271,6 +271,7 @@ DeclareVar(uint64, LastRecentStickersUpdate); DeclareVar(Stickers::Order, FeaturedStickerSetsOrder); DeclareVar(int, FeaturedStickerSetsUnreadCount); DeclareVar(uint64, LastFeaturedStickersUpdate); +DeclareVar(Stickers::Order, ArchivedStickerSetsOrder); DeclareVar(MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 59630d7fc1..48f0cc5ceb 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3844,7 +3844,7 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic QString title = stickerSetTitle(set); if (it == sets.cend()) { auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded; - if (unread.contains(set.vid.v) || !(set.vflags.v & MTPDstickerSet::Flag::f_installed)) { + 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)); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index c365e66067..b4395b4ebb 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3325,7 +3325,7 @@ namespace Local { return StickerSetCheckResult::Skip; } return StickerSetCheckResult::Write; - }, Stickers::Order()); + }, Global::ArchivedStickerSetsOrder()); } void importOldRecentStickers() { @@ -3434,30 +3434,28 @@ namespace Local { void readArchivedStickers() { static bool archivedStickersRead = false; if (!archivedStickersRead) { - _readStickerSets(_archivedStickersKey); + _readStickerSets(_archivedStickersKey, &Global::RefArchivedStickerSetsOrder()); archivedStickersRead = true; } } - int32 countStickersHash(bool checkOfficial) { + int32 countStickersHash(bool checkOutdatedInfo) { uint32 acc = 0; - bool foundOfficial = false, foundBad = false;; + bool foundOutdated = false; auto &sets = Global::StickerSets(); auto &order = Global::StickerSetsOrder(); for (auto i = order.cbegin(), e = order.cend(); i != e; ++i) { auto j = sets.constFind(*i); if (j != sets.cend()) { - if (j->id == 0) { - foundBad = true; - } else if (j->flags & MTPDstickerSet::Flag::f_official) { - foundOfficial = true; - } - if (!(j->flags & MTPDstickerSet::Flag::f_archived)) { + if (j->id == Stickers::DefaultSetId) { + foundOutdated = true; + } else if (!(j->flags & MTPDstickerSet_ClientFlag::f_special) + && !(j->flags & MTPDstickerSet::Flag::f_archived)) { acc = (acc * 20261) + j->hash; } } } - return (!checkOfficial || (!foundBad && foundOfficial)) ? int32(acc & 0x7FFFFFFF) : 0; + return (!checkOutdatedInfo || !foundOutdated) ? int32(acc & 0x7FFFFFFF) : 0; } int32 countRecentStickersHash() { diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index 786a108508..ca59fe65b7 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -161,7 +161,7 @@ namespace Local { void readFeaturedStickers(); void readRecentStickers(); void readArchivedStickers(); - int32 countStickersHash(bool checkOfficial = false); + int32 countStickersHash(bool checkOutdatedInfo = false); int32 countRecentStickersHash(); int32 countFeaturedStickersHash(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 44d597b819..bfd5d191b0 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4667,19 +4667,23 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { ////// Cloud sticker sets case mtpc_updateNewStickerSet: { - const auto &d(update.c_updateNewStickerSet()); + auto &d = update.c_updateNewStickerSet(); + bool writeArchived = false; if (d.vstickerset.type() == mtpc_messages_stickerSet) { - const auto &set(d.vstickerset.c_messages_stickerSet()); + auto &set = d.vstickerset.c_messages_stickerSet(); if (set.vset.type() == mtpc_stickerSet) { - const auto &s(set.vset.c_stickerSet()); + auto &s = set.vset.c_stickerSet(); - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); auto it = sets.find(s.vid.v); if (it == sets.cend()) { it = sets.insert(s.vid.v, Stickers::Set(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v | MTPDstickerSet::Flag::f_installed)); } else { it->flags |= MTPDstickerSet::Flag::f_installed; - it->flags &= ~MTPDstickerSet::Flag::f_archived; + if (it->flags & MTPDstickerSet::Flag::f_archived) { + it->flags &= ~MTPDstickerSet::Flag::f_archived; + writeArchived = true; + } } const auto &v(set.vdocuments.c_vector().v); @@ -4692,12 +4696,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { it->stickers.push_back(doc); } it->emoji.clear(); - const auto &packs(set.vpacks.c_vector().v); + auto &packs = set.vpacks.c_vector().v; for (int32 i = 0, l = packs.size(); i < l; ++i) { if (packs.at(i).type() != mtpc_stickerPack) continue; - const auto &pack(packs.at(i).c_stickerPack()); + auto &pack = packs.at(i).c_stickerPack(); if (EmojiPtr e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) { - const auto &stickers(pack.vdocuments.c_vector().v); + auto &stickers = pack.vdocuments.c_vector().v; StickerPack p; p.reserve(stickers.size()); for (int32 j = 0, c = stickers.size(); j < c; ++j) { @@ -4730,6 +4734,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } Local::writeInstalledStickers(); + if (writeArchived) Local::writeArchivedStickers(); emit stickersUpdated(); } } From cd986d6f5d8a94e889459e9f828e90bdbb12bac2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 22 Jul 2016 14:59:35 +0300 Subject: [PATCH 12/13] Fixed archived stickers loading. --- Telegram/SourceFiles/boxes/stickersetbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 2d8d02d194..7891ed6343 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -1317,7 +1317,7 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti if (auto set = Stickers::feedSet(stickerSet.c_stickerSet())) { auto index = archived.indexOf(set->id); - if (index != archived.size() - 1) { + if (archived.isEmpty() || index != archived.size() - 1) { if (index < archived.size() - 1) { archived.removeAt(index); } From 02e54dd8ba0cc65bca49a0814bcd3bcf190f28b4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 22 Jul 2016 19:04:38 +0300 Subject: [PATCH 13/13] Scheme updated with covered stickers, not used yet. --- Telegram/SourceFiles/boxes/stickersetbox.cpp | 8 +- Telegram/SourceFiles/historywidget.cpp | 4 +- Telegram/SourceFiles/mtproto/scheme.tl | 14 ++- Telegram/SourceFiles/mtproto/scheme_auto.cpp | 19 ++- Telegram/SourceFiles/mtproto/scheme_auto.h | 125 +++++++++++++++---- 5 files changed, 133 insertions(+), 37 deletions(-) diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 7891ed6343..62c8c5580e 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -47,8 +47,8 @@ void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { archived.reserve(v.size()); QMap setsToRequest; for_const (auto &stickerSet, v) { - if (stickerSet.type() == mtpc_stickerSet) { - auto set = Stickers::feedSet(stickerSet.c_stickerSet()); + if (stickerSet.type() == mtpc_stickerSetCovered && stickerSet.c_stickerSetCovered().vset.type() == mtpc_stickerSet) { + auto set = Stickers::feedSet(stickerSet.c_stickerSetCovered().vset.c_stickerSet()); if (set->stickers.isEmpty()) { setsToRequest.insert(set->id, set->access); } @@ -1313,9 +1313,9 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti bool addedSet = false; auto &v = stickers.vsets.c_vector().v; for_const (auto &stickerSet, v) { - if (stickerSet.type() != mtpc_stickerSet) continue; + if (stickerSet.type() != mtpc_stickerSetCovered || stickerSet.c_stickerSetCovered().vset.type() != mtpc_stickerSet) continue; - if (auto set = Stickers::feedSet(stickerSet.c_stickerSet())) { + if (auto set = Stickers::feedSet(stickerSet.c_stickerSetCovered().vset.c_stickerSet())) { auto index = archived.indexOf(set->id); if (archived.isEmpty() || index != archived.size() - 1) { if (index < archived.size() - 1) { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 48f0cc5ceb..4f94fea9c4 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3838,8 +3838,8 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic set.flags &= ~MTPDstickerSet_ClientFlag::f_featured; // mark for removing } for (int i = 0, l = d_sets.size(); i != l; ++i) { - if (d_sets.at(i).type() == mtpc_stickerSet) { - const auto &set(d_sets.at(i).c_stickerSet()); + if (d_sets.at(i).type() == mtpc_stickerSetCovered && d_sets.at(i).c_stickerSetCovered().vset.type() == mtpc_stickerSet) { + const auto &set(d_sets.at(i).c_stickerSetCovered().vset.c_stickerSet()); auto it = sets.find(set.vid.v); QString title = stickerSetTitle(set); if (it == sets.cend()) { diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index 168945f8d5..41b8c66b59 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -672,7 +672,7 @@ auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -messages.botCallbackAnswer#31fde6e4 flags:# alert:flags.1?true message:flags.0?string url:flags.3?string = messages.BotCallbackAnswer; +messages.botCallbackAnswer#b10df1fb flags:# alert:flags.1?true message:flags.0?string url:flags.2?string = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; @@ -699,15 +699,17 @@ draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; -messages.featuredStickers#ed6392b7 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; +messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; -messages.archivedStickers#f3475c0c count:int sets:Vector = messages.ArchivedStickers; +messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#192c8a4e sets:Vector = messages.StickerSetInstallResult; +messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; + +stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; ---functions--- @@ -839,7 +841,7 @@ messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEdi messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#a6e94f04 peer:InputPeer msg_id:int data:bytes = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#70dc0fa3 flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.3?string = Bool; +messages.setBotCallbackAnswer#c927d44b flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; @@ -848,7 +850,7 @@ messages.readFeaturedStickers#e21cbb = Bool; messages.getRecentStickers#99197c2c hash:int = messages.RecentStickers; messages.saveRecentSticker#348e39bf id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#ab02e5d2 = Bool; -messages.getUnusedStickers#a978d356 limit:int = Vector; +messages.getUnusedStickers#4309d65b limit:int = Vector; messages.getArchivedStickers#906e241f offset_id:long limit:int = messages.ArchivedStickers; updates.getState#edd4882a = updates.State; diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp index 65e157812f..6213eba12f 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp +++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp @@ -5601,7 +5601,7 @@ void _serialize_messages_botCallbackAnswer(MTPStringLogger &to, int32 stage, int case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 1: to.add(" alert: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_alert) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; case 2: to.add(" message: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 3: to.add(" url: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; + case 3: to.add(" url: "); ++stages.back(); if (flag & MTPDmessages_botCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -5828,6 +5828,20 @@ void _serialize_messages_stickerSetInstallResultArchive(MTPStringLogger &to, int } } +void _serialize_stickerSetCovered(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ stickerSetCovered"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" set: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" cover: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -6406,7 +6420,7 @@ void _serialize_messages_setBotCallbackAnswer(MTPStringLogger &to, int32 stage, case 1: to.add(" alert: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_alert) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; case 2: to.add(" query_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 3: to.add(" message: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_message) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 4: to.add(" url: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break; + case 4: to.add(" url: "); ++stages.back(); if (flag & MTPmessages_setBotCallbackAnswer::Flag::f_url) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -8865,6 +8879,7 @@ namespace { _serializers.insert(mtpc_messages_archivedStickers, _serialize_messages_archivedStickers); _serializers.insert(mtpc_messages_stickerSetInstallResultSuccess, _serialize_messages_stickerSetInstallResultSuccess); _serializers.insert(mtpc_messages_stickerSetInstallResultArchive, _serialize_messages_stickerSetInstallResultArchive); + _serializers.insert(mtpc_stickerSetCovered, _serialize_stickerSetCovered); _serializers.insert(mtpc_req_pq, _serialize_req_pq); _serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params); diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h index 3ad9425ebf..e883e74ee8 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.h +++ b/Telegram/SourceFiles/mtproto/scheme_auto.h @@ -487,7 +487,7 @@ enum { mtpc_auth_sentCodeTypeSms = 0xc000bba2, mtpc_auth_sentCodeTypeCall = 0x5353e5a7, mtpc_auth_sentCodeTypeFlashCall = 0xab03c6d9, - mtpc_messages_botCallbackAnswer = 0x31fde6e4, + mtpc_messages_botCallbackAnswer = 0xb10df1fb, mtpc_messages_messageEditData = 0x26b5dde6, mtpc_inputBotInlineMessageID = 0x890c3d89, mtpc_inlineBotSwitchPM = 0x3c20629f, @@ -504,12 +504,13 @@ enum { mtpc_draftMessageEmpty = 0xba4baec5, mtpc_draftMessage = 0xfd8e711f, mtpc_messages_featuredStickersNotModified = 0x4ede3cf, - mtpc_messages_featuredStickers = 0xed6392b7, + mtpc_messages_featuredStickers = 0xf89d88e5, mtpc_messages_recentStickersNotModified = 0xb17f890, mtpc_messages_recentStickers = 0x5ce20970, - mtpc_messages_archivedStickers = 0xf3475c0c, + mtpc_messages_archivedStickers = 0x4fcba9c8, mtpc_messages_stickerSetInstallResultSuccess = 0x38641628, - mtpc_messages_stickerSetInstallResultArchive = 0x192c8a4e, + mtpc_messages_stickerSetInstallResultArchive = 0x35e410a8, + mtpc_stickerSetCovered = 0x6410a5d2, mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsgs = 0x3dc4b4f0, mtpc_initConnection = 0x69796de9, @@ -633,7 +634,7 @@ enum { mtpc_messages_editMessage = 0xce91e4ca, mtpc_messages_editInlineBotMessage = 0x130c2c85, mtpc_messages_getBotCallbackAnswer = 0xa6e94f04, - mtpc_messages_setBotCallbackAnswer = 0x70dc0fa3, + mtpc_messages_setBotCallbackAnswer = 0xc927d44b, mtpc_messages_getPeerDialogs = 0x2d9776b9, mtpc_messages_saveDraft = 0xbc39e14b, mtpc_messages_getAllDrafts = 0x6a3f8d65, @@ -642,7 +643,7 @@ enum { mtpc_messages_getRecentStickers = 0x99197c2c, mtpc_messages_saveRecentSticker = 0x348e39bf, mtpc_messages_clearRecentStickers = 0xab02e5d2, - mtpc_messages_getUnusedStickers = 0xa978d356, + mtpc_messages_getUnusedStickers = 0x4309d65b, mtpc_messages_getArchivedStickers = 0x906e241f, mtpc_updates_getState = 0xedd4882a, mtpc_updates_getDifference = 0xa041495, @@ -1381,6 +1382,9 @@ class MTPDmessages_archivedStickers; class MTPmessages_stickerSetInstallResult; class MTPDmessages_stickerSetInstallResultArchive; +class MTPstickerSetCovered; +class MTPDstickerSetCovered; + // Boxed types definitions typedef MTPBoxed MTPResPQ; @@ -1559,6 +1563,7 @@ typedef MTPBoxed MTPmessages_FeaturedStickers; typedef MTPBoxed MTPmessages_RecentStickers; typedef MTPBoxed MTPmessages_ArchivedStickers; typedef MTPBoxed MTPmessages_StickerSetInstallResult; +typedef MTPBoxed MTPStickerSetCovered; // Type classes definitions @@ -9706,6 +9711,37 @@ private: }; typedef MTPBoxed MTPmessages_StickerSetInstallResult; +class MTPstickerSetCovered : private mtpDataOwner { +public: + MTPstickerSetCovered(); + MTPstickerSetCovered(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_stickerSetCovered) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDstickerSetCovered &_stickerSetCovered() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDstickerSetCovered*)data; + } + const MTPDstickerSetCovered &c_stickerSetCovered() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDstickerSetCovered*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_stickerSetCovered); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPstickerSetCovered(MTPDstickerSetCovered *_data); + + friend class MTP::internal::TypeCreator; +}; +typedef MTPBoxed MTPStickerSetCovered; + // Type constructors with data class MTPDresPQ : public mtpDataImpl { @@ -14457,9 +14493,9 @@ public: enum class Flag : int32 { f_alert = (1 << 1), f_message = (1 << 0), - f_url = (1 << 3), + f_url = (1 << 2), - MAX_FIELD = (1 << 3), + MAX_FIELD = (1 << 2), }; Q_DECLARE_FLAGS(Flags, Flag); friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } @@ -14601,11 +14637,11 @@ class MTPDmessages_featuredStickers : public mtpDataImpl &_sets, const MTPVector &_unread) : vhash(_hash), vsets(_sets), vunread(_unread) { + MTPDmessages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) : vhash(_hash), vsets(_sets), vunread(_unread) { } MTPint vhash; - MTPVector vsets; + MTPVector vsets; MTPVector vunread; }; @@ -14624,21 +14660,32 @@ class MTPDmessages_archivedStickers : public mtpDataImpl &_sets) : vcount(_count), vsets(_sets) { + MTPDmessages_archivedStickers(MTPint _count, const MTPVector &_sets) : vcount(_count), vsets(_sets) { } MTPint vcount; - MTPVector vsets; + MTPVector vsets; }; class MTPDmessages_stickerSetInstallResultArchive : public mtpDataImpl { public: MTPDmessages_stickerSetInstallResultArchive() { } - MTPDmessages_stickerSetInstallResultArchive(const MTPVector &_sets) : vsets(_sets) { + MTPDmessages_stickerSetInstallResultArchive(const MTPVector &_sets) : vsets(_sets) { } - MTPVector vsets; + MTPVector vsets; +}; + +class MTPDstickerSetCovered : public mtpDataImpl { +public: + MTPDstickerSetCovered() { + } + MTPDstickerSetCovered(const MTPStickerSet &_set, const MTPDocument &_cover) : vset(_set), vcover(_cover) { + } + + MTPStickerSet vset; + MTPDocument vcover; }; // RPC methods @@ -20434,9 +20481,9 @@ public: enum class Flag : int32 { f_alert = (1 << 1), f_message = (1 << 0), - f_url = (1 << 3), + f_url = (1 << 2), - MAX_FIELD = (1 << 3), + MAX_FIELD = (1 << 2), }; Q_DECLARE_FLAGS(Flags, Flag); friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } @@ -20837,7 +20884,7 @@ public: vlimit.write(to); } - typedef MTPVector ResponseType; + typedef MTPVector ResponseType; }; class MTPmessages_GetUnusedStickers : public MTPBoxed { public: @@ -24082,7 +24129,7 @@ public: inline static MTPmessages_featuredStickers new_messages_featuredStickersNotModified() { return MTPmessages_featuredStickers(mtpc_messages_featuredStickersNotModified); } - inline static MTPmessages_featuredStickers new_messages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) { + inline static MTPmessages_featuredStickers new_messages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) { return MTPmessages_featuredStickers(new MTPDmessages_featuredStickers(_hash, _sets, _unread)); } inline static MTPmessages_recentStickers new_messages_recentStickersNotModified() { @@ -24091,15 +24138,18 @@ public: inline static MTPmessages_recentStickers new_messages_recentStickers(MTPint _hash, const MTPVector &_stickers) { return MTPmessages_recentStickers(new MTPDmessages_recentStickers(_hash, _stickers)); } - inline static MTPmessages_archivedStickers new_messages_archivedStickers(MTPint _count, const MTPVector &_sets) { + inline static MTPmessages_archivedStickers new_messages_archivedStickers(MTPint _count, const MTPVector &_sets) { return MTPmessages_archivedStickers(new MTPDmessages_archivedStickers(_count, _sets)); } inline static MTPmessages_stickerSetInstallResult new_messages_stickerSetInstallResultSuccess() { return MTPmessages_stickerSetInstallResult(mtpc_messages_stickerSetInstallResultSuccess); } - inline static MTPmessages_stickerSetInstallResult new_messages_stickerSetInstallResultArchive(const MTPVector &_sets) { + inline static MTPmessages_stickerSetInstallResult new_messages_stickerSetInstallResultArchive(const MTPVector &_sets) { return MTPmessages_stickerSetInstallResult(new MTPDmessages_stickerSetInstallResultArchive(_sets)); } + inline static MTPstickerSetCovered new_stickerSetCovered(const MTPStickerSet &_set, const MTPDocument &_cover) { + return MTPstickerSetCovered(new MTPDstickerSetCovered(_set, _cover)); + } }; } // namespace internal @@ -35494,7 +35544,7 @@ inline MTPmessages_featuredStickers::MTPmessages_featuredStickers(MTPDmessages_f inline MTPmessages_featuredStickers MTP_messages_featuredStickersNotModified() { return MTP::internal::TypeCreator::new_messages_featuredStickersNotModified(); } -inline MTPmessages_featuredStickers MTP_messages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) { +inline MTPmessages_featuredStickers MTP_messages_featuredStickers(MTPint _hash, const MTPVector &_sets, const MTPVector &_unread) { return MTP::internal::TypeCreator::new_messages_featuredStickers(_hash, _sets, _unread); } @@ -35574,7 +35624,7 @@ inline void MTPmessages_archivedStickers::write(mtpBuffer &to) const { } inline MTPmessages_archivedStickers::MTPmessages_archivedStickers(MTPDmessages_archivedStickers *_data) : mtpDataOwner(_data) { } -inline MTPmessages_archivedStickers MTP_messages_archivedStickers(MTPint _count, const MTPVector &_sets) { +inline MTPmessages_archivedStickers MTP_messages_archivedStickers(MTPint _count, const MTPVector &_sets) { return MTP::internal::TypeCreator::new_messages_archivedStickers(_count, _sets); } @@ -35623,9 +35673,38 @@ inline MTPmessages_stickerSetInstallResult::MTPmessages_stickerSetInstallResult( inline MTPmessages_stickerSetInstallResult MTP_messages_stickerSetInstallResultSuccess() { return MTP::internal::TypeCreator::new_messages_stickerSetInstallResultSuccess(); } -inline MTPmessages_stickerSetInstallResult MTP_messages_stickerSetInstallResultArchive(const MTPVector &_sets) { +inline MTPmessages_stickerSetInstallResult MTP_messages_stickerSetInstallResultArchive(const MTPVector &_sets) { return MTP::internal::TypeCreator::new_messages_stickerSetInstallResultArchive(_sets); } + +inline MTPstickerSetCovered::MTPstickerSetCovered() : mtpDataOwner(new MTPDstickerSetCovered()) { +} + +inline uint32 MTPstickerSetCovered::innerLength() const { + const MTPDstickerSetCovered &v(c_stickerSetCovered()); + return v.vset.innerLength() + v.vcover.innerLength(); +} +inline mtpTypeId MTPstickerSetCovered::type() const { + return mtpc_stickerSetCovered; +} +inline void MTPstickerSetCovered::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_stickerSetCovered) throw mtpErrorUnexpected(cons, "MTPstickerSetCovered"); + + if (!data) setData(new MTPDstickerSetCovered()); + MTPDstickerSetCovered &v(_stickerSetCovered()); + v.vset.read(from, end); + v.vcover.read(from, end); +} +inline void MTPstickerSetCovered::write(mtpBuffer &to) const { + const MTPDstickerSetCovered &v(c_stickerSetCovered()); + v.vset.write(to); + v.vcover.write(to); +} +inline MTPstickerSetCovered::MTPstickerSetCovered(MTPDstickerSetCovered *_data) : mtpDataOwner(_data) { +} +inline MTPstickerSetCovered MTP_stickerSetCovered(const MTPStickerSet &_set, const MTPDocument &_cover) { + return MTP::internal::TypeCreator::new_stickerSetCovered(_set, _cover); +} inline MTPDmessage::Flags mtpCastFlags(MTPDmessageService::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } inline MTPDmessage::Flags mtpCastFlags(MTPflags flags) { return mtpCastFlags(flags.v); } inline MTPDmessage::Flags mtpCastFlags(MTPDupdateShortMessage::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); }