From 48cf0a4382a64e559ff3d622f18a021ff1fadf36 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 9 Dec 2022 21:35:45 +0400 Subject: [PATCH] Implement suggested profile photo message. --- Telegram/CMakeLists.txt | 8 +- Telegram/Resources/langs/lang.strings | 3 + Telegram/SourceFiles/api/api_peer_photo.cpp | 17 +- Telegram/SourceFiles/api/api_peer_photo.h | 1 + .../SourceFiles/data/data_media_types.cpp | 17 +- Telegram/SourceFiles/data/data_types.h | 3 + Telegram/SourceFiles/data/data_user.cpp | 4 + Telegram/SourceFiles/data/data_user.h | 1 + .../editor/photo_editor_layer_widget.cpp | 3 +- Telegram/SourceFiles/history/history_item.cpp | 33 +- Telegram/SourceFiles/history/history_item.h | 1 + .../view/history_view_service_message.cpp | 84 +++--- .../history/view/media/history_view_media.cpp | 4 + .../history/view/media/history_view_media.h | 1 + .../history/view/media/history_view_photo.h | 3 +- .../view/media/history_view_premium_gift.cpp | 127 ++++++++ .../view/media/history_view_premium_gift.h | 53 ++++ .../view/media/history_view_service_box.cpp | 240 +++++++++++++++ ...edia_gift.h => history_view_service_box.h} | 49 ++- .../media/history_view_service_media_gift.cpp | 282 ------------------ .../media/history_view_userpic_suggestion.cpp | 129 ++++++++ .../media/history_view_userpic_suggestion.h | 53 ++++ Telegram/SourceFiles/ui/chat/chat.style | 6 +- Telegram/SourceFiles/ui/special_buttons.cpp | 2 +- 24 files changed, 768 insertions(+), 356 deletions(-) create mode 100644 Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp create mode 100644 Telegram/SourceFiles/history/view/media/history_view_premium_gift.h create mode 100644 Telegram/SourceFiles/history/view/media/history_view_service_box.cpp rename Telegram/SourceFiles/history/view/media/{history_view_service_media_gift.h => history_view_service_box.h} (63%) delete mode 100644 Telegram/SourceFiles/history/view/media/history_view_service_media_gift.cpp create mode 100644 Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.cpp create mode 100644 Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 8360eefeb5..03d5098118 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -673,8 +673,10 @@ PRIVATE history/view/media/history_view_photo.h history/view/media/history_view_poll.cpp history/view/media/history_view_poll.h - history/view/media/history_view_service_media_gift.cpp - history/view/media/history_view_service_media_gift.h + history/view/media/history_view_premium_gift.cpp + history/view/media/history_view_premium_gift.h + history/view/media/history_view_service_box.cpp + history/view/media/history_view_service_box.h history/view/media/history_view_slot_machine.cpp history/view/media/history_view_slot_machine.h history/view/media/history_view_sticker.cpp @@ -684,6 +686,8 @@ PRIVATE history/view/media/history_view_sticker_player_abstract.h history/view/media/history_view_theme_document.cpp history/view/media/history_view_theme_document.h + history/view/media/history_view_userpic_suggestion.cpp + history/view/media/history_view_userpic_suggestion.h history/view/media/history_view_web_page.cpp history/view/media/history_view_web_page.h history/view/reactions/history_view_reactions.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index e59cc1e443..efb8656613 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1561,6 +1561,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "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_action_gift_received_me" = "You sent to {user} a gift for {cost}"; +"lng_action_suggested_photo_title" = "Suggested Photo"; +"lng_action_suggested_photo_me" = "You suggested {user} to use this photo for their account."; +"lng_action_suggested_photo" = "{user} suggests you to use this photo for your account."; "lng_action_topic_created_inside" = "Topic created"; "lng_action_topic_closed_inside" = "Topic closed"; "lng_action_topic_reopened_inside" = "Topic reopened"; diff --git a/Telegram/SourceFiles/api/api_peer_photo.cpp b/Telegram/SourceFiles/api/api_peer_photo.cpp index c488c7374a..16d9ef4a0f 100644 --- a/Telegram/SourceFiles/api/api_peer_photo.cpp +++ b/Telegram/SourceFiles/api/api_peer_photo.cpp @@ -116,6 +116,17 @@ void PeerPhoto::upload(not_null peer, QImage &&image) { upload(peer, std::move(image), false); } +void PeerPhoto::updateSelf(not_null photo) { + _api.request(MTPphotos_UpdateProfilePhoto( + photo->mtpInput() + )).done([=](const MTPphotos_Photo &result) { + result.match([&](const MTPDphotos_photo &data) { + _session->data().processPhoto(data.vphoto()); + _session->data().processUsers(data.vusers()); + }); + }).send(); +} + void PeerPhoto::upload( not_null peer, QImage &&image, @@ -195,8 +206,7 @@ void PeerPhoto::clearPersonal(not_null user) { _session->data().processUsers(data.vusers()); }); }).send(); - if (!user->userpicPhotoUnknown() - && (user->flags() & UserDataFlag::PersonalPhoto)) { + if (!user->userpicPhotoUnknown() && user->hasPersonalPhoto()) { _session->storage().remove(Storage::UserPhotosRemoveOne( peerToUser(user->id), user->userpicPhotoId())); @@ -331,8 +341,7 @@ void PeerPhoto::requestUserPhotos( } return photoIds; }); - if (!user->userpicPhotoUnknown() - && (user->flags() & UserDataFlag::PersonalPhoto)) { + if (!user->userpicPhotoUnknown() && user->hasPersonalPhoto()) { const auto photo = owner.photo(user->userpicPhotoId()); if (!photo->isNull()) { ++fullCount; diff --git a/Telegram/SourceFiles/api/api_peer_photo.h b/Telegram/SourceFiles/api/api_peer_photo.h index 660d965ace..e9e5797563 100644 --- a/Telegram/SourceFiles/api/api_peer_photo.h +++ b/Telegram/SourceFiles/api/api_peer_photo.h @@ -25,6 +25,7 @@ public: explicit PeerPhoto(not_null api); void upload(not_null peer, QImage &&image); + void updateSelf(not_null photo); void suggest(not_null peer, QImage &&image); void clear(not_null photo); void clearPersonal(not_null user); diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 578f89ea7b..21d431f597 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -27,7 +27,9 @@ 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 "history/view/media/history_view_service_box.h" +#include "history/view/media/history_view_premium_gift.h" +#include "history/view/media/history_view_userpic_suggestion.h" #include "dialogs/ui/dialogs_message_view.h" #include "ui/image/image.h" #include "ui/effects/spoiler_mess.h" @@ -702,6 +704,15 @@ std::unique_ptr MediaPhoto::createView( not_null realParent, HistoryView::Element *replacing) { if (_chat) { + if (realParent->isUserpicSuggestion()) { + return std::make_unique( + message, + std::make_unique( + message, + _chat, + _photo, + st::msgServicePhotoWidth)); + } return std::make_unique( message, _chat, @@ -1907,7 +1918,9 @@ std::unique_ptr MediaGiftBox::createView( not_null message, not_null realParent, HistoryView::Element *replacing) { - return std::make_unique(message, this); + return std::make_unique( + message, + std::make_unique(message, this)); } bool MediaGiftBox::activated() const { diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index c0cf7f29ac..7af4049658 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -285,6 +285,9 @@ enum class MessageFlag : uint64 { // Optimization for item text custom emoji repainting. CustomEmojiRepainting = (1ULL << 32), + + // Profile photo suggestion, views have special media type. + IsUserpicSuggestion = (1ULL << 33), }; inline constexpr bool is_flag_type(MessageFlag) { return true; } using MessageFlags = base::flags; diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 7991cc1ae9..c083faf914 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -298,6 +298,10 @@ bool UserData::applyMinPhoto() const { return !(flags() & UserDataFlag::DiscardMinPhoto); } +bool UserData::hasPersonalPhoto() const { + return (flags() & UserDataFlag::PersonalPhoto); +} + bool UserData::canAddContact() const { return canShareThisContact() && !isContact(); } diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index ea2bc6e5ba..04ba6ed409 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -114,6 +114,7 @@ public: [[nodiscard]] bool isInaccessible() const; [[nodiscard]] bool canWrite() const; [[nodiscard]] bool applyMinPhoto() const; + [[nodiscard]] bool hasPersonalPhoto() const; [[nodiscard]] bool canShareThisContact() const; [[nodiscard]] bool canAddContact() const; diff --git a/Telegram/SourceFiles/editor/photo_editor_layer_widget.cpp b/Telegram/SourceFiles/editor/photo_editor_layer_widget.cpp index 23d53e9cc2..b82b65fd81 100644 --- a/Telegram/SourceFiles/editor/photo_editor_layer_widget.cpp +++ b/Telegram/SourceFiles/editor/photo_editor_layer_widget.cpp @@ -123,7 +123,8 @@ void PrepareProfilePhoto( .cropType = (radius == ImageRoundRadius::Ellipse ? EditorData::CropType::Ellipse : EditorData::CropType::RoundedRect), - .keepAspectRatio = true, }), + .keepAspectRatio = true, + }), Ui::LayerOption::KeepOther); } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index c648c8f855..d9d48dde42 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1318,6 +1318,10 @@ bool HistoryItem::skipNotification() const { return false; } +bool HistoryItem::isUserpicSuggestion() const { + return (_flags & MessageFlag::IsUserpicSuggestion); +} + void HistoryItem::destroy() { _history->destroyMessage(this); } @@ -3872,12 +3876,20 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { auto prepareSuggestProfilePhoto = [this](const MTPDmessageActionSuggestProfilePhoto &action) { auto result = PreparedServiceText{}; - result.links.push_back(fromLink()); - result.text = tr::lng_action_changed_photo( - tr::now, - lt_from, - fromLinkText(), // Link 1. - Ui::Text::WithEntities); + const auto isSelf = (_from->id == _from->session().userPeerId()); + const auto peer = isSelf ? history()->peer : _from; + const auto user = peer->asUser(); + const auto name = (user && !user->firstName.isEmpty()) + ? user->firstName + : peer->name(); + result.links.push_back(peer->createOpenLink()); + result.text = (isSelf + ? tr::lng_action_suggested_photo_me + : tr::lng_action_suggested_photo)( + tr::now, + lt_user, + Ui::Text::Link(name, 1), // Link 1. + Ui::Text::WithEntities); return result; }; @@ -4009,6 +4021,15 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { this, _from, data.vmonths().v); + }, [&](const MTPDmessageActionSuggestProfilePhoto &data) { + data.vphoto().match([&](const MTPDphoto &photo) { + _flags |= MessageFlag::IsUserpicSuggestion; + _media = std::make_unique( + this, + history()->peer, + history()->owner().processPhoto(photo)); + }, [](const MTPDphotoEmpty &) { + }); }, [](const auto &) { }); } diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index b722c96469..0827140d4c 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -199,6 +199,7 @@ public: [[nodiscard]] bool isScheduled() const; [[nodiscard]] bool isSponsored() const; [[nodiscard]] bool skipNotification() const; + [[nodiscard]] bool isUserpicSuggestion() const; void addLogEntryOriginal( WebPageId localId, diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.cpp b/Telegram/SourceFiles/history/view/history_view_service_message.cpp index 167d5f0e2c..c98141fc02 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_service_message.cpp @@ -427,8 +427,10 @@ QSize Service::performCountCurrentSize(int newWidth) { if (isHidden()) { return { newWidth, newHeight }; } - - if (!text().isEmpty()) { + const auto media = this->media(); + if (media && data()->isUserpicSuggestion()) { + newHeight = st::msgServiceMargin.top() + media->resizeGetHeight(newWidth) + st::msgServiceMargin.bottom(); + } else if (!text().isEmpty()) { auto contentWidth = newWidth; if (delegate()->elementIsChatWide()) { accumulate_min(contentWidth, st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()); @@ -443,7 +445,7 @@ QSize Service::performCountCurrentSize(int newWidth) { ? minHeight() : textHeightFor(nwidth); newHeight += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); - if (const auto media = this->media()) { + if (media) { newHeight += st::msgServiceMargin.top() + media->resizeGetHeight(media->maxWidth()); } } @@ -454,11 +456,14 @@ QSize Service::performCountCurrentSize(int newWidth) { QSize Service::performCountOptimalSize() { validateText(); - auto maxWidth = text().maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right(); - auto minHeight = text().minHeight(); if (const auto media = this->media()) { media->initDimensions(); + if (data()->isUserpicSuggestion()) { + return { media->maxWidth(), media->minHeight() }; + } } + auto maxWidth = text().maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right(); + auto minHeight = text().minHeight(); return { maxWidth, minHeight }; } @@ -519,40 +524,42 @@ void Service::draw(Painter &p, const PaintContext &context) const { p.setTextPalette(st->serviceTextPalette()); const auto media = this->media(); - if (media) { - height -= margin.top() + media->height(); + const auto onlyMedia = (media && data()->isUserpicSuggestion()); + + if (!onlyMedia) { + if (media) { + height -= margin.top() + media->height(); + } + const auto trect = QRect(g.left(), margin.top(), g.width(), height) + - st::msgServicePadding; + + ServiceMessagePainter::PaintComplexBubble( + p, + context.st, + g.left(), + g.width(), + text(), + trect); + + p.setBrush(Qt::NoBrush); + p.setPen(st->msgServiceFg()); + p.setFont(st::msgServiceFont); + prepareCustomEmojiPaint(p, context, text()); + text().draw(p, { + .position = trect.topLeft(), + .availableWidth = trect.width(), + .align = style::al_top, + .palette = &st->serviceTextPalette(), + .spoiler = Ui::Text::DefaultSpoilerCache(), + .now = context.now, + .paused = context.paused, + .selection = context.selection, + .fullWidthSelection = false, + }); } - - const auto trect = QRect(g.left(), margin.top(), g.width(), height) - - st::msgServicePadding; - - ServiceMessagePainter::PaintComplexBubble( - p, - context.st, - g.left(), - g.width(), - text(), - trect); - - p.setBrush(Qt::NoBrush); - p.setPen(st->msgServiceFg()); - p.setFont(st::msgServiceFont); - prepareCustomEmojiPaint(p, context, text()); - text().draw(p, { - .position = trect.topLeft(), - .availableWidth = trect.width(), - .align = style::al_top, - .palette = &st->serviceTextPalette(), - .spoiler = Ui::Text::DefaultSpoilerCache(), - .now = context.now, - .paused = context.paused, - .selection = context.selection, - .fullWidthSelection = false, - }); - if (media) { const auto left = margin.left() + (g.width() - media->maxWidth()) / 2; - const auto top = margin.top() + height + margin.top(); + const auto top = margin.top() + (onlyMedia ? 0 : (height + margin.top())); p.translate(left, top); media->draw(p, context.translated(-left, -top).withSelection({})); p.translate(-left, -top); @@ -591,6 +598,7 @@ PointState Service::pointState(QPoint point) const { TextState Service::textState(QPoint point, StateRequest request) const { const auto item = data(); const auto media = this->media(); + const auto onlyMedia = (media && data()->isUserpicSuggestion()); auto result = TextState(item); @@ -609,7 +617,9 @@ TextState Service::textState(QPoint point, StateRequest request) const { g.setHeight(g.height() - unreadbarh); } - if (media) { + if (onlyMedia) { + return media->textState(point - QPoint(st::msgServiceMargin.left() + (g.width() - media->maxWidth()) / 2, st::msgServiceMargin.top()), request); + } else if (media) { g.setHeight(g.height() - (st::msgServiceMargin.top() + media->height())); } auto trect = g.marginsAdded(-st::msgServicePadding); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.cpp b/Telegram/SourceFiles/history/view/media/history_view_media.cpp index 7ee2c2d514..a909d41127 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media.cpp @@ -176,6 +176,10 @@ Storage::SharedMediaTypesMask Media::sharedMediaTypes() const { return {}; } +not_null Media::parent() const { + return _parent; +} + not_null Media::history() const { return _parent->history(); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.h b/Telegram/SourceFiles/history/view/media/history_view_media.h index 8c18ce2a2c..e06f0eb2de 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media.h @@ -79,6 +79,7 @@ public: explicit Media(not_null parent) : _parent(parent) { } + [[nodiscard]] not_null parent() const; [[nodiscard]] not_null history() const; [[nodiscard]] virtual TextForMimeData selectedText( diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index c436e7f226..0b7e474627 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -59,6 +59,7 @@ public: PhotoData *getPhoto() const override { return _data; } + void showPhoto(FullMsgId id); QSize sizeForGroupingOptimal(int maxWidth) const override; QSize sizeForGrouping(int width) const override; @@ -103,8 +104,6 @@ protected: private: struct Streamed; - void showPhoto(FullMsgId id); - void create(FullMsgId contextId, PeerData *chat = nullptr); void playAnimation(bool autoplay) override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp new file mode 100644 index 0000000000..06e1dfe4b1 --- /dev/null +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -0,0 +1,127 @@ +/* +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_premium_gift.h" + +#include "chat_helpers/stickers_gift_box_pack.h" +#include "core/click_handler_types.h" // ClickHandlerContext +#include "data/data_document.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/view/history_view_element.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "settings/settings_premium.h" // Settings::ShowGiftPremium +#include "window/window_session_controller.h" +#include "styles/style_chat.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 + +PremiumGift::PremiumGift( + not_null parent, + not_null gift) +: _parent(parent) +, _gift(gift) { +} + +PremiumGift::~PremiumGift() = default; + +int PremiumGift::top() { + return st::msgServiceGiftBoxStickerTop; +} + +QSize PremiumGift::size() { + return st::msgServiceGiftBoxStickerSize; +} + +QString PremiumGift::title() { + return tr::lng_premium_summary_title(tr::now); +} + +QString PremiumGift::subtitle() { + return FormatGiftMonths(_gift->months()); +} + +ClickHandlerPtr PremiumGift::createViewLink() { + const auto from = _gift->from(); + const auto to = _parent->history()->peer; + const auto months = _gift->months(); + return std::make_shared([=](ClickContext context) { + const auto my = context.other.value(); + if (const auto controller = my.sessionWindow.get()) { + const auto me = (from->id == controller->session().userPeerId()); + const auto peer = me ? to : from; + Settings::ShowGiftPremium(controller, peer, months, me); + } + }); +} + +void PremiumGift::draw( + Painter &p, + const PaintContext &context, + const QRect &geometry) { + if (_sticker) { + _sticker->draw(p, context, geometry); + } else { + ensureStickerCreated(); + } +} + +void PremiumGift::stickerClearLoopPlayed() { + if (_sticker) { + _sticker->stickerClearLoopPlayed(); + } +} + +std::unique_ptr PremiumGift::stickerTakePlayer( + not_null data, + const Lottie::ColorReplacements *replacements) { + return _sticker + ? _sticker->stickerTakePlayer(data, replacements) + : nullptr; +} + +bool PremiumGift::hasHeavyPart() { + return (_sticker ? _sticker->hasHeavyPart() : false); +} + +void PremiumGift::unloadHeavyPart() { + if (_sticker) { + _sticker->unloadHeavyPart(); + } +} + +void PremiumGift::ensureStickerCreated() const { + if (_sticker) { + return; + } + const auto &session = _parent->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->setGiftBoxSticker(true); + _sticker->initSize(); + } + } +} + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h new file mode 100644 index 0000000000..7a786ce799 --- /dev/null +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h @@ -0,0 +1,53 @@ +/* +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_sticker.h" +#include "history/view/media/history_view_service_box.h" + +namespace Data { +class MediaGiftBox; +} // namespace Data + +namespace HistoryView { + +class PremiumGift final : public ServiceBoxContent { +public: + PremiumGift( + not_null parent, + not_null gift); + ~PremiumGift(); + + int top() override; + QSize size() override; + QString title() override; + QString subtitle() override; + void draw( + Painter &p, + const PaintContext &context, + const QRect &geometry) override; + ClickHandlerPtr createViewLink() override; + + void stickerClearLoopPlayed() override; + std::unique_ptr stickerTakePlayer( + not_null data, + const Lottie::ColorReplacements *replacements) override; + + bool hasHeavyPart() override; + void unloadHeavyPart() override; + +private: + void ensureStickerCreated() const; + + const not_null _parent; + const not_null _gift; + mutable std::optional _sticker; + +}; + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp b/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp new file mode 100644 index 0000000000..c9069384cc --- /dev/null +++ b/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp @@ -0,0 +1,240 @@ +/* +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_box.h" +// +#include "history/view/history_view_cursor_state.h" +#include "history/view/media/history_view_sticker_player_abstract.h" +#include "lang/lang_keys.h" +#include "ui/chat/chat_style.h" +#include "ui/effects/ripple_animation.h" +#include "ui/painter.h" +#include "styles/style_chat.h" +#include "styles/style_premium.h" +#include "styles/style_settings.h" + +namespace HistoryView { + +ServiceBox::ServiceBox( + not_null parent, + std::unique_ptr content) +: Media(parent) +, _parent(parent) +, _content(std::move(content)) +, _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 &padding = st::msgServiceGiftBoxButtonPadding; + result.size = QSize( + result.text.maxWidth() + + height + + padding.left() + + padding.right(), + height); + + result.link = _content->createViewLink(); + + return result; +}()) +, _maxWidth(st::msgServiceGiftBoxSize.width() + - st::msgPadding.left() + - st::msgPadding.right()) +, _title( + st::settingsSubsectionTitle.style, + _content->title(), + kDefaultTextOptions, + _maxWidth) +, _subtitle( + st::premiumPreviewAbout.style, + _content->subtitle(), + kDefaultTextOptions, + _maxWidth) +, _size( + st::msgServiceGiftBoxSize.width(), + (st::msgServiceGiftBoxTopSkip + + _content->top() + + _content->size().height() + + st::msgServiceGiftBoxTitlePadding.top() + + _title.countHeight(_maxWidth) + + st::msgServiceGiftBoxTitlePadding.bottom() + + _subtitle.countHeight(_maxWidth) + + st::msgServiceGiftBoxButtonMargins.top() + + _button.size.height() + + st::msgServiceGiftBoxButtonMargins.bottom())) +, _innerSize(_size - QSize(0, st::msgServiceGiftBoxTopSkip)) { +} + +ServiceBox::~ServiceBox() = default; + +QSize ServiceBox::countOptimalSize() { + return _size; +} + +QSize ServiceBox::countCurrentSize(int newWidth) { + return _size; +} + +void ServiceBox::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); + + const auto content = contentRect(); + auto top = content.top() + content.height(); + { + p.setPen(context.st->msgServiceFg()); + const auto &padding = st::msgServiceGiftBoxTitlePadding; + top += padding.top(); + _title.draw(p, st::msgPadding.left(), top, _maxWidth, style::al_top); + top += _title.countHeight(_maxWidth) + padding.bottom(); + _subtitle.draw(p, st::msgPadding.left(), top, _maxWidth, style::al_top); + top += _subtitle.countHeight(_maxWidth) + padding.bottom(); + } + + { + 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); + } + + _content->draw(p, context, content); + + p.translate(0, -st::msgServiceGiftBoxTopSkip); +} + +TextState ServiceBox::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 ServiceBox::toggleSelectionByHandlerClick( + const ClickHandlerPtr &p) const { + return false; +} + +bool ServiceBox::dragItemByHandler(const ClickHandlerPtr &p) const { + return false; +} + +void ServiceBox::clickHandlerPressedChanged( + const ClickHandlerPtr &handler, + bool pressed) { + if (!handler) { + return; + } + + if (handler == _button.link) { + _button.toggleRipple(pressed); + } +} + +void ServiceBox::stickerClearLoopPlayed() { + _content->stickerClearLoopPlayed(); +} + +std::unique_ptr ServiceBox::stickerTakePlayer( + not_null data, + const Lottie::ColorReplacements *replacements) { + return _content->stickerTakePlayer(data, replacements); +} + +bool ServiceBox::needsBubble() const { + return false; +} + +bool ServiceBox::customInfoLayout() const { + return false; +} + +bool ServiceBox::hasHeavyPart() const { + return _content->hasHeavyPart(); +} + +void ServiceBox::unloadHeavyPart() { + _content->unloadHeavyPart(); +} + +QRect ServiceBox::buttonRect() const { + const auto &padding = st::msgServiceGiftBoxButtonMargins; + const auto position = QPoint( + (width() - _button.size.width()) / 2, + height() - padding.bottom() - _button.size.height()); + return QRect(position, _button.size); +} + +QRect ServiceBox::contentRect() const { + const auto size = _content->size(); + const auto top = _content->top(); + return QRect(QPoint((width() - size.width()) / 2, top), size); +} + +void ServiceBox::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 ServiceBox::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_box.h similarity index 63% rename from Telegram/SourceFiles/history/view/media/history_view_service_media_gift.h rename to Telegram/SourceFiles/history/view/media/history_view_service_box.h index 711290545c..b9b4bcfc63 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_service_media_gift.h +++ b/Telegram/SourceFiles/history/view/media/history_view_service_box.h @@ -8,12 +8,6 @@ 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; @@ -21,10 +15,35 @@ class RippleAnimation; namespace HistoryView { -class MediaGift final : public Media { +class ServiceBoxContent { public: - MediaGift(not_null parent, not_null gift); - ~MediaGift(); + virtual ~ServiceBoxContent() = default; + + [[nodiscard]] virtual int top() = 0; + [[nodiscard]] virtual QSize size() = 0; + [[nodiscard]] virtual QString title() = 0; + [[nodiscard]] virtual QString subtitle() = 0; + virtual void draw( + Painter &p, + const PaintContext &context, + const QRect &geometry) = 0; + [[nodiscard]] virtual ClickHandlerPtr createViewLink() = 0; + + virtual void stickerClearLoopPlayed() = 0; + [[nodiscard]] virtual std::unique_ptr stickerTakePlayer( + not_null data, + const Lottie::ColorReplacements *replacements) = 0; + + [[nodiscard]] virtual bool hasHeavyPart() = 0; + virtual void unloadHeavyPart() = 0; +}; + +class ServiceBox final : public Media { +public: + ServiceBox( + not_null parent, + std::unique_ptr content); + ~ServiceBox(); QSize countOptimalSize() override; QSize countCurrentSize(int newWidth) override; @@ -53,14 +72,11 @@ public: void unloadHeavyPart() override; private: - void ensureStickerCreated() const; [[nodiscard]] QRect buttonRect() const; - [[nodiscard]] QRect stickerRect() const; + [[nodiscard]] QRect contentRect() const; const not_null _parent; - const not_null _gift; - const QSize &_size; - const QSize _innerSize; + const std::unique_ptr _content; struct Button { void drawBg(QPainter &p) const; @@ -77,10 +93,11 @@ private: mutable QPoint lastPoint; } _button; + const int _maxWidth = 0; Ui::Text::String _title; Ui::Text::String _subtitle; - - mutable std::optional _sticker; + const QSize _size; + const QSize _innerSize; }; 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 deleted file mode 100644 index 589d03b0d6..0000000000 --- a/Telegram/SourceFiles/history/view/media/history_view_service_media_gift.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* -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::ShowGiftPremium -#include "ui/chat/chat_style.h" -#include "ui/effects/ripple_animation.h" -#include "ui/painter.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); - - const auto from = _gift->from(); - const auto to = _parent->history()->peer; - const auto months = _gift->months(); - result.link = std::make_shared([=]( - ClickContext context) { - const auto my = context.other.value(); - if (const auto controller = my.sessionWindow.get()) { - const auto me = (from->id == controller->session().userPeerId()); - Settings::ShowGiftPremium(controller, me ? to : from, months, me); - } - }); - - 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); - } -} - -void MediaGift::stickerClearLoopPlayed() { - if (_sticker) { - _sticker->stickerClearLoopPlayed(); - } -} - -std::unique_ptr MediaGift::stickerTakePlayer( - not_null data, - const Lottie::ColorReplacements *replacements) { - return _sticker - ? _sticker->stickerTakePlayer(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->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->setGiftBoxSticker(true); - _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 &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_userpic_suggestion.cpp b/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.cpp new file mode 100644 index 0000000000..9c0f771b8d --- /dev/null +++ b/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.cpp @@ -0,0 +1,129 @@ +/* +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_userpic_suggestion.h" + +#include "core/click_handler_types.h" // ClickHandlerContext +#include "data/data_document.h" +#include "data/data_photo.h" +#include "data/data_user.h" +#include "data/data_photo_media.h" +#include "data/data_file_click_handler.h" +#include "data/data_session.h" +#include "editor/photo_editor_layer_widget.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/view/media/history_view_sticker_player_abstract.h" +#include "history/view/history_view_element.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "window/window_session_controller.h" +#include "ui/painter.h" +#include "mainwidget.h" +#include "apiwrap.h" +#include "api/api_peer_photo.h" +#include "styles/style_chat.h" + +namespace HistoryView { + +UserpicSuggestion::UserpicSuggestion( + not_null parent, + not_null chat, + not_null photo, + int width) +: _photo(parent, chat, photo, width) { + _photo.initDimensions(); + _photo.resizeGetHeight(_photo.maxWidth()); +} + +UserpicSuggestion::~UserpicSuggestion() = default; + +int UserpicSuggestion::top() { + return st::msgServiceGiftBoxButtonMargins.top(); +} + +QSize UserpicSuggestion::size() { + return { _photo.maxWidth(), _photo.minHeight() }; +} + +QString UserpicSuggestion::title() { + return tr::lng_action_suggested_photo_title(tr::now); +} + +QString UserpicSuggestion::subtitle() { + return _photo.parent()->data()->notificationText().text; +} + +ClickHandlerPtr UserpicSuggestion::createViewLink() { + const auto out = _photo.parent()->data()->out(); + const auto photo = _photo.getPhoto(); + const auto itemId = _photo.parent()->data()->fullId(); + const auto show = crl::guard(&_photo, [=](FullMsgId id) { + _photo.showPhoto(id); + }); + return std::make_shared([=](ClickContext context) { + const auto my = context.other.value(); + if (const auto controller = my.sessionWindow.get()) { + const auto media = photo->activeMediaView(); + if (media->loaded()) { + if (out) { + PhotoOpenClickHandler(photo, show, itemId).onClick(context); + } else { + const auto original = std::make_shared( + media->image(Data::PhotoSize::Large)->original()); + const auto callback = [=](QImage &&image) { + const auto session = &photo->session(); + const auto user = session->user(); + auto &peerPhotos = session->api().peerPhoto(); + if (original->size() == image.size() + && original->constBits() == image.constBits()) { + peerPhotos.updateSelf(photo); + } else { + peerPhotos.upload(user, std::move(image)); + } + }; + Editor::PrepareProfilePhoto( + controller->content(), + &controller->window(), + ImageRoundRadius::Ellipse, + callback, + base::duplicate(*original)); + } + } else if (!photo->loading()) { + PhotoSaveClickHandler(photo, itemId).onClick(context); + } + } + }); +} + +void UserpicSuggestion::draw( + Painter &p, + const PaintContext &context, + const QRect &geometry) { + p.translate(geometry.topLeft()); + _photo.draw(p, context); + p.translate(-geometry.topLeft()); +} + +void UserpicSuggestion::stickerClearLoopPlayed() { +} + +std::unique_ptr UserpicSuggestion::stickerTakePlayer( + not_null data, + const Lottie::ColorReplacements *replacements) { + return nullptr; +} + +bool UserpicSuggestion::hasHeavyPart() { + return _photo.hasHeavyPart(); +} + +void UserpicSuggestion::unloadHeavyPart() { + _photo.unloadHeavyPart(); +} + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.h b/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.h new file mode 100644 index 0000000000..348f0e09ca --- /dev/null +++ b/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.h @@ -0,0 +1,53 @@ +/* +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_photo.h" +#include "history/view/media/history_view_service_box.h" + +namespace Data { +class MediaGiftBox; +} // namespace Data + +namespace HistoryView { + +class UserpicSuggestion final : public ServiceBoxContent { +public: + UserpicSuggestion( + not_null parent, + not_null chat, + not_null photo, + int width); + ~UserpicSuggestion(); + + int top() override; + QSize size() override; + QString title() override; + QString subtitle() override; + void draw( + Painter &p, + const PaintContext &context, + const QRect &geometry) override; + ClickHandlerPtr createViewLink() override; + + void stickerClearLoopPlayed() override; + std::unique_ptr stickerTakePlayer( + not_null data, + const Lottie::ColorReplacements *replacements) override; + + bool hasHeavyPart() override; + void unloadHeavyPart() override; + +private: + Photo _photo; + +}; + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index d51e9aa9cf..144edbf926 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -1242,9 +1242,9 @@ 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); +msgServiceGiftBoxButtonPadding: margins(2px, 0px, 2px, 0px); +msgServiceGiftBoxButtonMargins: margins(0px, 13px, 0px, 17px); +msgServiceGiftBoxTitlePadding: margins(0px, 5px, 0px, 2px); msgServiceGiftBoxStickerTop: -19px; msgServiceGiftBoxStickerSize: size(140px, 140px); diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp index 4fa1ba108c..181dc651f0 100644 --- a/Telegram/SourceFiles/ui/special_buttons.cpp +++ b/Telegram/SourceFiles/ui/special_buttons.cpp @@ -317,7 +317,7 @@ void UserpicButton::choosePhotoLocally() { _menu->addAction( tr::lng_profile_suggest_photo(tr::now, lt_user, name), [=] { chooseFile(ChosenType::Suggest); }); - if (user->flags() & UserDataFlag::PersonalPhoto) { + if (user->hasPersonalPhoto()) { _menu->addAction( tr::lng_profile_photo_reset(tr::now), [=] { user->session().api().peerPhoto().clearPersonal(