diff --git a/Telegram/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index 7401aa08b..6f6eec6ef 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -110,7 +110,7 @@ storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; userEmpty#d3bc4b7a id:long = User; -user#3ff6ecb0 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; +user#3ff6ecb0 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#82d1f706 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; @@ -582,7 +582,7 @@ messages.stickerSetNotModified#d3f924eb = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; -botInfo#cc8ba4d7 flags:# user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo commands:flags.2?Vector menu_button:flags.3?BotMenuButton = BotInfo; +botInfo#8f300b57 flags:# user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index bb0b8eba2..6e464eed1 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -450,6 +450,11 @@ void ApiWrap::sendMessageFail( ? tr::lng_error_noforwards_channel(tr::now) : tr::lng_error_noforwards_group(tr::now) }, .duration = kJoinErrorDuration }); + } else if (error.type() == qstr("PREMIUM_ACCOUNT_REQUIRED")) { + Ui::ShowMultilineToast({ + .text = { u"Premium sticker."_q }, + .duration = kJoinErrorDuration, + }); } if (const auto item = _session->data().message(itemId)) { Assert(randomId != 0); diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 3fabde796..faa5ce058 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -465,7 +465,8 @@ bool DocumentData::checkWallPaperProperties() { void DocumentData::updateThumbnails( const InlineImageLocation &inlineThumbnail, const ImageWithLocation &thumbnail, - const ImageWithLocation &videoThumbnail) { + const ImageWithLocation &videoThumbnail, + bool isPremiumSticker) { if (!inlineThumbnail.bytes.isEmpty() && _inlineThumbnailBytes.isEmpty()) { _inlineThumbnailBytes = inlineThumbnail.bytes; @@ -475,6 +476,11 @@ void DocumentData::updateThumbnails( _flags &= ~Flag::InlineThumbnailIsPath; } } + if (isPremiumSticker) { + _flags |= Flag::PremiumSticker; + } else { + _flags &= ~Flag::PremiumSticker; + } Data::UpdateCloudFile( _thumbnail, thumbnail, @@ -511,6 +517,10 @@ bool DocumentData::isPatternWallPaperSVG() const { return isWallPaper() && hasMimeType(qstr("application/x-tgwallpattern")); } +bool DocumentData::isPremiumSticker() const { + return (_flags & Flag::PremiumSticker); +} + bool DocumentData::hasThumbnail() const { return _thumbnail.location.valid(); } diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 9b648527c..23145b569 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -78,7 +78,6 @@ struct StickerData : public DocumentAdditionalData { struct SongData : public DocumentAdditionalData { int32 duration = 0; QString title, performer; - }; struct VoiceData : public DocumentAdditionalData { @@ -172,6 +171,7 @@ public: [[nodiscard]] bool isPatternWallPaper() const; [[nodiscard]] bool isPatternWallPaperPNG() const; [[nodiscard]] bool isPatternWallPaperSVG() const; + [[nodiscard]] bool isPremiumSticker() const; [[nodiscard]] bool hasThumbnail() const; [[nodiscard]] bool thumbnailLoading() const; @@ -190,7 +190,8 @@ public: void updateThumbnails( const InlineImageLocation &inlineThumbnail, const ImageWithLocation &thumbnail, - const ImageWithLocation &videoThumbnail); + const ImageWithLocation &videoThumbnail, + bool isPremiumSticker); [[nodiscard]] QByteArray inlineThumbnailBytes() const { return _inlineThumbnailBytes; @@ -279,6 +280,7 @@ private: HasAttachedStickers = 0x040, InlineThumbnailIsPath = 0x080, ForceToCache = 0x100, + PremiumSticker = 0x200, }; using Flags = base::flags; friend constexpr bool is_flag_type(Flag) { return true; }; diff --git a/Telegram/SourceFiles/data/data_download_manager.cpp b/Telegram/SourceFiles/data/data_download_manager.cpp index f2d248e71..f33693b58 100644 --- a/Telegram/SourceFiles/data/data_download_manager.cpp +++ b/Telegram/SourceFiles/data/data_download_manager.cpp @@ -743,6 +743,7 @@ void DownloadManager::generateEntry( InlineImageLocation(), // inlineThumbnail ImageWithLocation(), // thumbnail ImageWithLocation(), // videoThumbnail + false, // isPremiumSticker 0, // dc id.size); document->setLocation(Core::FileLocation(info)); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 98af6caf8..efc9d8dbb 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -2672,7 +2672,8 @@ not_null Session::processDocument( qs(data.vmime_type()), InlineImageLocation(), thumbnail, - ImageWithLocation(), + ImageWithLocation(), // videoThumbnail + false, // isPremiumSticker data.vdc_id().v, data.vsize().v); }, [&](const MTPDdocumentEmpty &data) { @@ -2690,6 +2691,7 @@ not_null Session::document( const InlineImageLocation &inlineThumbnail, const ImageWithLocation &thumbnail, const ImageWithLocation &videoThumbnail, + bool isPremiumSticker, int32 dc, int32 size) { const auto result = document(id); @@ -2703,6 +2705,7 @@ not_null Session::document( inlineThumbnail, thumbnail, videoThumbnail, + isPremiumSticker, dc, size); return result; @@ -2771,6 +2774,7 @@ DocumentData *Session::documentFromWeb( InlineImageLocation(), ImageWithLocation{ .location = thumbnailLocation }, ImageWithLocation{ .location = videoThumbnailLocation }, + false, // isPremiumSticker session().mainDcId(), int32(0)); // data.vsize().v result->setWebLocation(WebFileLocation( @@ -2793,6 +2797,7 @@ DocumentData *Session::documentFromWeb( InlineImageLocation(), ImageWithLocation{ .location = thumbnailLocation }, ImageWithLocation{ .location = videoThumbnailLocation }, + false, // isPremiumSticker session().mainDcId(), int32(0)); // data.vsize().v result->setContentUrl(qs(data.vurl())); @@ -2820,6 +2825,8 @@ void Session::documentApplyFields( const auto videoThumbnail = videoThumbnailSize ? Images::FromVideoSize(_session, data, *videoThumbnailSize) : ImageWithLocation(); + const auto isPremiumSticker = videoThumbnailSize + && (videoThumbnailSize->c_videoSize().vtype().v == "fp"); documentApplyFields( document, data.vaccess_hash().v, @@ -2830,6 +2837,7 @@ void Session::documentApplyFields( inlineThumbnail, prepared, videoThumbnail, + isPremiumSticker, data.vdc_id().v, data.vsize().v); } @@ -2844,6 +2852,7 @@ void Session::documentApplyFields( const InlineImageLocation &inlineThumbnail, const ImageWithLocation &thumbnail, const ImageWithLocation &videoThumbnail, + bool isPremiumSticker, int32 dc, int32 size) { if (!date) { @@ -2854,7 +2863,8 @@ void Session::documentApplyFields( document->updateThumbnails( inlineThumbnail, thumbnail, - videoThumbnail); + videoThumbnail, + isPremiumSticker); document->size = size; document->setattributes(attributes); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 45ccb1592..a21fe4c64 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -502,6 +502,7 @@ public: const InlineImageLocation &inlineThumbnail, const ImageWithLocation &thumbnail, const ImageWithLocation &videoThumbnail, + bool isPremiumSticker, int32 dc, int32 size); void documentConvert( @@ -753,6 +754,7 @@ private: const InlineImageLocation &inlineThumbnail, const ImageWithLocation &thumbnail, const ImageWithLocation &videoThumbnail, + bool isPremiumSticker, int32 dc, int32 size); DocumentData *documentFromWeb( diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index bdb94f1dd..817d51468 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -46,6 +46,7 @@ enum class UserDataFlag { CanPinMessages = (1 << 11), DiscardMinPhoto = (1 << 12), Self = (1 << 13), + Premium = (1 << 14), }; inline constexpr bool is_flag_type(UserDataFlag) { return true; }; using UserDataFlags = base::flags; @@ -96,6 +97,9 @@ public: [[nodiscard]] bool isFake() const { return flags() & UserDataFlag::Fake; } + [[nodiscard]] bool isPremium() const { + return flags() & UserDataFlag::Premium; + } [[nodiscard]] bool isBotInlineGeo() const { return flags() & UserDataFlag::BotInlineGeo; } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index fc5d26c86..1c4750fd7 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6680,9 +6680,10 @@ bool HistoryWidget::sendExistingDocument( Ui::MakeInformBox(*error), Ui::LayerOption::KeepOther); return false; - } else if (!_peer || !_peer->canWrite()) { - return false; - } else if (showSlowmodeError()) { + } else if (!_peer + || !_peer->canWrite() + || showSlowmodeError() + || ShowSendPremiumError(controller(), document)) { return false; } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index 642de93a3..c8ad45411 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -109,6 +109,7 @@ enum class FilterType { InlineImageLocation(), ImageWithLocation(), ImageWithLocation(), + false, // isPremiumSticker owner->session().mainDcId(), int32(0)); } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index f9148fda2..1513acdbc 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -1090,7 +1090,8 @@ bool RepliesWidget::sendExistingDocument( Ui::MakeInformBox(*error), Ui::LayerOption::KeepOther); return false; - } else if (showSlowmodeError()) { + } else if (showSlowmodeError() + || ShowSendPremiumError(controller(), document)) { return false; } diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index bb8a69dd2..db8bb3be2 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -685,6 +685,8 @@ bool ScheduledWidget::sendExistingDocument( Ui::MakeInformBox(*error), Ui::LayerOption::KeepOther); return false; + } else if (ShowSendPremiumError(controller(), document)) { + return false; } Api::SendExistingDocument( diff --git a/Telegram/SourceFiles/platform/mac/touchbar/items/mac_scrubber_item.mm b/Telegram/SourceFiles/platform/mac/touchbar/items/mac_scrubber_item.mm index 6e2c64079..5bafdc921 100644 --- a/Telegram/SourceFiles/platform/mac/touchbar/items/mac_scrubber_item.mm +++ b/Telegram/SourceFiles/platform/mac/touchbar/items/mac_scrubber_item.mm @@ -462,6 +462,8 @@ void AppendEmojiPacks( if (const auto error = RestrictionToSendStickers(_controller)) { _controller->show(Ui::MakeInformBox(*error)); return true; + } else if (ShowSendPremiumError(_controller, document)) { + return true; } Api::SendExistingDocument( Api::MessageToSend( diff --git a/Telegram/SourceFiles/storage/serialize_document.cpp b/Telegram/SourceFiles/storage/serialize_document.cpp index fef3bdd21..ea944975a 100644 --- a/Telegram/SourceFiles/storage/serialize_document.cpp +++ b/Telegram/SourceFiles/storage/serialize_document.cpp @@ -18,7 +18,7 @@ namespace Serialize { namespace { constexpr auto kVersionTag = int32(0x7FFFFFFF); -constexpr auto kVersion = 3; +constexpr auto kVersion = 4; enum StickerSetType { StickerSetTypeEmpty = 0, @@ -45,6 +45,7 @@ void Document::writeToStream(QDataStream &stream, DocumentData *document) { } } stream << qint32(document->getDuration()); + stream << qint32(document->isPremiumSticker() ? 1 : 0); writeImageLocation(stream, document->thumbnailLocation()); stream << qint32(document->thumbnailByteSize()); writeImageLocation(stream, document->videoThumbnailLocation()); @@ -86,6 +87,7 @@ DocumentData *Document::readFromStreamHelper( } qint32 duration = -1; + qint32 isPremiumSticker = 0; if (type == StickerDocument) { QString alt; qint32 typeOfSet; @@ -116,6 +118,9 @@ DocumentData *Document::readFromStreamHelper( } if (version >= 3) { stream >> duration; + if (version >= 4) { + stream >> isPremiumSticker; + } } } else { stream >> duration; @@ -185,6 +190,7 @@ DocumentData *Document::readFromStreamHelper( .location = *videoThumb, .bytesCount = videoThumbnailByteSize }, + (isPremiumSticker == 1), dc, size); } diff --git a/Telegram/SourceFiles/storage/storage_account.cpp b/Telegram/SourceFiles/storage/storage_account.cpp index 0fccde674..a10ffd5e0 100644 --- a/Telegram/SourceFiles/storage/storage_account.cpp +++ b/Telegram/SourceFiles/storage/storage_account.cpp @@ -2169,8 +2169,9 @@ void Account::importOldRecentStickers() { attributes, mime, InlineImageLocation(), - ImageWithLocation(), - ImageWithLocation(), + ImageWithLocation(), // thumbnail + ImageWithLocation(), // videoThumbnail + false, // isPremiumSticker dc, size); if (!doc->sticker()) { diff --git a/Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp b/Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp index f6203963e..cb2a6a203 100644 --- a/Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp +++ b/Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp @@ -100,12 +100,13 @@ void LoadAndApplyThumbnail( document->updateThumbnails( InlineImageLocation(), imageWithLocation, - ImageWithLocation{ .location = ImageLocation() }); + ImageWithLocation{ .location = ImageLocation() }, + document->isPremiumSticker()); document->loadThumbnail(Data::FileOrigin()); } -} +} // namespace void LoadThumbnailFromExternal(not_null document) { const auto songData = document->song(); diff --git a/Telegram/SourceFiles/window/section_widget.cpp b/Telegram/SourceFiles/window/section_widget.cpp index 79f91e4b9..1ebb4aa5b 100644 --- a/Telegram/SourceFiles/window/section_widget.cpp +++ b/Telegram/SourceFiles/window/section_widget.cpp @@ -10,7 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "ui/ui_utility.h" #include "ui/chat/chat_theme.h" +#include "ui/toasts/common_toasts.h" #include "data/data_peer.h" +#include "data/data_user.h" +#include "data/data_document.h" #include "data/data_changes.h" #include "data/data_session.h" #include "data/data_cloud_themes.h" @@ -322,4 +325,17 @@ auto ChatThemeValueFromPeer( }); } +bool ShowSendPremiumError( + not_null controller, + not_null document) { + if (!document->isPremiumSticker() + || document->session().user()->isPremium()) { + return false; + } + Ui::ShowMultilineToast({ + .text = { u"Premium sticker."_q }, + }); + return true; +} + } // namespace Window diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index cc9f692d2..6a43aaea2 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -205,4 +205,8 @@ private: not_null peer) -> rpl::producer>; +[[nodiscard]] bool ShowSendPremiumError( + not_null controller, + not_null document); + } // namespace Window