diff --git a/Telegram/Resources/art/sprite.png b/Telegram/Resources/art/sprite.png index 809d0201a..932c1d990 100644 Binary files a/Telegram/Resources/art/sprite.png and b/Telegram/Resources/art/sprite.png differ diff --git a/Telegram/Resources/art/sprite_200x.png b/Telegram/Resources/art/sprite_200x.png index 2c1270a99..dcad41196 100644 Binary files a/Telegram/Resources/art/sprite_200x.png and b/Telegram/Resources/art/sprite_200x.png differ diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index 8516585ce..94f8555f6 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -1868,6 +1868,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 { @@ -2141,7 +2144,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 000000000..33be1af78 Binary files /dev/null and b/Telegram/Resources/icons/mediaview_save_check.png differ 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 000000000..d9d3bd85b Binary files /dev/null and b/Telegram/Resources/icons/mediaview_save_check@2x.png differ diff --git a/Telegram/Resources/icons/stickers_add.png b/Telegram/Resources/icons/stickers_add.png new file mode 100644 index 000000000..ac6c2a166 Binary files /dev/null and b/Telegram/Resources/icons/stickers_add.png differ diff --git a/Telegram/Resources/icons/stickers_add@2x.png b/Telegram/Resources/icons/stickers_add@2x.png new file mode 100644 index 000000000..de8948d66 Binary files /dev/null and b/Telegram/Resources/icons/stickers_add@2x.png differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 771cd8a25..43c72f429 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."; @@ -680,15 +682,20 @@ 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"; "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"; +"lng_stickers_add" = "Add"; "lng_stickers_count" = "{count:Loading...|# sticker|# stickers}"; "lng_in_dlg_photo" = "Photo"; diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index e4f013b17..ec047c8e2 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,60,0 - PRODUCTVERSION 0,9,60,0 + FILEVERSION 0,9,61,0 + PRODUCTVERSION 0,9,61,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.9.60.0" + VALUE "FileVersion", "0.9.61.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.60.0" + VALUE "ProductVersion", "0.9.61.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 64ed6a32d..e28d17a5b 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,60,0 - PRODUCTVERSION 0,9,60,0 + FILEVERSION 0,9,61,0 + PRODUCTVERSION 0,9,61,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.60.0" + VALUE "FileVersion", "0.9.61.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.60.0" + VALUE "ProductVersion", "0.9.61.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 08c4da448..5f5086f4f 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -923,12 +923,12 @@ 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()); - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); auto it = sets.find(setId); if (it == sets.cend()) return; @@ -936,7 +936,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_unread | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_special); + 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); @@ -1002,7 +1004,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 7b67ab797..9dc46f963 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "data/data_abstract_structure.h" #include "history/history_service_layout.h" #include "media/media_audio.h" +#include "inline_bots/inline_bot_layout_item.h" #include "application.h" #include "fileuploader.h" #include "mainwidget.h" @@ -382,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; } @@ -1452,7 +1469,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); } @@ -1465,14 +1482,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) { @@ -1629,11 +1646,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); @@ -1645,10 +1664,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; @@ -1658,7 +1678,7 @@ namespace { } MediaKey newKey = convert->mediaKey(); - if (newKey != oldKey) { + if (idChanged) { if (convert->voice()) { Local::copyAudio(oldKey, newKey); } else if (convert->sticker() || convert->isAnimation()) { @@ -1677,7 +1697,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; @@ -1692,12 +1712,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; @@ -1710,6 +1731,30 @@ namespace { if (sentSticker && App::main()) { App::main()->incrementSticker(result); } + if (versionChanged) { + 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); + if (i != items.cend()) { + for (auto j = i->cbegin(), e = i->cend(); j != e; ++j) { + j.key()->setPendingInitDimensions(); + } + } + } return result; } @@ -1977,6 +2022,11 @@ 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); + Global::SetArchivedStickerSetsOrder(Stickers::Order()); cSetSavedGifs(SavedGifs()); cSetLastSavedGifsUpdate(0); cSetReportSpamStatuses(ReportSpamStatuses()); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 8468b9456..6dc19af13 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); @@ -149,7 +151,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/boxes.style b/Telegram/SourceFiles/boxes/boxes.style new file mode 100644 index 000000000..54f43ec25 --- /dev/null +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -0,0 +1,69 @@ +/* +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; + +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/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index 83ce30643..39c978ed3 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 59f27336d..ebad005d5 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 b71a9634e..62c8c5580 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -28,18 +28,51 @@ 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" +#include "styles/style_boxes.h" + +namespace { + +constexpr int kArchivedLimitFirstRequest = 10; +constexpr int kArchivedLimitPerPage = 30; + +} // namespace + +namespace Stickers { + +void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { + auto &v = d.vsets.c_vector().v; + auto &order = Global::RefStickerSetsOrder(); + Stickers::Order archived; + archived.reserve(v.size()); + QMap setsToRequest; + for_const (auto &stickerSet, v) { + 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); + } + 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(); + } + Local::writeArchivedStickers(); + Ui::showLayer(new StickersBox(archived), KeepOtherLayers); +} + +} // namespace Stickers 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; @@ -56,21 +89,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) { @@ -83,7 +116,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); @@ -92,6 +125,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 | MTPDstickerSet_ClientFlag::f_special); + _setFlags |= clientFlags; + it->flags = _setFlags; + it->stickers = _pack; + it->emoji = _emoji; + } } } @@ -116,19 +158,29 @@ bool StickerSetInner::failedSet(const RPCError &error) { return true; } -void StickerSetInner::installDone(const MTPBool &result) { - Stickers::Sets &sets(Global::RefStickerSets()); +void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &result) { + auto &sets = Global::RefStickerSets(); - _setFlags &= ~MTPDstickerSet::Flag::f_disabled; + 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); if (it == sets.cend()) { it = sets.insert(_setId, Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)); + } else { + it->flags = _setFlags; } - it.value().stickers = _pack; - it.value().emoji = _emoji; + it->stickers = _pack; + it->emoji = _emoji; - Stickers::Order &order(Global::RefStickerSetsOrder()); - int32 insertAtIndex = 0, currentIndex = order.indexOf(_setId); + auto &order = Global::RefStickerSetsOrder(); + int insertAtIndex = 0, currentIndex = order.indexOf(_setId); if (currentIndex != insertAtIndex) { if (currentIndex > 0) { order.removeAt(currentIndex); @@ -138,27 +190,30 @@ 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()) { sets.erase(custom); } } - Local::writeStickers(); + + if (result.type() == mtpc_messages_stickerSetInstallResultArchive) { + Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); + } else if (wasArchived) { + Local::writeArchivedStickers(); + } + + Local::writeInstalledStickers(); + emit App::main()->stickersUpdated(); emit installed(_setId); - Ui::hideLayer(); } -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))); - } else { - Ui::showLayer(new InformBox(lang(lng_stickers_not_found))); - } + Ui::showLayer(new InformBox(lang(lng_stickers_not_found))); return true; } @@ -261,7 +316,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_archived)) return _pack.size(); return 0; } @@ -279,7 +334,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() { @@ -305,7 +360,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(); @@ -314,6 +369,11 @@ StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st:: prepare(); } +void StickerSetBox::onInstalled(uint64 setId) { + emit installed(setId); + onClose(); +} + void StickerSetBox::onStickersUpdated() { showAll(); } @@ -402,28 +462,63 @@ 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) +, _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))) -, _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) { + 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); } +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(), y + st::stickersFeaturedPosition.y(), width(), text); + + 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 = y + (_buttonHeight - st::stickersFeaturedBadgeSize) / 2; + Dialogs::Layout::paintUnreadCount(p, QString::number(badgeCounter), unreadRight, unreadTop, unreadSt); + } +} + void StickersInner::paintEvent(QPaintEvent *e) { QRect r(e->rect()); Painter p(this); @@ -432,10 +527,23 @@ void StickersInner::paintEvent(QPaintEvent *e) { p.fillRect(r, st::white); p.setClipRect(r); + + 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->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, y, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); } else { p.translate(0, _itemsTop); @@ -462,50 +570,84 @@ 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->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) { + 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 && !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 = st::stickersAddSize.width(); + int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw; + 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); + 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)); 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); @@ -516,10 +658,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 && !_rows.at(_selected)->recent) { _above = _dragging = _started = _selected; _dragStart = mapFromGlobal(_mouse); } @@ -537,8 +681,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); @@ -567,19 +715,74 @@ 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)->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 && !_rows.at(selected)->disabled) { + actionSel = -1; + } else { + int addw = st::stickersAddSize.width(); + int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw; + 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 (_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 = -3; } - setRemoveSel(removeSel); + if (_selected != selected) { + if (((_selected == -1) != (selected == -1)) || ((_selected == -2) != (selected == -2))) { + update(); + } + 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; + } + setActionSel(actionSel); emit noDraggingScroll(); } } +void StickersInner::onClearRecent() { + if (_clearBox) { + _clearBox->onClose(); + } + + auto &sets = Global::RefStickerSets(); + bool removedCloud = (sets.remove(Stickers::CloudRecentSetId) != 0); + bool removedCustom = (sets.remove(Stickers::CustomSetId) != 0); + + auto &recent = cGetRecentStickers(); + if (!recent.isEmpty()) { + recent.clear(); + Local::writeUserSettings(); + } + + if (removedCustom) Local::writeInstalledStickers(); + if (removedCloud) Local::writeRecentStickers(); + 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; @@ -589,11 +792,30 @@ float64 StickersInner::aboveShadowOpacity() const { } void StickersInner::mouseReleaseEvent(QMouseEvent *e) { + auto pressed = _pressed; + _pressed = -2; + + if (_section != Section::Installed && _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) { + 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); + } } else if (_dragging >= 0) { QPoint local(mapFromGlobal(_mouse)); _rows[_dragging]->yadd.start(0); @@ -604,13 +826,124 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) { } _dragging = _started = -1; + } else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) { + 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 = -3; + 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()), 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); + 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::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(); +} + +void StickersInner::installDone(const MTPmessages_StickerSetInstallResult &result) { + if (result.type() == mtpc_messages_stickerSetInstallResultArchive) { + Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); + Local::writeInstalledStickers(); + Local::writeArchivedStickers(); + 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; + + 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::writeInstalledStickers(); + emit App::main()->stickersUpdated(); + + 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; @@ -664,90 +997,267 @@ void StickersInner::clear() { _aboveShadowFadeOpacity = anim::fvalue(0, 0); _a_shifting.stop(); _above = _dragging = _started = -1; - _selected = -1; - _removeDown = -1; - setRemoveSel(-1); + _selected = -3; + _pressed = -3; + _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; + _hasFeaturedButton = _hasArchivedButton = false; + _itemsTop = 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(); + } + } - 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); + int maxNameWidth = countMaxNameWidth(); clear(); - const Stickers::Order &order(Global::StickerSetsOrder()); - _animStartTimes.reserve(order.size()); + auto &order = ([this]() { + if (_section == Section::Installed) { + return Global::StickerSetsOrder(); + } else if (_section == Section::Featured) { + return Global::FeaturedStickerSetsOrder(); + } else if (_section == Section::Archived) { + return Global::ArchivedStickerSetsOrder(); + } + return _archivedIds; + })(); + _rows.reserve(order.size() + 1); + _animStartTimes.reserve(order.size() + 1); - const Stickers::Sets &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); + auto &sets = Global::StickerSets(); + if (_section == Section::Installed) { + auto cloudIt = sets.constFind(Stickers::CloudRecentSetId); + if (cloudIt != sets.cend() && !cloudIt->stickers.isEmpty()) { + rebuildAppendSet(cloudIt.value(), maxNameWidth); + } + } + 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) { - 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); - } + 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(); - _rows = rows + rowsDisabled; + updateSize(); + + 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::updateSize() { resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom()); } -QVector StickersInner::getOrder() const { - QVector result; +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; + } + } + 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(); +} + +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; + } + *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(); + for_const (auto &sticker, cGetRecentStickers()) { + if (customIt->stickers.indexOf(sticker.first) < 0) { + ++added; + } + } + } else { + added = cGetRecentStickers().size(); + } + } + 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) { + Local::writeFeaturedStickers(); + 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; +} + +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)->disabled || _rows.at(i)->recent) { + continue; } result.push_back(_rows.at(i)->id); } 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) { @@ -765,40 +1275,177 @@ StickersInner::~StickersInner() { clear(); } -StickersBox::StickersBox() : ItemListBox(st::boxScroll) -, _save(this, lang(lng_settings_save), st::defaultBoxButton) -, _cancel(this, lang(lng_cancel), st::cancelBoxButton) -, _reorderRequest(0) -, _topShadow(this, st::contactsAboutShadow) -, _bottomShadow(this) -, _scrollDelta(0) +} // namespace internal + +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) -, _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((section == Section::Archived) ? lng_stickers_packs_archived : 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::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_stickerSetCovered || stickerSet.c_stickerSetCovered().vset.type() != mtpc_stickerSet) continue; + + 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) { + 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(); + _topShadow = new PlainShadow(this, st::contactsAboutShadow); + + _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(); + } 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())); + } 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))); 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())); + connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); _scrollTimer.setSingleShot(false); - onStickersUpdated(); + rebuildList(); prepare(); } -int32 StickersBox::countHeight() const { - return st::boxTitleHeight + _aboutHeight + _inner.height() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); +void StickersBox::onScroll() { + checkLoadMoreArchived(); } -void StickersBox::disenableDone(const MTPBool & result, mtpRequestId req) { +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) { + bottomSkip = st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom(); + } + return st::boxTitleHeight + _aboutHeight + _inner->height() + bottomSkip; +} + +void StickersBox::disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req) { _disenableRequests.remove(req); if (_disenableRequests.isEmpty()) { saveOrder(); @@ -815,7 +1462,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()); @@ -846,12 +1493,22 @@ 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); - 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() { @@ -870,20 +1527,40 @@ void StickersBox::closePressed() { } } +StickersBox::~StickersBox() { + if (_section == Section::Archived) { + Local::writeArchivedStickers(); + } +} + 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()); - _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->resize(width(), _inner->height()); + _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); + } } void StickersBox::onStickersUpdated() { - _inner.rebuild(); + 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); + _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); } void StickersBox::onCheckDraggingScroll(int localY) { @@ -911,15 +1588,15 @@ void StickersBox::onScrollTimer() { } void StickersBox::onSave() { - if (!_inner.savingStart()) { + if (!_inner->savingStart()) { return; } - bool writeRecent = false; - RecentStickerPack &recent(cGetRecentStickers()); - Stickers::Sets &sets(Global::RefStickerSets()); + bool writeRecent = false, writeArchived = false; + 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()) { @@ -931,43 +1608,69 @@ 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; + 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); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); - sets.erase(it); + 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); + } } } } } - Stickers::Order &order(Global::RefStickerSetsOrder()); + + // Clear all installed flags, set only for sets from order. + for (auto &set : sets) { + if (!(set.flags & MTPDstickerSet::Flag::f_archived)) { + set.flags &= ~MTPDstickerSet::Flag::f_installed; + } + } + + auto &order(Global::RefStickerSetsOrder()); order.clear(); 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; + writeArchived = true; } 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 || order.contains(it->id)) { + 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 { it = sets.erase(it); } } - Local::writeStickers(); + Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); + if (writeArchived) Local::writeArchivedStickers(); emit App::main()->stickersUpdated(); if (_disenableRequests.isEmpty()) { @@ -978,29 +1681,41 @@ void StickersBox::onSave() { } void StickersBox::hideAll() { - _save.hide(); - _cancel.hide(); - _topShadow.hide(); - _bottomShadow.hide(); + if (_topShadow) { + _topShadow->hide(); + } + if (_save) { + _save->hide(); + } + if (_cancel) { + _cancel->hide(); + _bottomShadow->hide(); + } ItemListBox::hideAll(); } void StickersBox::showAll() { - _save.show(); - _cancel.show(); - _topShadow.show(); - _bottomShadow.show(); + if (_topShadow) { + _topShadow->show(); + } + if (_save) { + _save->show(); + } + if (_cancel) { + _cancel->show(); + _bottomShadow->show(); + } ItemListBox::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()) { - 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 fc2c9a513..42d9e23cf 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 @@ -62,24 +64,26 @@ private: void gotSet(const MTPmessages_StickerSet &set); bool failedSet(const RPCError &error); - void installDone(const MTPBool &result); - bool installFailed(const RPCError &error); + void installDone(const MTPmessages_StickerSetInstallResult &result); + bool installFail(const RPCError &error); 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 { @@ -93,7 +97,6 @@ public: void resizeEvent(QResizeEvent *e); public slots: - void onStickersUpdated(); void onAddStickers(); void onShareStickers(); @@ -101,122 +104,49 @@ 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: + enum class Section { + Installed, + Featured, + Archived, + ArchivedPart, + }; + StickersBox(Section section = Section::Installed); + StickersBox(const Stickers::Order &archivedIds); - StickersBox(); void resizeEvent(QResizeEvent *e); void paintEvent(QPaintEvent *e); void closePressed(); -public slots: + ~StickersBox(); +public slots: void onStickersUpdated(); void onCheckDraggingScroll(int localY); @@ -225,35 +155,184 @@ public slots: void onSave(); -protected: +private slots: + void onScroll(); +protected: void hideAll(); void showAll(); private: - + void setup(); int32 countHeight() const; + void rebuildList(); - 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); void saveOrder(); - StickersInner _inner; - BoxButton _save, _cancel; + void checkLoadMoreArchived(); + void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result); + + Section _section; + + ChildWidget _inner; + ChildWidget _save = { nullptr }; + ChildWidget _cancel = { nullptr }; QMap _disenableRequests; - mtpRequestId _reorderRequest; - PlainShadow _topShadow; - ScrollableBoxShadow _bottomShadow; + mtpRequestId _reorderRequest = 0; + ChildWidget _topShadow = { nullptr }; + ChildWidget _bottomShadow = { nullptr }; QTimer _scrollTimer; - int32 _scrollDelta; + int32 _scrollDelta = 0; - int32 _aboutWidth; + int _aboutWidth = 0; Text _about; - int32 _aboutHeight; + int _aboutHeight = 0; + + mtpRequestId _archivedRequestId = 0; + bool _allArchivedLoaded = false; }; int32 stickerPacksCount(bool includeDisabledOfficial = false); + +namespace internal { + +class StickersInner : public TWidget, public RPCSender { + Q_OBJECT + +public: + using Section = StickersBox::Section; + StickersInner(Section section); + 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; + return true; + } + + Stickers::Order getOrder() const; + Stickers::Order 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(); + void onClearRecent(); + void onClearBoxDestroyed(QObject *box); + +private: + void setup(); + 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); + void clear(); + void setActionSel(int32 actionSel); + 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 { + 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) + , installed(installed) + , official(official) + , unread(unread) + , disabled(disabled) + , recent(recent) + , pixw(pixw) + , pixh(pixh) + , yadd(0, 0) { + } + uint64 id; + DocumentData *sticker; + int32 count; + QString title; + bool installed, official, unread, disabled, recent; + int32 pixw, pixh; + anim::ivalue yadd; + }; + 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; + uint64 _aboveShadowFadeStart = 0; + anim::fvalue _aboveShadowFadeOpacity = { 0., 0. }; + Animation _a_shifting; + + int32 _itemsTop; + + bool _saving = false; + + int _actionSel = -1; + int _actionDown = -1; + + int _clearWidth, _removeWidth, _returnWidth, _restoreWidth; + + ConfirmBox *_clearBox = nullptr; + + QString _addText; + int _addWidth; + + 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 = -3; // -2 - featured stickers button, -1 - archived 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/core/vector_of_moveable.h b/Telegram/SourceFiles/core/vector_of_moveable.h index 412d87b35..608bb0796 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/core/version.h b/Telegram/SourceFiles/core/version.h index ad8fb384b..9c9fe8880 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 = 9060; -constexpr str_const AppVersionStr = "0.9.60"; -constexpr bool AppAlphaVersion = true; +constexpr int AppVersion = 9061; +constexpr str_const AppVersionStr = "0.9.61"; +constexpr bool AppAlphaVersion = false; constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index daae49132..ce4681df0 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; @@ -86,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/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 8e8843ac6..29e8ea46d 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 b0e5bd8b1..f083f062f 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 b96b1a1d3..a3327c608 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" @@ -713,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) @@ -1229,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); @@ -1508,7 +1509,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) { @@ -1517,7 +1518,7 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) { if (it->stickers.isEmpty()) { sets.erase(it); } - Local::writeStickers(); + Local::writeInstalledStickers(); refresh = true; break; } @@ -1628,8 +1629,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,9 +2086,9 @@ 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; + if (it == sets.cend() || (it->flags & MTPDstickerSet::Flag::f_archived) || it->stickers.isEmpty()) return; StickerPack pack; pack.reserve(it->stickers.size()); @@ -2110,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); } } @@ -2829,6 +2842,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 +2873,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 +3120,7 @@ void EmojiPan::refreshStickers() { if (!_stickersShown) { s_inner.preloadImages(); } + update(); } void EmojiPan::refreshSavedGifs() { @@ -3228,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(); @@ -3584,7 +3612,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(); @@ -3623,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())); @@ -3635,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()) { @@ -3652,11 +3682,14 @@ void EmojiPan::onRemoveSetSure() { ++i; } } - Global::RefStickerSets().erase(it); + it->flags &= ~MTPDstickerSet::Flag::f_installed; + if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { + 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/dropdown.h b/Telegram/SourceFiles/dropdown.h index 32faf3568..dfd81a7cf 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 b0f0a17b2..3f82c3d85 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)); } } @@ -518,6 +520,45 @@ DefineVar(Sandbox, ConnectionProxy, PreLaunchProxy); } // namespace Sandbox +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); + 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); + 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()) { + it->count = set.vcount.v; + it->hash = set.vhash.v; + 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(); +} + +} // namespace Stickers + namespace Global { namespace internal { @@ -557,6 +598,7 @@ struct Data { int32 PushChatLimit = 2; int32 SavedGifsLimit = 200; int32 EditTimeLimit = 172800; + int32 StickersRecentLimit = 30; HiddenPinnedMessagesMap HiddenPinnedMessages; @@ -565,6 +607,11 @@ struct Data { Stickers::Sets StickerSets; Stickers::Order StickerSetsOrder; uint64 LastStickersUpdate = 0; + uint64 LastRecentStickersUpdate = 0; + Stickers::Order FeaturedStickerSetsOrder; + int FeaturedStickerSetsUnreadCount = 0; + uint64 LastFeaturedStickersUpdate = 0; + Stickers::Order ArchivedStickerSetsOrder; MTP::DcOptions DcOptions; @@ -628,6 +675,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); @@ -636,6 +684,11 @@ 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); +DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder); DefineVar(Global, MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 4a14f5694..364dc28da 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(); @@ -178,10 +183,19 @@ 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), 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; @@ -193,6 +207,15 @@ struct Set { using Sets = QMap; using Order = QList; +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)); +} + +Set *feedSet(const MTPDstickerSet &set); + } // namespace Stickers namespace Global { @@ -236,6 +259,7 @@ DeclareVar(int32, PushChatPeriod); DeclareVar(int32, PushChatLimit); DeclareVar(int32, SavedGifsLimit); DeclareVar(int32, EditTimeLimit); +DeclareVar(int32, StickersRecentLimit); typedef QMap HiddenPinnedMessagesMap; DeclareVar(HiddenPinnedMessagesMap, HiddenPinnedMessages); @@ -246,6 +270,11 @@ 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); +DeclareVar(Stickers::Order, ArchivedStickerSetsOrder); DeclareVar(MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index d94e11200..6fcdd5a72 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2869,7 +2869,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; } } @@ -4079,10 +4081,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())) { @@ -5170,7 +5172,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/history/field_autocomplete.cpp b/Telegram/SourceFiles/history/field_autocomplete.cpp index cfeffcdf0..a814fa9bd 100644 --- a/Telegram/SourceFiles/history/field_autocomplete.cpp +++ b/Telegram/SourceFiles/history/field_autocomplete.cpp @@ -153,15 +153,15 @@ 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()) { 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; @@ -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 ecf537a67..efcc20934 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; @@ -43,8 +45,6 @@ membersInnerDropdown: InnerDropdown(defaultInnerDropdown) { scrollMargin: margins(0px, 5px, 0px, 5px); scrollPadding: margins(0px, 3px, 8px, 3px); } -historyToDownBadgeFont: semiboldFont; -historyToDownBadgeSize: 22px; historyServiceMsgRadius: 12px; historyServiceMsgInvertedRadius: 6px; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 87b1c9bb8..0c00c6a25 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" @@ -3523,12 +3524,23 @@ 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::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)); + } + } + if (!cLastSavedGifsUpdate() || now >= cLastSavedGifsUpdate() + StickersUpdateTimeout) { if (!_savedGifsUpdateRequest) { _savedGifsUpdateRequest = MTP::send(MTPmessages_GetSavedGifs(MTP_int(Local::countSavedGifsHash())), rpcDone(&HistoryWidget::savedGifsGot), rpcFail(&HistoryWidget::savedGifsFailed)); } @@ -3654,36 +3666,23 @@ 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) { + if (!(set.flags & MTPDstickerSet::Flag::f_archived)) { + 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()); - 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); - it->flags = set.vflags.v; - 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); + for_const (auto &setData, d_sets) { + if (setData.type() == mtpc_stickerSet) { + auto set = Stickers::feedSet(setData.c_stickerSet()); + if (!(set->flags & MTPDstickerSet::Flag::f_archived) || (set->flags & MTPDstickerSet::Flag::f_official)) { + setsOrder.push_back(set->id); + if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + setsToRequest.insert(set->id, set->access); } } } @@ -3691,9 +3690,11 @@ 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); + bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special); + bool archived = (it->flags & MTPDstickerSet::Flag::f_archived); + if (!installed) { // remove not mine sets from recent stickers for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) { if (it->stickers.indexOf(i->first) >= 0) { i = recent.erase(i); @@ -3702,6 +3703,10 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { ++i; } } + } + if (installed || featured || special || archived) { + ++it; + } else { it = sets.erase(it); } } @@ -3717,7 +3722,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(); @@ -3733,6 +3738,193 @@ 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::writeRecentStickers(); + + 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; + + 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(); + 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_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()) { + auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded; + if (unread.contains(set.vid.v)) { + setClientFlags |= MTPDstickerSet_ClientFlag::f_unread; + } + it = sets.insert(set.vid.v, Stickers::Set(set.vid.v, set.vaccess_hash.v, title, qs(set.vshort_name), set.vcount.v, set.vhash.v, set.vflags.v | setClientFlags)); + } else { + it->access = set.vaccess_hash.v; + it->title = title; + it->shortName = qs(set.vshort_name); + auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_special); + it->flags = set.vflags.v | clientFlags; + it->flags |= MTPDstickerSet_ClientFlag::f_featured; + if (unread.contains(it->id)) { + it->flags |= MTPDstickerSet_ClientFlag::f_unread; + } else { + it->flags &= ~MTPDstickerSet_ClientFlag::f_unread; + } + if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) { + it->count = set.vcount.v; + it->hash = set.vhash.v; + it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; // need to request this set + } + } + setsOrder.push_back(set.vid.v); + if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + setsToRequest.insert(set.vid.v, set.vaccess_hash.v); + } + } + } + + int unreadCount = 0; + for (auto it = sets.begin(), e = sets.end(); it != e;) { + bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); + bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured); + bool special = (it->flags & MTPDstickerSet_ClientFlag::f_special); + bool archived = (it->flags & MTPDstickerSet::Flag::f_archived); + if (installed || featured || special || archived) { + if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { + ++unreadCount; + } + ++it; + } else { + it = sets.erase(it); + } + } + 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())); + } + + 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::writeFeaturedStickers(); + + 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; @@ -4575,7 +4767,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; } @@ -4587,7 +4779,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; } @@ -5605,6 +5797,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()) { + HiddenUrlClickHandler(qs(answerData.vurl)).onClick(Qt::LeftButton); } } } @@ -6040,7 +6234,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); @@ -6055,7 +6249,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 { @@ -6065,7 +6259,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; @@ -6111,8 +6305,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); } @@ -6664,10 +6858,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()); } @@ -7195,7 +7389,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); @@ -7973,7 +8167,7 @@ void HistoryWidget::onCancel() { } else if (!_fieldAutocomplete->isHidden()) { _fieldAutocomplete->hideStart(); } else { - Ui::showChatsList(); + App::main()->showBackFromStack(); emit cancelled(); } } @@ -8011,7 +8205,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/historywidget.h b/Telegram/SourceFiles/historywidget.h index fdcdad95d..ee97d4115 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -1005,6 +1005,14 @@ 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); + mtpRequestId _savedGifsUpdateRequest = 0; void savedGifsGot(const MTPmessages_SavedGifs &gifs); bool savedGifsFailed(const RPCError &error); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index 29a4909c7..d3afc27b4 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 8419f665e..1da43d5c1 100644 --- a/Telegram/SourceFiles/localimageloader.cpp +++ b/Telegram/SourceFiles/localimageloader.cpp @@ -414,9 +414,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 11e617c13..dcd58c50a 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 { @@ -542,6 +543,7 @@ namespace { dbiDialogsMode = 0x40, dbiModerateMode = 0x41, dbiVideoVolume = 0x42, + dbiStickersRecentLimit = 0x43, dbiEncryptedWithSalt = 333, dbiEncrypted = 444, @@ -571,7 +573,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; @@ -835,6 +839,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; @@ -1725,7 +1737,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; @@ -1806,8 +1820,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; @@ -1842,7 +1859,10 @@ namespace { _locationsKey = locationsKey; _reportSpamStatusesKey = reportSpamStatusesKey; _recentStickersKeyOld = recentStickersKeyOld; - _stickersKey = stickersKey; + _installedStickersKey = installedStickersKey; + _featuredStickersKey = featuredStickersKey; + _recentStickersKey = recentStickersKey; + _archivedStickersKey = archivedStickersKey; _savedGifsKey = savedGifsKey; _savedPeersKey = savedPeersKey; _backgroundKey = backgroundKey; @@ -1915,7 +1935,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); @@ -1961,8 +1983,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); @@ -2185,12 +2208,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()); @@ -2247,7 +2271,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 +3043,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,61 +3068,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; - const Stickers::Sets &sets(Global::StickerSets()); + 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 (auto i = sets.cbegin(); i != sets.cend(); ++i) { - bool notLoaded = (i->flags & MTPDstickerSet_ClientFlag::f_not_loaded); - if (notLoaded) { - if (!(i->flags & MTPDstickerSet::Flag::f_disabled) || (i->flags & MTPDstickerSet::Flag::f_official)) { // waiting to receive - return; - } - } else { - if (i->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); - } - - if (AppVersion > 9018) { - size += sizeof(qint32); // emojiCount - for (StickersByEmojiMap::const_iterator j = i->emoji.cbegin(), e = i->emoji.cend(); j != e; ++j) { - size += Serialize::stringSize(emojiString(j.key())) + sizeof(qint32) + (j->size() * sizeof(quint64)); - } - } - - ++setsCount; - } - - if (!_stickersKey) { - _stickersKey = genKey(); - _mapChanged = true; - _writeMap(WriteMapFast); - } - 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); - } - 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 < 9061) { + 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 < 9061) { + 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 < 9061) { + 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 >= 9061) { + 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; + }, Global::ArchivedStickerSetsOrder()); } void importOldRecentStickers() { @@ -3113,17 +3349,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 | 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()) { @@ -3149,7 +3385,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) { @@ -3159,7 +3395,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); @@ -3168,7 +3406,7 @@ namespace Local { } if (custom.stickers.isEmpty()) sets.remove(Stickers::CustomSetId); - writeStickers(); + writeInstalledStickers(); writeUserSettings(); clearKey(_recentStickersKeyOld); @@ -3176,130 +3414,95 @@ 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)); + } + + void readFeaturedStickers() { + _readStickerSets(_featuredStickersKey, &Global::RefFeaturedStickerSetsOrder(), qFlags(MTPDstickerSet_ClientFlag::f_featured)); + + auto &sets = Global::StickerSets(); + int unreadCount = 0; + 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); + } - Stickers::Sets &sets(Global::RefStickerSets()); - sets.clear(); + void readRecentStickers() { + _readStickerSets(_recentStickersKey); + } - Stickers::Order &order(Global::RefStickerSetsOrder()); - order.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 (setId == Stickers::DefaultSetId) { - setTitle = lang(lng_stickers_default_set); - setFlags |= qFlags(MTPDstickerSet::Flag::f_official); - order.push_front(setId); - } else if (setId == Stickers::CustomSetId) { - setTitle = lang(lng_custom_stickers); - } else if (setId) { - order.push_back(setId); - } else { - continue; - } - Stickers::Set &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; - } - - 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.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); - } - } - } + void readArchivedStickers() { + static bool archivedStickersRead = false; + if (!archivedStickersRead) { + _readStickerSets(_archivedStickersKey, &Global::RefArchivedStickerSetsOrder()); + archivedStickersRead = true; } } - int32 countStickersHash(bool checkOfficial) { + int32 countStickersHash(bool checkOutdatedInfo) { uint32 acc = 0; - bool foundOfficial = false, foundBad = false;; - const Stickers::Sets &sets(Global::StickerSets()); - const Stickers::Order &order(Global::StickerSetsOrder()); + 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_disabled)) { + 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() { + 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(); + auto &featured = Global::FeaturedStickerSetsOrder(); + for_const (auto setId, featured) { + acc = (acc * 20261) + uint32(setId >> 32); + acc = (acc * 20261) + uint32(setId & 0xFFFFFFFF); + + auto it = sets.constFind(setId); + if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) { + acc = (acc * 20261) + 1U; + } + } + return int32(acc & 0x7FFFFFFF); } 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); } @@ -3357,7 +3560,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; @@ -3862,8 +4065,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 0f9a0fd11..ca59fe65b 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -153,9 +153,17 @@ namespace Local { void cancelTask(TaskId id); - void writeStickers(); - void readStickers(); - int32 countStickersHash(bool checkOfficial = false); + void writeInstalledStickers(); + void writeFeaturedStickers(); + void writeRecentStickers(); + void writeArchivedStickers(); + void readInstalledStickers(); + void readFeaturedStickers(); + void readRecentStickers(); + void readArchivedStickers(); + int32 countStickersHash(bool checkOutdatedInfo = false); + int32 countRecentStickersHash(); + int32 countFeaturedStickersHash(); void writeSavedGifs(); void readSavedGifs(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index cdf9f42a2..7ab4ce6d7 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -298,11 +298,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) { @@ -1519,8 +1514,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) { @@ -1995,7 +1990,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(); @@ -2009,8 +2004,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(); @@ -2022,10 +2046,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(); @@ -2042,11 +2068,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(); @@ -2090,6 +2111,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac } _dialogs->update(); } + topBar()->showAll(); App::wnd()->getTitle()->updateBackButton(); } @@ -2146,6 +2168,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(); @@ -2166,17 +2203,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(); @@ -2201,7 +2228,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(); @@ -2217,17 +2246,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); } @@ -2320,6 +2339,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()) { @@ -2327,34 +2350,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() { @@ -3251,7 +3273,9 @@ void MainWidget::start(const MTPUser &user) { } _started = true; App::wnd()->sendServiceHistoryRequest(); - Local::readStickers(); + Local::readInstalledStickers(); + Local::readFeaturedStickers(); + Local::readRecentStickers(); Local::readSavedGifs(); _history->start(); } @@ -3322,7 +3346,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); } @@ -3337,7 +3361,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)); @@ -3357,7 +3381,6 @@ void MainWidget::stickersBox(const MTPInputStickerSet &set) { } void MainWidget::onStickersInstalled(uint64 setId) { - emit stickersUpdated(); _history->stickersInstalled(setId); } @@ -3405,7 +3428,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); } @@ -3436,11 +3459,21 @@ 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()); + + 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, d.vparticipants_count.v, participants); _inviteHash = hash; - connect(box, SIGNAL(confirmed()), this, SLOT(onInviteImport())); - Ui::showLayer(box); + Ui::showLayer(box.release()); } break; case mtpc_chatInviteAlready: { @@ -3618,72 +3651,65 @@ 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 writeRecentStickers = 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); + writeRecentStickers = true; + } + + // Remove that sticker from old recent, now it is in cloud recent stickers. + bool writeOldRecent = 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)); - } + writeOldRecent = 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() > Global::StickersRecentLimit()) { + writeOldRecent = 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 (writeOldRecent) { + 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. + bool writeInstalledStickers = false; + 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; + writeInstalledStickers = 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, 0)); - } - it->stickers.push_back(sticker); - ++it->count; - Local::writeStickers(); + + if (writeInstalledStickers) { + Local::writeInstalledStickers(); + } + if (writeRecentStickers) { + Local::writeRecentStickers(); } _history->updateRecentStickers(); } @@ -4625,16 +4651,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)); + 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; + if (it->flags & MTPDstickerSet::Flag::f_archived) { + it->flags &= ~MTPDstickerSet::Flag::f_archived; + writeArchived = true; + } } const auto &v(set.vdocuments.c_vector().v); @@ -4647,12 +4680,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) { @@ -4684,16 +4717,17 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { sets.erase(custom); } } - Local::writeStickers(); + Local::writeInstalledStickers(); + if (writeArchived) Local::writeArchivedStickers(); emit stickersUpdated(); } } } 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()) { @@ -4706,7 +4740,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { App::main()->updateStickers(); } else { Global::SetStickerSetsOrder(result); - Local::writeStickers(); + Local::writeInstalledStickers(); emit stickersUpdated(); } } break; @@ -4716,6 +4750,24 @@ 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) { + set.flags &= ~MTPDstickerSet_ClientFlag::f_unread; + } + } + if (Global::FeaturedStickerSetsUnreadCount()) { + Global::SetFeaturedStickerSetsUnreadCount(0); + Local::writeFeaturedStickers(); + emit stickersUpdated(); + } + } break; + ////// Cloud saved GIFs case mtpc_updateSavedGifs: { cSetLastSavedGifsUpdate(0); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index c6a41c918..0ee2899c7 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); @@ -492,7 +472,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: @@ -518,6 +498,8 @@ private: Window::SectionSlideParams prepareOverviewAnimation(); Window::SectionSlideParams prepareDialogsAnimation(); + void saveSectionInStack(); + bool _started = false; uint64 failedObjId = 0; @@ -597,7 +579,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/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index f03dacae2..3afe8ae3f 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -1556,7 +1556,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 0fed750d1..846b8ef71 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -1060,8 +1060,17 @@ 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), + + // 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 << 30), + MIN_FIELD = (1 << 27), }; DEFINE_MTP_CLIENT_FLAGS(MTPDstickerSet) diff --git a/Telegram/SourceFiles/mtproto/dcenter.cpp b/Telegram/SourceFiles/mtproto/dcenter.cpp index 7043e26b9..f15fd2fc4 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/file_download.cpp b/Telegram/SourceFiles/mtproto/file_download.cpp index d8c588eee..0b8997325 100644 --- a/Telegram/SourceFiles/mtproto/file_download.cpp +++ b/Telegram/SourceFiles/mtproto/file_download.cpp @@ -351,13 +351,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)); @@ -365,15 +360,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)); @@ -422,7 +414,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; } } @@ -532,7 +524,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)); } @@ -594,7 +586,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 f8a05d7ea..94b65fb2b 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 0e5f0b11d..96162e540 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; @@ -392,6 +392,8 @@ 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; +updateRecentStickers#9a422c20 = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -416,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; @@ -454,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; @@ -547,13 +549,13 @@ 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#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; 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; @@ -670,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#1264f1c6 flags:# alert:flags.1?true message:flags.0?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; @@ -696,6 +698,19 @@ 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#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#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; + +messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; +messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; + +stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -806,7 +821,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; @@ -826,10 +841,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#481c591a flags:# alert:flags.1?true query_id:long message:flags.0?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; +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#4309d65b 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; @@ -880,4 +902,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 230d39b93..21ef6b800 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; } } @@ -3012,6 +3013,14 @@ 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_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); @@ -3320,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; } } @@ -3672,7 +3682,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; } } @@ -4339,6 +4350,9 @@ 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_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; } } @@ -4386,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; @@ -5587,6 +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 2 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -5745,6 +5760,88 @@ 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_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_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_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); @@ -6421,20 +6518,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); @@ -6546,6 +6629,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 2 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -6570,6 +6654,28 @@ 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_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(); +} + 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); @@ -7906,6 +8012,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); @@ -8010,6 +8130,59 @@ 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_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_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(); } @@ -8467,6 +8640,8 @@ 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_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); @@ -8680,6 +8855,14 @@ 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_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_stickerSetCovered, _serialize_stickerSetCovered); _serializers.insert(mtpc_req_pq, _serialize_req_pq); _serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params); @@ -8731,7 +8914,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); @@ -8740,6 +8922,9 @@ 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_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); _serializers.insert(mtpc_help_saveAppLog, _serialize_help_saveAppLog); @@ -8836,6 +9021,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); @@ -8843,6 +9029,10 @@ 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_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 7c6769561..f4ce9d502 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; @@ -111,7 +111,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, @@ -287,6 +287,8 @@ enum { mtpc_updateInlineBotCallbackQuery = 0x2cbd95af, mtpc_updateReadChannelOutbox = 0x25d6c9c7, mtpc_updateDraftMessage = 0xee2bb969, + mtpc_updateReadFeaturedStickers = 0x571d2742, + mtpc_updateRecentStickers = 0x9a422c20, mtpc_updates_state = 0xa56c2a3e, mtpc_updates_differenceEmpty = 0x5d75a138, mtpc_updates_difference = 0xf49ca0, @@ -303,7 +305,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, @@ -329,7 +331,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, @@ -395,7 +397,7 @@ enum { mtpc_chatInviteEmpty = 0x69df3769, mtpc_chatInviteExported = 0xfc2e05bc, mtpc_chatInviteAlready = 0x5a686d7c, - mtpc_chatInvite = 0x93e99b60, + mtpc_chatInvite = 0xdb74f558, mtpc_inputStickerSetEmpty = 0xffb62b95, mtpc_inputStickerSetID = 0x9de7a269, mtpc_inputStickerSetShortName = 0x861cc8a0, @@ -484,7 +486,7 @@ enum { mtpc_auth_sentCodeTypeSms = 0xc000bba2, mtpc_auth_sentCodeTypeCall = 0x5353e5a7, mtpc_auth_sentCodeTypeFlashCall = 0xab03c6d9, - mtpc_messages_botCallbackAnswer = 0x1264f1c6, + mtpc_messages_botCallbackAnswer = 0xb10df1fb, mtpc_messages_messageEditData = 0x26b5dde6, mtpc_inputBotInlineMessageID = 0x890c3d89, mtpc_inlineBotSwitchPM = 0x3c20629f, @@ -500,6 +502,14 @@ enum { mtpc_contacts_topPeers = 0x70b772a8, mtpc_draftMessageEmpty = 0xba4baec5, mtpc_draftMessage = 0xfd8e711f, + mtpc_messages_featuredStickersNotModified = 0x4ede3cf, + mtpc_messages_featuredStickers = 0xf89d88e5, + mtpc_messages_recentStickersNotModified = 0xb17f890, + mtpc_messages_recentStickers = 0x5ce20970, + mtpc_messages_archivedStickers = 0x4fcba9c8, + mtpc_messages_stickerSetInstallResultSuccess = 0x38641628, + mtpc_messages_stickerSetInstallResultArchive = 0x35e410a8, + mtpc_stickerSetCovered = 0x6410a5d2, mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsgs = 0x3dc4b4f0, mtpc_initConnection = 0x69796de9, @@ -603,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, @@ -623,10 +633,17 @@ enum { mtpc_messages_editMessage = 0xce91e4ca, mtpc_messages_editInlineBotMessage = 0x130c2c85, mtpc_messages_getBotCallbackAnswer = 0xa6e94f04, - mtpc_messages_setBotCallbackAnswer = 0x481c591a, + mtpc_messages_setBotCallbackAnswer = 0xc927d44b, mtpc_messages_getPeerDialogs = 0x2d9776b9, mtpc_messages_saveDraft = 0xbc39e14b, mtpc_messages_getAllDrafts = 0x6a3f8d65, + mtpc_messages_getFeaturedStickers = 0x2dacca4f, + mtpc_messages_readFeaturedStickers = 0xe21cbb, + mtpc_messages_getRecentStickers = 0x99197c2c, + mtpc_messages_saveRecentSticker = 0x348e39bf, + mtpc_messages_clearRecentStickers = 0xab02e5d2, + mtpc_messages_getUnusedStickers = 0x4309d65b, + mtpc_messages_getArchivedStickers = 0x906e241f, mtpc_updates_getState = 0xedd4882a, mtpc_updates_getDifference = 0xa041495, mtpc_updates_getChannelDifference = 0xbb32d7c0, @@ -1352,6 +1369,21 @@ class MTPDcontacts_topPeers; class MTPdraftMessage; class MTPDdraftMessage; +class MTPmessages_featuredStickers; +class MTPDmessages_featuredStickers; + +class MTPmessages_recentStickers; +class MTPDmessages_recentStickers; + +class MTPmessages_archivedStickers; +class MTPDmessages_archivedStickers; + +class MTPmessages_stickerSetInstallResult; +class MTPDmessages_stickerSetInstallResultArchive; + +class MTPstickerSetCovered; +class MTPDstickerSetCovered; + // Boxed types definitions typedef MTPBoxed MTPResPQ; @@ -1526,6 +1558,11 @@ typedef MTPBoxed MTPTopPeerCategory; typedef MTPBoxed MTPTopPeerCategoryPeers; typedef MTPBoxed MTPcontacts_TopPeers; typedef MTPBoxed MTPDraftMessage; +typedef MTPBoxed MTPmessages_FeaturedStickers; +typedef MTPBoxed MTPmessages_RecentStickers; +typedef MTPBoxed MTPmessages_ArchivedStickers; +typedef MTPBoxed MTPmessages_StickerSetInstallResult; +typedef MTPBoxed MTPStickerSetCovered; // Type classes definitions @@ -9531,6 +9568,179 @@ 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; + +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; + +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; + +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 { @@ -10123,11 +10333,12 @@ class MTPDinputDocumentFileLocation : public mtpDataImpl { @@ -12267,7 +12478,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; @@ -12290,6 +12501,7 @@ public: MTPint vsaved_gifs_limit; MTPint vedit_time_limit; MTPint vrating_e_decay; + MTPint vstickers_recent_limit; MTPVector vdisabled_features; }; @@ -12550,7 +12762,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; @@ -12560,6 +12772,7 @@ public: MTPint vsize; MTPPhotoSize vthumb; MTPint vdc_id; + MTPint vversion; MTPVector vattributes; }; @@ -13049,8 +13262,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)); } @@ -13059,14 +13273,18 @@ 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, 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; }; class MTPDinputStickerSetID : public mtpDataImpl { @@ -13094,7 +13312,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), @@ -13103,7 +13321,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() { @@ -14274,22 +14492,25 @@ public: enum class Flag : int32 { f_alert = (1 << 1), f_message = (1 << 0), + f_url = (1 << 2), - MAX_FIELD = (1 << 1), + MAX_FIELD = (1 << 2), }; 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 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 { @@ -14411,6 +14632,61 @@ 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; +}; + +class MTPDmessages_recentStickers : public mtpDataImpl { +public: + MTPDmessages_recentStickers() { + } + MTPDmessages_recentStickers(MTPint _hash, const MTPVector &_stickers) : vhash(_hash), vstickers(_stickers) { + } + + MTPint vhash; + 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; +}; + +class MTPDstickerSetCovered : public mtpDataImpl { +public: + MTPDstickerSetCovered() { + } + MTPDstickerSetCovered(const MTPStickerSet &_set, const MTPDocument &_cover) : vset(_set), vcover(_cover) { + } + + MTPStickerSet vset; + MTPDocument vcover; +}; + // RPC methods class MTPreq_pq { // RPC method 'req_pq' @@ -19156,32 +19432,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: @@ -19191,7 +19467,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)) { } }; @@ -20153,29 +20429,32 @@ public: enum class Flag : int32 { f_alert = (1 << 1), f_message = (1 << 0), + f_url = (1 << 2), - MAX_FIELD = (1 << 1), + MAX_FIELD = (1 << 2), }; 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 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; @@ -20184,11 +20463,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; @@ -20203,7 +20484,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)) { } }; @@ -20344,6 +20625,269 @@ 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 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_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() { + } + 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 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() { @@ -22357,8 +22901,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); @@ -22885,6 +23429,12 @@ 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 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)); } @@ -22933,8 +23483,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)); @@ -23011,8 +23561,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)); @@ -23209,8 +23759,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, 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); @@ -23476,8 +24026,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)); @@ -23524,6 +24074,30 @@ 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)); + } + 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)); + } + 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)); + } + inline static MTPstickerSetCovered new_stickerSetCovered(const MTPStickerSet &_set, const MTPDocument &_cover) { + return MTPstickerSetCovered(new MTPDstickerSetCovered(_set, _cover)); + } }; } // namespace internal @@ -25190,7 +25764,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; @@ -25220,6 +25794,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"); } @@ -25241,6 +25816,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; } } @@ -25264,8 +25840,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 { @@ -28741,6 +29317,8 @@ 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; + case mtpc_updateRecentStickers: _type = cons; break; default: throw mtpErrorUnexpected(cons, "MTPupdate"); } } @@ -29074,6 +29652,8 @@ 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; + case mtpc_updateRecentStickers: break; default: throw mtpErrorBadTypeId(type, "MTPupdate"); } } @@ -29321,6 +29901,12 @@ 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 MTPupdate MTP_updateRecentStickers() { + return MTP::internal::TypeCreator::new_updateRecentStickers(); +} inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) { } @@ -29850,7 +30436,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; @@ -29880,6 +30466,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 { @@ -29904,12 +30491,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()) { @@ -30630,7 +31218,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; @@ -30657,6 +31245,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"); @@ -30677,6 +31266,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; } @@ -30695,8 +31285,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()) { @@ -32044,7 +32634,7 @@ inline uint32 MTPchatInvite::innerLength() const { } case mtpc_chatInvite: { const MTPDchatInvite &v(c_chatInvite()); - return v.vflags.innerLength() + v.vtitle.innerLength(); + return v.vflags.innerLength() + v.vtitle.innerLength() + v.vphoto.innerLength() + v.vparticipants_count.innerLength() + (v.has_participants() ? v.vparticipants.innerLength() : 0); } } return 0; @@ -32066,6 +32656,9 @@ inline void MTPchatInvite::read(const mtpPrime *&from, const mtpPrime *end, mtpT MTPDchatInvite &v(_chatInvite()); 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"); } @@ -32080,6 +32673,9 @@ inline void MTPchatInvite::write(mtpBuffer &to) const { const MTPDchatInvite &v(c_chatInvite()); 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; } } @@ -32098,8 +32694,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, MTPint _participants_count, const MTPVector &_participants) { + return MTP::internal::TypeCreator::new_chatInvite(_flags, _title, _photo, _participants_count, _participants); } inline uint32 MTPinputStickerSet::innerLength() const { @@ -34481,7 +35077,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; @@ -34493,17 +35089,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()) { @@ -34844,6 +35442,217 @@ 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 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 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 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)); } diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp index 9c58ddca0..a6df50772 100644 --- a/Telegram/SourceFiles/profile/profile_cover.cpp +++ b/Telegram/SourceFiles/profile/profile_cover.cpp @@ -467,7 +467,7 @@ void CoverWidget::onOnlineCountUpdated(int onlineCount) { } void CoverWidget::onSendMessage() { - Ui::showPeerHistory(_peer, ShowAtUnreadMsgId); + Ui::showPeerHistory(_peer, ShowAtUnreadMsgId, Ui::ShowWay::Forward); } void CoverWidget::onShareContact() { diff --git a/Telegram/SourceFiles/serialize/serialize_document.cpp b/Telegram/SourceFiles/serialize/serialize_document.cpp index 73823edf5..b83f420f3 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 >= 9061) { + stream >> version; + } else { + version = 0; + } stream >> name >> mime >> dc >> size; stream >> width >> height; stream >> type; @@ -87,7 +93,7 @@ DocumentData *Document::readFromStreamHelper(QDataStream &stream, const StickerS 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; } @@ -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 b0ed77282..44ad8cd2f 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/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index cd051bcf4..c6bb3ac19 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 d88df93c8..4d125b4a6 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(); diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 5575db300..0f2be68a5 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -889,13 +889,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_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); + return !(it->flags & MTPDstickerSet::Flag::f_archived) && (it->flags & MTPDstickerSet::Flag::f_installed); } } } break; @@ -1095,10 +1095,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) { @@ -1107,15 +1108,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) { @@ -1396,7 +1397,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))); @@ -1537,6 +1538,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 4e7ed2fab..2a88d23c8 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/flatbutton.cpp b/Telegram/SourceFiles/ui/flatbutton.cpp index 365e5297e..df5a762be 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() { diff --git a/Telegram/SourceFiles/ui/images.h b/Telegram/SourceFiles/ui/images.h index 2a2ca3b2d..ed97d9247 100644 --- a/Telegram/SourceFiles/ui/images.h +++ b/Telegram/SourceFiles/ui/images.h @@ -487,8 +487,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/SourceFiles/ui/text/text.h b/Telegram/SourceFiles/ui/text/text.h index e407b4fc2..02df17957 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/SourceFiles/window/top_bar_widget.cpp b/Telegram/SourceFiles/window/top_bar_widget.cpp index 7218dfa8d..fdc290a8b 100644 --- a/Telegram/SourceFiles/window/top_bar_widget.cpp +++ b/Telegram/SourceFiles/window/top_bar_widget.cpp @@ -228,7 +228,7 @@ void TopBarWidget::showAll() { } } if (h && !o && _clearSelection->isHidden()) { - if (Adaptive::OneColumn()) { + if (Adaptive::OneColumn() || !App::main()->stackIsEmpty()) { _info->setPeer(h); _info->show(); } else { diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index 474bffb8e..ff510d164 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -1240,6 +1240,7 @@ + @@ -1528,6 +1529,7 @@ + @@ -3030,6 +3032,7 @@ Compiling style %(Identity)... + diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 61425a2d4..3ef0c488f 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -1446,6 +1446,9 @@ GeneratedFiles\Release + + GeneratedFiles\styles + @@ -1727,6 +1730,9 @@ SourceFiles\ui\buttons + + GeneratedFiles\styles + @@ -2122,10 +2128,13 @@ SourceFiles\media\view + + SourceFiles\boxes + Resources\winrc - \ No newline at end of file + diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index 624061e50..a1d6e7c93 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -2531,7 +2531,7 @@ SDKROOT = macosx; SYMROOT = ./../Mac; TDESKTOP_MAJOR_VERSION = 0.9; - TDESKTOP_VERSION = 0.9.60; + TDESKTOP_VERSION = 0.9.61; }; name = Release; }; @@ -2672,7 +2672,7 @@ SDKROOT = macosx; SYMROOT = ./../Mac; TDESKTOP_MAJOR_VERSION = 0.9; - TDESKTOP_VERSION = 0.9.60; + TDESKTOP_VERSION = 0.9.61; }; name = Debug; }; diff --git a/Telegram/build/version b/Telegram/build/version index 1921f28f9..00c77ce37 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,6 +1,6 @@ -AppVersion 9060 +AppVersion 9061 AppVersionStrMajor 0.9 -AppVersionStrSmall 0.9.60 -AppVersionStr 0.9.60 -AlphaChannel 1 +AppVersionStrSmall 0.9.61 +AppVersionStr 0.9.61 +AlphaChannel 0 BetaVersion 0