diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index ffa80a5173..6f9bafd8c2 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -368,6 +368,8 @@ PRIVATE chat_helpers/stickers_emoji_image_loader.h chat_helpers/stickers_emoji_pack.cpp chat_helpers/stickers_emoji_pack.h + chat_helpers/stickers_gift_box_pack.cpp + chat_helpers/stickers_gift_box_pack.h chat_helpers/stickers_dice_pack.cpp chat_helpers/stickers_dice_pack.h chat_helpers/stickers_list_footer.cpp @@ -644,6 +646,8 @@ PRIVATE history/view/media/history_view_photo.cpp history/view/media/history_view_poll.h history/view/media/history_view_poll.cpp + history/view/media/history_view_service_media_gift.h + history/view/media/history_view_service_media_gift.cpp history/view/media/history_view_slot_machine.h history/view/media/history_view_slot_machine.cpp history/view/media/history_view_sticker.h diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 8a7049cbdb..34b6a79675 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1456,6 +1456,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_action_proximity_distance_km#one" = "{count} km"; "lng_action_proximity_distance_km#other" = "{count} km"; "lng_action_webview_data_done" = "You have just successfully transferred data from the «{text}» button to the bot."; +"lng_action_gift_received" = "{user} sent you a gift for {cost}"; + +"lng_premium_gift_duration_months#one" = "for {count} month"; +"lng_premium_gift_duration_months#other" = "for {count} months"; +"lng_premium_gift_duration_years#one" = "for {count} year"; +"lng_premium_gift_duration_years#other" = "for {count} years"; "lng_ttl_photo_received" = "{from} sent you a self-destructing photo. Please view it on your mobile."; "lng_ttl_photo_sent" = "You sent a self-destructing photo."; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp index 31d671c4df..23ea9d72eb 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp @@ -65,8 +65,7 @@ void DicePack::applySet(const MTPDmessages_stickerSet &data) { auto index = 0; auto documents = base::flat_map>(); for (const auto &sticker : data.vdocuments().v) { - const auto document = _session->data().processDocument( - sticker); + const auto document = _session->data().processDocument(sticker); if (document->sticker()) { if (isSlotMachine) { _map.emplace(index++, document); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp new file mode 100644 index 0000000000..5bfa80acb9 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp @@ -0,0 +1,86 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "chat_helpers/stickers_gift_box_pack.h" + +#include "apiwrap.h" +#include "data/data_document.h" +#include "data/data_session.h" +#include "main/main_session.h" + +namespace Stickers { + +GiftBoxPack::GiftBoxPack(not_null session) +: _session(session) +, _localMonths({ 3, 6, 12 }) { +} + +GiftBoxPack::~GiftBoxPack() = default; + +DocumentData *GiftBoxPack::lookup(int months) const { + const auto it = ranges::lower_bound(_localMonths, months); + if (it == begin(_localMonths)) { + return _documents.empty() ? nullptr : _documents[0]; + } + const auto left = *(it - 1); + const auto right = *it; + const auto shift = (std::abs(months - left) < std::abs(months - right)) + ? -1 + : 0; + const auto index = int(std::distance(begin(_localMonths), it - shift)); + return (index >= _documents.size()) ? nullptr : _documents[index]; +} + +void GiftBoxPack::load() { + if (_requestId || !_documents.empty()) { + return; + } + _requestId = _session->api().request(MTPmessages_GetStickerSet( + MTP_inputStickerSetPremiumGifts(), + MTP_int(0) // Hash. + )).done([=](const MTPmessages_StickerSet &result) { + result.match([&](const MTPDmessages_stickerSet &data) { + applySet(data); + }, [](const MTPDmessages_stickerSetNotModified &) { + LOG(("API Error: Unexpected messages.stickerSetNotModified.")); + }); + }).fail([=] { + _requestId = 0; + }).send(); +} + +void GiftBoxPack::applySet(const MTPDmessages_stickerSet &data) { + _setId = data.vset().data().vid().v; + auto documents = base::flat_map>(); + for (const auto &sticker : data.vdocuments().v) { + const auto document = _session->data().processDocument(sticker); + if (document->sticker()) { + documents.emplace(document->id, document); + } + } + for (const auto &pack : data.vpacks().v) { + pack.match([&](const MTPDstickerPack &data) { + const auto emoji = qs(data.vemoticon()); + if (emoji.isEmpty()) { + return; + } + for (const auto &id : data.vdocuments().v) { + if (const auto document = documents.take(id.v)) { + _documents.push_back(*document); + } + } + }); + } +} + +bool GiftBoxPack::isGiftSticker(not_null document) const { + return document->sticker() + ? (document->sticker()->set.id == _setId) + : false; +} + +} // namespace Stickers diff --git a/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.h new file mode 100644 index 0000000000..aea2f25366 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.h @@ -0,0 +1,41 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +class DocumentData; + +namespace Main { +class Session; +} // namespace Main + +namespace Stickers { + +class GiftBoxPack final { +public: + explicit GiftBoxPack(not_null session); + ~GiftBoxPack(); + + void load(); + [[nodiscard]] DocumentData *lookup(int months) const; + + [[nodiscard]] bool isGiftSticker(not_null document) const; + +private: + using SetId = uint64; + void applySet(const MTPDmessages_stickerSet &data); + + const not_null _session; + const std::vector _localMonths; + + std::vector _documents; + SetId _setId = 0; + mtpRequestId _requestId = 0; + +}; + +} // namespace Stickers diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index d15743ac3f..1d45fdc90c 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_theme_document.h" #include "history/view/media/history_view_slot_machine.h" #include "history/view/media/history_view_dice.h" +#include "history/view/media/history_view_service_media_gift.h" #include "dialogs/ui/dialogs_message_view.h" #include "ui/image/image.h" #include "ui/text/format_song_document_name.h" @@ -1718,4 +1719,60 @@ ClickHandlerPtr MediaDice::MakeHandler( }); } +MediaGiftBox::MediaGiftBox(not_null parent, int months) +: Media(parent) +, _months(months) { +} + +std::unique_ptr MediaGiftBox::clone(not_null parent) { + return std::make_unique(parent, _months); +} + +int MediaGiftBox::months() const { + return _months; +} + +bool MediaGiftBox::allowsRevoke(TimeId now) const { + return false; +} + +TextWithEntities MediaGiftBox::notificationText() const { + return {}; +} + +QString MediaGiftBox::pinnedTextSubstring() const { + return {}; +} + +TextForMimeData MediaGiftBox::clipboardText() const { + return {}; +} + +bool MediaGiftBox::forceForwardedInfo() const { + return false; +} + +bool MediaGiftBox::updateInlineResultMedia(const MTPMessageMedia &media) { + return false; +} + +bool MediaGiftBox::updateSentMedia(const MTPMessageMedia &media) { + return false; +} + +std::unique_ptr MediaGiftBox::createView( + not_null message, + not_null realParent, + HistoryView::Element *replacing) { + return std::make_unique(message, this); +} + +bool MediaGiftBox::activated() const { + return _activated; +} + +void MediaGiftBox::setActivated(bool activated) { + _activated = activated; +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index 7c4c83b7aa..36102f2b0c 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -475,6 +475,36 @@ private: }; +class MediaGiftBox final : public Media { +public: + MediaGiftBox(not_null parent, int months); + + std::unique_ptr clone(not_null parent) override; + + [[nodiscard]] int months() const; + + [[nodiscard]] bool activated() const; + void setActivated(bool activated); + + bool allowsRevoke(TimeId now) const override; + TextWithEntities notificationText() const override; + QString pinnedTextSubstring() const override; + TextForMimeData clipboardText() const override; + bool forceForwardedInfo() const override; + + bool updateInlineResultMedia(const MTPMessageMedia &media) override; + bool updateSentMedia(const MTPMessageMedia &media) override; + std::unique_ptr createView( + not_null message, + not_null realParent, + HistoryView::Element *replacing = nullptr) override; + +private: + int _months = 0; + bool _activated = false; + +}; + [[nodiscard]] TextForMimeData WithCaptionClipboardText( const QString &attachType, TextForMimeData &&caption); diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index 92bde18e04..db100d6a71 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "history/history_service.h" +#include "chat_helpers/stickers_gift_box_pack.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "main/main_session.h" @@ -614,8 +615,21 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { return result; }; - auto prepareGiftPremium = [](const MTPDmessageActionGiftPremium &action) { - return PreparedText{ .text = { "gift premium" }, }; // #TODO gifts + auto prepareGiftPremium = [&]( + const MTPDmessageActionGiftPremium &action) { + history()->session().giftBoxStickersPacks().load(); + const auto amount = action.vamount().v; + const auto currency = qs(action.vcurrency()); + auto result = PreparedText{}; + result.links.push_back(fromLink()); + result.text = tr::lng_action_gift_received( + tr::now, + lt_user, + fromLinkText(), // Link 1. + lt_cost, + { Ui::FillAmountAndCurrency(amount, currency) }, + Ui::Text::WithEntities); + return result; }; const auto messageText = action.match([&]( @@ -745,6 +759,8 @@ void HistoryService::applyAction(const MTPMessageAction &action) { channel->mgInfo->joinedMessageFound = true; } } + }, [&](const MTPDmessageActionGiftPremium &data) { + _media = std::make_unique(this, data.vmonths().v); }, [](const auto &) { }); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_service_media_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_service_media_gift.cpp new file mode 100644 index 0000000000..f41d83e19b --- /dev/null +++ b/Telegram/SourceFiles/history/view/media/history_view_service_media_gift.cpp @@ -0,0 +1,281 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "history/view/media/history_view_service_media_gift.h" + +#include "chat_helpers/stickers_gift_box_pack.h" +#include "core/click_handler_types.h" // ClickHandlerContext +#include "data/data_document.h" +#include "data/data_media_types.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/history_item_components.h" +#include "history/view/history_view_cursor_state.h" +#include "history/view/history_view_element.h" +#include "lang/lang_keys.h" +#include "lottie/lottie_common.h" +#include "lottie/lottie_single_player.h" +#include "main/main_session.h" +#include "settings/settings_premium.h" // Settings::ShowPremium +#include "ui/chat/chat_style.h" +#include "ui/effects/ripple_animation.h" +#include "window/window_session_controller.h" +#include "styles/style_chat.h" +#include "styles/style_premium.h" +#include "styles/style_settings.h" + +namespace HistoryView { +namespace { + +[[nodiscard]] QString FormatGiftMonths(int months) { + return (months < 12) + ? tr::lng_premium_gift_duration_months(tr::now, lt_count, months) + : tr::lng_premium_gift_duration_years( + tr::now, + lt_count, + std::round(months / 12.)); +} + +} // namespace + +MediaGift::MediaGift( + not_null parent, + not_null gift) +: Media(parent) +, _parent(parent) +, _gift(gift) +, _size(st::msgServiceGiftBoxSize) +, _innerSize(_size - QSize(0, st::msgServiceGiftBoxTopSkip)) +, _button([&] { + auto result = Button(); + result.repaint = [=] { repaint(); }; + result.text.setText( + st::semiboldTextStyle, + tr::lng_sticker_premium_view(tr::now)); + + const auto height = st::msgServiceGiftBoxButtonHeight; + const auto &margins = st::msgServiceGiftBoxButtonMargins; + result.size = QSize( + result.text.maxWidth() + + height + + margins.left() + + margins.right(), + height); + + result.link = std::make_shared([=]( + ClickContext context) { + const auto my = context.other.value(); + if (const auto controller = my.sessionWindow.get()) { + Settings::ShowPremium(controller, QString()); + } + }); + + return result; +}()) +, _title( + st::settingsSubsectionTitle.style, + tr::lng_premium_summary_title(tr::now)) +, _subtitle( + st::premiumPreviewAbout.style, + FormatGiftMonths(gift->months())) { +} + +MediaGift::~MediaGift() = default; + +QSize MediaGift::countOptimalSize() { + return _size; +} + +QSize MediaGift::countCurrentSize(int newWidth) { + return _size; +} + +void MediaGift::draw(Painter &p, const PaintContext &context) const { + p.translate(0, st::msgServiceGiftBoxTopSkip); + + PainterHighQualityEnabler hq(p); + const auto radius = st::msgServiceGiftBoxRadius; + p.setPen(Qt::NoPen); + p.setBrush(context.st->msgServiceBg()); + p.drawRoundedRect(QRect(QPoint(), _innerSize), radius, radius); + + { + p.setPen(context.st->msgServiceFg()); + const auto &padding = st::msgServiceGiftBoxTitlePadding; + const auto titleTop = padding.top(); + _title.draw(p, 0, titleTop, _innerSize.width(), style::al_top); + const auto subtitleTop = titleTop + + _title.minHeight() + + padding.bottom(); + _subtitle.draw(p, 0, subtitleTop, _innerSize.width(), style::al_top); + } + + { + const auto position = buttonRect().topLeft(); + p.translate(position); + + p.setPen(Qt::NoPen); + p.setBrush(context.st->msgServiceBg()); // ? + _button.drawBg(p); + p.setPen(context.st->msgServiceFg()); + if (_button.ripple) { + const auto opacity = p.opacity(); + p.setOpacity(st::historyPollRippleOpacity); + _button.ripple->paint( + p, + 0, + 0, + width(), + &context.messageStyle()->msgWaveformInactive->c); + p.setOpacity(opacity); + } + _button.text.draw( + p, + 0, + (_button.size.height() - _button.text.minHeight()) / 2, + _button.size.width(), + style::al_top); + + p.translate(-position); + } + + if (_sticker) { + _sticker->draw(p, context, stickerRect()); + } else { + ensureStickerCreated(); + } + + p.translate(0, -st::msgServiceGiftBoxTopSkip); +} + +TextState MediaGift::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); + { + const auto rect = buttonRect(); + if (rect.contains(point)) { + result.link = _button.link; + _button.lastPoint = point - rect.topLeft(); + } + } + return result; +} + +bool MediaGift::toggleSelectionByHandlerClick( + const ClickHandlerPtr &p) const { + return false; +} + +bool MediaGift::dragItemByHandler(const ClickHandlerPtr &p) const { + return false; +} + +void MediaGift::clickHandlerPressedChanged( + const ClickHandlerPtr &handler, + bool pressed) { + if (!handler) { + return; + } + + if (handler == _button.link) { + _button.toggleRipple(pressed); + } +} + +DocumentData *MediaGift::getDocument() const { + return _sticker ? _sticker->document() : nullptr; +} + +void MediaGift::stickerClearLoopPlayed() { + if (_sticker) { + _sticker->stickerClearLoopPlayed(); + } +} + +std::unique_ptr MediaGift::stickerTakeLottie( + not_null data, + const Lottie::ColorReplacements *replacements) { + return _sticker + ? _sticker->stickerTakeLottie(data, replacements) + : nullptr; +} + +bool MediaGift::needsBubble() const { + return false; +} + +bool MediaGift::customInfoLayout() const { + return false; +} + +bool MediaGift::hasHeavyPart() const { + return (_sticker ? _sticker->hasHeavyPart() : false); +} + +void MediaGift::unloadHeavyPart() { + if (_sticker) { + _sticker->unloadHeavyPart(); + } +} + +void MediaGift::ensureStickerCreated() const { + if (_sticker) { + return; + } + const auto &session = _parent->data()->history()->session(); + auto &packs = session.giftBoxStickersPacks(); + if (const auto document = packs.lookup(_gift->months())) { + if (const auto sticker = document->sticker()) { + const auto skipPremiumEffect = false; + _sticker.emplace(_parent, document, skipPremiumEffect, _parent); + _sticker->setDiceIndex(sticker->alt, 1); + _sticker->initSize(); + } + } +} + +QRect MediaGift::buttonRect() const { + const auto &padding = st::msgServiceGiftBoxButtonPadding; + const auto position = QPoint( + (width() - _button.size.width()) / 2, + height() - padding.bottom() - _button.size.height()); + return QRect(position, _button.size); +} + +QRect MediaGift::stickerRect() const { + const auto &padding = st::msgServiceGiftBoxButtonPadding; + const auto &size = st::msgServiceGiftBoxStickerSize; + const auto top = st::msgServiceGiftBoxStickerTop; + return QRect(QPoint((width() - size.width()) / 2, top), size); +} + +void MediaGift::Button::toggleRipple(bool pressed) { + if (pressed) { + const auto linkWidth = size.width(); + const auto linkHeight = size.height(); + if (!ripple) { + const auto drawMask = [&](QPainter &p) { drawBg(p); }; + auto mask = Ui::RippleAnimation::maskByDrawer( + QSize(linkWidth, linkHeight), + false, + drawMask); + ripple = std::make_unique( + st::defaultRippleAnimation, + std::move(mask), + repaint); + } + ripple->add(lastPoint); + } else if (ripple) { + ripple->lastStop(); + } +} + +void MediaGift::Button::drawBg(QPainter &p) const { + const auto radius = size.height() / 2.; + p.drawRoundedRect(0, 0, size.width(), size.height(), radius, radius); +} + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_service_media_gift.h b/Telegram/SourceFiles/history/view/media/history_view_service_media_gift.h new file mode 100644 index 0000000000..d850b805f7 --- /dev/null +++ b/Telegram/SourceFiles/history/view/media/history_view_service_media_gift.h @@ -0,0 +1,89 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "history/view/media/history_view_media.h" +#include "history/view/media/history_view_media_unwrapped.h" +#include "history/view/media/history_view_sticker.h" + +namespace Data { +class MediaGiftBox; +} // namespace Data + +namespace Ui { +class RippleAnimation; +} // namespace Ui + +namespace HistoryView { + +class MediaGift final : public Media { +public: + MediaGift(not_null parent, not_null gift); + ~MediaGift(); + + QSize countOptimalSize() override; + QSize countCurrentSize(int newWidth) override; + + void draw(Painter &p, const PaintContext &context) const override; + TextState textState(QPoint point, StateRequest request) const override; + + [[nodiscard]] bool toggleSelectionByHandlerClick( + const ClickHandlerPtr &p) const override; + [[nodiscard]] bool dragItemByHandler( + const ClickHandlerPtr &p) const override; + + void clickHandlerPressedChanged( + const ClickHandlerPtr &handler, + bool pressed) override; + + DocumentData *getDocument() const override; + + void stickerClearLoopPlayed() override; + std::unique_ptr stickerTakeLottie( + not_null data, + const Lottie::ColorReplacements *replacements) override; + + [[nodiscard]] bool needsBubble() const override; + [[nodiscard]] bool customInfoLayout() const override; + + bool hasHeavyPart() const override; + void unloadHeavyPart() override; + +private: + void ensureStickerCreated() const; + [[nodiscard]] QRect buttonRect() const; + [[nodiscard]] QRect stickerRect() const; + + const not_null _parent; + const not_null _gift; + const QSize &_size; + const QSize _innerSize; + + struct Button { + void drawBg(QPainter &p) const; + void toggleRipple(bool pressed); + + Fn repaint; + + Ui::Text::String text; + QSize size; + + ClickHandlerPtr link; + std::unique_ptr ripple; + + mutable QPoint lastPoint; + } _button; + + Ui::Text::String _title; + Ui::Text::String _subtitle; + + mutable std::optional _sticker; + +}; + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp index fc740e65c8..4757e26c31 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_file_click_handler.h" #include "data/data_file_origin.h" #include "lottie/lottie_single_player.h" +#include "chat_helpers/stickers_gift_box_pack.h" #include "chat_helpers/stickers_lottie.h" #include "styles/style_chat.h" @@ -111,7 +112,12 @@ bool Sticker::isEmojiSticker() const { void Sticker::initSize() { if (isEmojiSticker() || _diceIndex >= 0) { - _size = EmojiSize(); + const auto &session = _data->owner().session(); + if (session.giftBoxStickersPacks().isGiftSticker(_data)) { + _size = st::msgServiceGiftBoxStickerSize; + } else { + _size = EmojiSize(); + } if (_diceIndex > 0) { [[maybe_unused]] bool result = readyToDrawLottie(); } diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index c299c9e537..efcf46887b 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/mtproto_config.h" #include "chat_helpers/stickers_emoji_pack.h" #include "chat_helpers/stickers_dice_pack.h" +#include "chat_helpers/stickers_gift_box_pack.h" #include "inline_bots/bot_attach_web_view.h" #include "storage/file_download.h" #include "storage/download_manager_mtproto.h" @@ -91,6 +92,7 @@ Session::Session( , _user(_data->processUser(user)) , _emojiStickersPack(std::make_unique(this)) , _diceStickersPacks(std::make_unique(this)) +, _giftBoxStickersPacks(std::make_unique(this)) , _sendAsPeers(std::make_unique(this)) , _attachWebView(std::make_unique(this)) , _supportHelper(Support::Helper::Create(this)) diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 383c5acacf..40bf3da7c6 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -51,6 +51,7 @@ struct TermsLock; namespace Stickers { class EmojiPack; class DicePacks; +class GiftBoxPack; } // namespace Stickers; namespace InlineBots { @@ -117,6 +118,9 @@ public: [[nodiscard]] Stickers::DicePacks &diceStickersPacks() const { return *_diceStickersPacks; } + [[nodiscard]] Stickers::GiftBoxPack &giftBoxStickersPacks() const { + return *_giftBoxStickersPacks; + } [[nodiscard]] Data::Session &data() const { return *_data; } @@ -205,6 +209,7 @@ private: // _emojiStickersPack depends on _data. const std::unique_ptr _emojiStickersPack; const std::unique_ptr _diceStickersPacks; + const std::unique_ptr _giftBoxStickersPacks; const std::unique_ptr _sendAsPeers; const std::unique_ptr _attachWebView; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index bc656db83d..d48a8f894f 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -1077,3 +1077,13 @@ searchInChatPeerListItem: PeerListItem(defaultPeerListItem) { searchInChatPeerList: PeerList(defaultPeerList) { item: searchInChatPeerListItem; } + +msgServiceGiftBoxSize: size(206px, 231px); // Plus msgServiceGiftBoxTopSkip. +msgServiceGiftBoxRadius: 12px; +msgServiceGiftBoxTopSkip: 4px; +msgServiceGiftBoxButtonHeight: 32px; +msgServiceGiftBoxButtonMargins: margins(2px, 0px, 2px, 0px); +msgServiceGiftBoxButtonPadding: margins(0px, 17px, 0px, 17px); +msgServiceGiftBoxTitlePadding: margins(0px, 126px, 0px, 2px); +msgServiceGiftBoxStickerTop: -30px; +msgServiceGiftBoxStickerSize: size(150px, 150px);