From 4b09050061ad5783f416d3b25374e46a85d29f19 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 25 Jul 2024 11:40:22 +0200 Subject: [PATCH] Implement Stars gift view from service messages. --- Telegram/Resources/langs/lang.strings | 3 + .../SourceFiles/boxes/gift_premium_box.cpp | 4 +- Telegram/SourceFiles/calls/calls_panel.cpp | 4 +- Telegram/SourceFiles/history/history_item.cpp | 29 ++- .../view/media/history_view_premium_gift.cpp | 22 ++- .../settings/settings_credits_graphics.cpp | 178 ++++++++++-------- .../settings/settings_credits_graphics.h | 7 + .../ui/effects/credits_graphics.cpp | 4 +- 8 files changed, 154 insertions(+), 97 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index fad51ea323..fedb32957c 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1845,6 +1845,7 @@ 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_gift_received_anonymous" = "Unknown user sent you a gift for {cost}"; "lng_action_suggested_photo_me" = "You suggested {user} to use this profile photo."; "lng_action_suggested_photo" = "{user} suggests you to use this profile photo."; "lng_action_suggested_photo_button" = "View Photo"; @@ -2358,6 +2359,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_credits_box_out_confirm#one" = "Confirm and Pay {emoji} {count} Star"; "lng_credits_box_out_confirm#other" = "Confirm and Pay {emoji} {count} Stars"; "lng_credits_box_out_about" = "Review the {link} for Stars."; +"lng_credits_box_out_about_link" = "https://telegram.org/tos/stars"; "lng_credits_media_done_title" = "Media Unlocked"; "lng_credits_media_done_text#one" = "**{count} Star** transferred to {chat}."; "lng_credits_media_done_text#other" = "**{count} Stars** transferred to {chat}."; @@ -2372,6 +2374,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_credits_box_history_entry_fragment" = "Fragment"; "lng_credits_box_history_entry_anonymous" = "Unknown User"; "lng_credits_box_history_entry_gift_name" = "Received Gift"; +"lng_credits_box_history_entry_gift_sent" = "Sent Gift"; "lng_credits_box_history_entry_gift_out_about" = "With Stars, **{user}** will be able to unlock content and services on Telegram.\n{link}"; "lng_credits_box_history_entry_gift_in_about" = "Use Stars to unlock content and services on Telegram. {link}"; "lng_credits_box_history_entry_gift_about_link" = "See Examples {emoji}"; diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index 5730d9b40a..3b8f6f1b5e 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -1694,7 +1694,9 @@ void AddCreditsHistoryEntryTable( } else if (entry.peerType == Type::Fragment) { AddTableRow( table, - tr::lng_credits_box_history_entry_via(), + (entry.gift + ? tr::lng_credits_box_history_entry_peer_in + : tr::lng_credits_box_history_entry_via)(), (entry.gift ? tr::lng_credits_box_history_entry_anonymous : tr::lng_credits_box_history_entry_fragment)( diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index ea204a7704..6a816af963 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -276,8 +276,8 @@ void Panel::initControls() { _layerBg->showBox(std::move(box)); } } else if (const auto source = env->uniqueDesktopCaptureSource()) { - if (_call->isSharingScreen()) { - _call->toggleScreenSharing(std::nullopt); + if (!chooseSourceActiveDeviceId().isEmpty()) { + chooseSourceStop(); } else { chooseSourceAccepted(*source, false); } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 4a8a413ccf..a38b9b33fe 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -4694,21 +4694,32 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { auto prepareGiftPremium = [&]( const MTPDmessageActionGiftPremium &action) { auto result = PreparedServiceText(); - const auto isSelf = (_from->id == _from->session().userPeerId()); + const auto session = &_history->session(); + const auto isSelf = _from->isSelf(); const auto peer = isSelf ? _history->peer : _from; - _history->session().giftBoxStickersPacks().load(); + session->giftBoxStickersPacks().load(); const auto amount = action.vamount().v; const auto currency = qs(action.vcurrency()); - result.links.push_back(peer->createOpenLink()); - result.text = (isSelf - ? tr::lng_action_gift_received_me - : tr::lng_action_gift_received)( + const auto cost = AmountAndStarCurrency(session, amount, currency); + const auto anonymous = _from->isServiceUser(); + if (anonymous) { + result.text = tr::lng_action_gift_received_anonymous( tr::now, - lt_user, - Ui::Text::Link(peer->name(), 1), // Link 1. lt_cost, - AmountAndStarCurrency(&peer->session(), amount, currency), + cost, Ui::Text::WithEntities); + } else { + result.links.push_back(peer->createOpenLink()); + result.text = (isSelf + ? tr::lng_action_gift_received_me + : tr::lng_action_gift_received)( + tr::now, + lt_user, + Ui::Text::Link(peer->name(), 1), // Link 1. + lt_cost, + cost, + Ui::Text::WithEntities); + } return result; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp index 2a7a2f4b1e..23d483c1ff 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -12,13 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/click_handler_types.h" // ClickHandlerContext #include "data/data_document.h" #include "data/data_channel.h" +#include "data/data_user.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_credits.h" // Settings::CreditsId +#include "settings/settings_credits_graphics.h" // GiftedCreditsBox #include "settings/settings_premium.h" // Settings::ShowGiftPremium +#include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "window/window_session_controller.h" #include "styles/style_chat.h" @@ -99,22 +102,29 @@ rpl::producer PremiumGift::button() { ClickHandlerPtr PremiumGift::createViewLink() { const auto from = _gift->from(); - const auto to = _parent->history()->peer; + const auto peer = _parent->history()->peer; + const auto date = _parent->data()->date(); const auto data = _gift->data(); return std::make_shared([=](ClickContext context) { const auto my = context.other.value(); if (const auto controller = my.sessionWindow.get()) { const auto selfId = controller->session().userPeerId(); - const auto self = (from->id == selfId); + const auto sent = (from->id == selfId); if (data.type == Data::GiftType::Stars) { - controller->showSettings(Settings::CreditsId()); + const auto to = sent ? peer : peer->session().user(); + controller->show(Box( + Settings::GiftedCreditsBox, + controller, + from, + to, + data.count, + date)); } else if (data.slug.isEmpty()) { - const auto peer = self ? to : from; const auto months = data.count; - Settings::ShowGiftPremium(controller, peer, months, self); + Settings::ShowGiftPremium(controller, peer, months, sent); } else { const auto fromId = from->id; - const auto toId = self ? to->id : selfId; + const auto toId = sent ? peer->id : selfId; ResolveGiftCode(controller, data.slug, fromId, toId); } } diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index 954c07c7b5..a8c63b5f8b 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -466,84 +466,81 @@ void ReceiptCreditsBox( content->add(object_ptr>( content, object_ptr(content, peer, stUser))); - } else { - if (e.gift) { - using PlayerPtr = std::unique_ptr; - struct State final { - DocumentData *sticker = nullptr; - std::shared_ptr media; - std::unique_ptr lottie; - rpl::lifetime downloadLifetime; - }; - Ui::AddSkip( - content, - st::creditsHistoryEntryGiftStickerSpace); - const auto icon = Ui::CreateChild(content); - icon->resize(Size(st::creditsHistoryEntryGiftStickerSize)); - const auto state = icon->lifetime().make_state(); - auto &packs = session->giftBoxStickersPacks(); - const auto document = packs.lookup(1); - if (document && document->sticker()) { - state->sticker = document; - state->media = document->createMediaView(); - state->media->thumbnailWanted(packs.origin()); - state->media->automaticLoad(packs.origin(), nullptr); - session->downloaderTaskFinished( - ) | rpl::start_with_next([=] { - if (state->media->loaded()) { - state->lottie = ChatHelpers::LottiePlayerFromDocument( - state->media.get(), - ChatHelpers::StickerLottieSize::MessageHistory, - icon->size(), - Lottie::Quality::High); - state->lottie->updates() | rpl::start_with_next([=] { - icon->update(); - }, icon->lifetime()); - state->downloadLifetime.destroy(); - } - }, state->downloadLifetime); - } - icon->paintRequest( - ) | rpl::start_with_next([=] { - auto p = Painter(icon); - const auto &lottie = state->lottie; - const auto frame = (lottie && lottie->ready()) - ? lottie->frameInfo({ .box = icon->size() }) - : Lottie::Animation::FrameInfo(); - if (!frame.image.isNull()) { - p.drawImage(0, 0, frame.image); - if (lottie->frameIndex() < lottie->framesCount() - 1) { - lottie->markFrameShown(); - } - } - }, icon->lifetime()); - content->sizeValue( - ) | rpl::start_with_next([=](const QSize &size) { - icon->move( - (size.width() - icon->width()) / 2, - st::creditsHistoryEntryGiftStickerSkip); - }, icon->lifetime()); - } else { - const auto widget = content->add( - object_ptr>( - content, - object_ptr(content)))->entity(); - using Draw = Fn; - const auto draw = widget->lifetime().make_state( - Ui::GenerateCreditsPaintUserpicCallback(e)); - widget->resize(Size(stUser.photoSize)); - widget->paintRequest( - ) | rpl::start_with_next([=] { - auto p = Painter(widget); - (*draw)(p, 0, 0, stUser.photoSize, stUser.photoSize); - }, widget->lifetime()); + } else if (e.gift) { + struct State final { + DocumentData *sticker = nullptr; + std::shared_ptr media; + std::unique_ptr lottie; + rpl::lifetime downloadLifetime; + }; + Ui::AddSkip( + content, + st::creditsHistoryEntryGiftStickerSpace); + const auto icon = Ui::CreateChild(content); + icon->resize(Size(st::creditsHistoryEntryGiftStickerSize)); + const auto state = icon->lifetime().make_state(); + auto &packs = session->giftBoxStickersPacks(); + const auto document = packs.lookup(packs.monthsForStars(e.credits)); + if (document && document->sticker()) { + state->sticker = document; + state->media = document->createMediaView(); + state->media->thumbnailWanted(packs.origin()); + state->media->automaticLoad(packs.origin(), nullptr); + rpl::single() | rpl::then( + session->downloaderTaskFinished() + ) | rpl::filter([=] { + return state->media->loaded(); + }) | rpl::start_with_next([=] { + state->lottie = ChatHelpers::LottiePlayerFromDocument( + state->media.get(), + ChatHelpers::StickerLottieSize::MessageHistory, + icon->size(), + Lottie::Quality::High); + state->lottie->updates() | rpl::start_with_next([=] { + icon->update(); + }, icon->lifetime()); + state->downloadLifetime.destroy(); + }, state->downloadLifetime); } + icon->paintRequest( + ) | rpl::start_with_next([=] { + auto p = Painter(icon); + const auto &lottie = state->lottie; + const auto frame = (lottie && lottie->ready()) + ? lottie->frameInfo({ .box = icon->size() }) + : Lottie::Animation::FrameInfo(); + if (!frame.image.isNull()) { + p.drawImage(0, 0, frame.image); + if (lottie->frameIndex() < lottie->framesCount() - 1) { + lottie->markFrameShown(); + } + } + }, icon->lifetime()); + content->sizeValue( + ) | rpl::start_with_next([=](const QSize &size) { + icon->move( + (size.width() - icon->width()) / 2, + st::creditsHistoryEntryGiftStickerSkip); + }, icon->lifetime()); + } else { + const auto widget = content->add( + object_ptr>( + content, + object_ptr(content)))->entity(); + using Draw = Fn; + const auto draw = widget->lifetime().make_state( + Ui::GenerateCreditsPaintUserpicCallback(e)); + widget->resize(Size(stUser.photoSize)); + widget->paintRequest( + ) | rpl::start_with_next([=] { + auto p = Painter(widget); + (*draw)(p, 0, 0, stUser.photoSize, stUser.photoSize); + }, widget->lifetime()); } Ui::AddSkip(content); Ui::AddSkip(content); - box->addRow(object_ptr>( box, object_ptr( @@ -565,7 +562,7 @@ void ReceiptCreditsBox( auto &lifetime = content->lifetime(); const auto text = lifetime.make_state( st::semiboldTextStyle, - (e.in ? QChar('+') : kMinus) + (e.in ? u"+"_q : e.gift ? QString() : QString(kMinus)) + Lang::FormatCountDecimal(std::abs(int64(e.credits)))); const auto roundedText = e.refunded ? tr::lng_channel_earn_history_return(tr::now) @@ -605,6 +602,8 @@ void ReceiptCreditsBox( ? st::creditsStroke : e.in ? st::boxTextFgGood + : e.gift + ? st::windowBoldFg : st::menuIconAttentionColor); const auto x = (amount->width() - fullWidth) / 2; text->draw(p, Ui::Text::PaintContext{ @@ -709,10 +708,9 @@ void ReceiptCreditsBox( tr::lng_credits_box_out_about( lt_link, tr::lng_payments_terms_link( - ) | rpl::map([](const QString &t) { - using namespace Ui::Text; - return Link(t, u"https://telegram.org/tos"_q); - }), + ) | Ui::Text::ToLink( + tr::lng_credits_box_out_about_link(tr::now) + ), Ui::Text::WithEntities), st::creditsBoxAboutDivider))); @@ -757,6 +755,32 @@ void ReceiptCreditsBox( }, button->lifetime()); } +void GiftedCreditsBox( + not_null box, + not_null controller, + not_null from, + not_null to, + int count, + TimeId date) { + const auto received = to->isSelf(); + const auto anonymous = from->isServiceUser(); + const auto peer = received ? from : to; + using PeerType = Data::CreditsHistoryEntry::PeerType; + Settings::ReceiptCreditsBox(box, controller, nullptr, { + .id = QString(), + .title = (received + ? tr::lng_credits_box_history_entry_gift_name + : tr::lng_credits_box_history_entry_gift_sent)(tr::now), + .date = base::unixtime::parse(date), + .credits = uint64(count), + .bareMsgId = uint64(), + .barePeerId = (anonymous ? uint64() : peer->id.value), + .peerType = (anonymous ? PeerType::Fragment : PeerType::Peer), + .in = received, + .gift = true, + }); +} + void ShowRefundInfoBox( not_null controller, FullMsgId refundItemId) { diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.h b/Telegram/SourceFiles/settings/settings_credits_graphics.h index 701c60b7fe..e07262d6d0 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.h +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.h @@ -59,6 +59,13 @@ void ReceiptCreditsBox( not_null controller, PeerData *premiumBot, const Data::CreditsHistoryEntry &e); +void GiftedCreditsBox( + not_null box, + not_null controller, + not_null from, + not_null to, + int count, + TimeId date); void ShowRefundInfoBox( not_null controller, FullMsgId refundItemId); diff --git a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp index 61b43b8fc9..018188cb3e 100644 --- a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp +++ b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp @@ -217,7 +217,7 @@ PaintRoundImageCallback GenerateCreditsPaintUserpicCallback( case Data::CreditsHistoryEntry::PeerType::PlayMarket: return { st::historyPeer2UserpicBg, st::historyPeer2UserpicBg2 }; case Data::CreditsHistoryEntry::PeerType::Fragment: - return { st::historyPeer8UserpicBg, st::historyPeer8UserpicBg2 }; + return { st::windowSubTextFg, st::imageBg }; case Data::CreditsHistoryEntry::PeerType::PremiumBot: return { st::historyPeer8UserpicBg, st::historyPeer8UserpicBg2 }; case Data::CreditsHistoryEntry::PeerType::Ads: @@ -458,7 +458,7 @@ TextWithEntities GenerateEntryName(const Data::CreditsHistoryEntry &entry) { return (entry.gift ? tr::lng_credits_box_history_entry_gift_name : (entry.peerType == Data::CreditsHistoryEntry::PeerType::Fragment) - ? tr::lng_bot_username_description1_link + ? tr::lng_credits_box_history_entry_fragment : (entry.peerType == Data::CreditsHistoryEntry::PeerType::PremiumBot) ? tr::lng_credits_box_history_entry_premium_bot : (entry.peerType == Data::CreditsHistoryEntry::PeerType::Ads)