From a174119877f06a463bb6a1fda0309c64fe530f43 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 15 Jan 2025 14:26:22 +0400 Subject: [PATCH] Update API scheme on layer 198. --- Telegram/Resources/langs/lang.strings | 4 + Telegram/SourceFiles/api/api_credits.cpp | 8 ++ Telegram/SourceFiles/api/api_credits.h | 7 + Telegram/SourceFiles/api/api_editing.cpp | 1 + Telegram/SourceFiles/api/api_media.cpp | 1 + Telegram/SourceFiles/api/api_premium.cpp | 24 ++-- Telegram/SourceFiles/api/api_premium.h | 4 +- Telegram/SourceFiles/api/api_sending.cpp | 4 + Telegram/SourceFiles/apiwrap.cpp | 4 +- .../SourceFiles/boxes/gift_premium_box.cpp | 42 ++++-- Telegram/SourceFiles/boxes/share_box.cpp | 3 +- Telegram/SourceFiles/boxes/star_gift_box.cpp | 19 +-- Telegram/SourceFiles/boxes/star_gift_box.h | 4 +- .../SourceFiles/boxes/transfer_gift_box.cpp | 19 +-- .../SourceFiles/boxes/transfer_gift_box.h | 3 +- Telegram/SourceFiles/data/data_channel.cpp | 11 +- Telegram/SourceFiles/data/data_channel.h | 5 +- Telegram/SourceFiles/data/data_credits.h | 2 + Telegram/SourceFiles/data/data_media_types.h | 2 + Telegram/SourceFiles/data/data_peer.cpp | 7 + Telegram/SourceFiles/data/data_peer.h | 1 + Telegram/SourceFiles/data/data_session.h | 3 +- Telegram/SourceFiles/data/data_star_gift.h | 51 ++++++- .../SourceFiles/data/data_subscriptions.h | 3 +- Telegram/SourceFiles/history/history.cpp | 2 +- Telegram/SourceFiles/history/history_item.cpp | 57 +++++++- .../view/media/history_view_premium_gift.cpp | 38 +++-- .../peer_gifts/info_peer_gifts_widget.cpp | 27 ++-- .../info/peer_gifts/info_peer_gifts_widget.h | 2 +- Telegram/SourceFiles/mtproto/scheme/api.tl | 53 ++++--- .../SourceFiles/payments/payments_form.cpp | 6 +- Telegram/SourceFiles/payments/payments_form.h | 2 +- .../payments/payments_non_panel_process.cpp | 2 +- .../settings/settings_credits_graphics.cpp | 131 ++++++++++++------ .../settings/settings_credits_graphics.h | 8 +- .../SourceFiles/window/window_peer_menu.cpp | 3 +- 36 files changed, 403 insertions(+), 160 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 1080b4f1f..d5bf92e78 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2047,6 +2047,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_action_gift_got_upgradable_text" = "Upgrade this gift to a unique collectible."; "lng_action_gift_got_gift_text" = "You can keep this gift on your page."; "lng_action_gift_can_remove_text" = "You can remove this gift from your page."; +"lng_action_gift_got_gift_channel" = "You can keep this gift in channel's Gifts."; +"lng_action_gift_can_remove_channel" = "You can remove this gift from channel's Gifts."; "lng_action_gift_sent_subtitle" = "Gift for {user}"; "lng_action_gift_sent_text#one" = "{user} can display this gift on their page or convert it to {count} Star."; "lng_action_gift_sent_text#other" = "{user} can display this gift on their page or convert it to {count} Stars."; @@ -3281,12 +3283,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_price_unique" = "Unique"; "lng_gift_view_unpack" = "Unpack"; "lng_gift_anonymous_hint" = "Only you can see the sender's name."; +"lng_gift_anonymous_hint_channel" = "Only admins of this channel can see the sender's name."; "lng_gift_hidden_hint" = "This gift is hidden. Only you can see it."; "lng_gift_visible_hint" = "This gift is visible on your page."; "lng_gift_hidden_hint_channel" = "This gift is hidden from visitors of your channel."; "lng_gift_visible_hint_channel" = "This gift is visible in your channel's Gifts."; "lng_gift_visible_hide" = "Hide >"; "lng_gift_show_on_page" = "Display on my Page"; +"lng_gift_show_on_channel" = "Display in channel's Gifts"; "lng_gift_availability" = "Availability"; "lng_gift_from_hidden" = "Hidden User"; "lng_gift_self_status" = "buy yourself a gift"; diff --git a/Telegram/SourceFiles/api/api_credits.cpp b/Telegram/SourceFiles/api/api_credits.cpp index 7d17ca41e..bdb10d02d 100644 --- a/Telegram/SourceFiles/api/api_credits.cpp +++ b/Telegram/SourceFiles/api/api_credits.cpp @@ -513,4 +513,12 @@ void EditCreditsSubscription( )).done(done).fail([=](const MTP::Error &e) { fail(e.type()); }).send(); } +MTPInputSavedStarGift InputSavedStarGiftId(const Data::SavedStarGiftId &id) { + return id.isUser() + ? MTP_inputSavedStarGiftUser(MTP_int(id.userMessageId().bare)) + : MTP_inputSavedStarGiftChat( + id.chat()->input, + MTP_long(id.chatSavedId())); +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_credits.h b/Telegram/SourceFiles/api/api_credits.h index 4f697cf09..c7005073e 100644 --- a/Telegram/SourceFiles/api/api_credits.h +++ b/Telegram/SourceFiles/api/api_credits.h @@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_credits_earn.h" #include "mtproto/sender.h" +namespace Data { +class SavedStarGiftId; +} // namespace Data + namespace Main { class Session; } // namespace Main @@ -116,4 +120,7 @@ void EditCreditsSubscription( Fn done, Fn fail); +[[nodiscard]] MTPInputSavedStarGift InputSavedStarGiftId( + const Data::SavedStarGiftId &id); + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_editing.cpp b/Telegram/SourceFiles/api/api_editing.cpp index 2d9a86e13..313d6bfef 100644 --- a/Telegram/SourceFiles/api/api_editing.cpp +++ b/Telegram/SourceFiles/api/api_editing.cpp @@ -285,6 +285,7 @@ mtpRequestId EditTextMessage( document->mtpInput(), MTPInputPhoto(), // video_cover MTP_int(media->ttlSeconds()), + MTPint(), // video_timestamp MTPstring()); // query }; takeFileReference = [=] { return document->fileReference(); }; diff --git a/Telegram/SourceFiles/api/api_media.cpp b/Telegram/SourceFiles/api/api_media.cpp index 3d82f7ce0..3bbc00f5f 100644 --- a/Telegram/SourceFiles/api/api_media.cpp +++ b/Telegram/SourceFiles/api/api_media.cpp @@ -122,6 +122,7 @@ MTPInputMedia PrepareUploadedDocument( MTP_vector( ranges::to>(info.attachedStickers)), MTPInputPhoto(), // video_cover + MTP_int(0), // video_timestamp MTP_int(ttlSeconds)); } diff --git a/Telegram/SourceFiles/api/api_premium.cpp b/Telegram/SourceFiles/api/api_premium.cpp index cbd8e670f..177bda4e3 100644 --- a/Telegram/SourceFiles/api/api_premium.cpp +++ b/Telegram/SourceFiles/api/api_premium.cpp @@ -809,8 +809,9 @@ std::optional FromTL( .slug = qs(data.vslug()), .title = qs(data.vtitle()), .ownerName = qs(data.vowner_name().value_or_empty()), - .ownerId = peerFromUser( - UserId(data.vowner_id().value_or_empty())), + .ownerId = (data.vowner_id() + ? peerFromMTP(*data.vowner_id()) + : PeerId()), .number = data.vnum().v, .model = *model, .pattern = *pattern, @@ -833,9 +834,9 @@ std::optional FromTL( }); } -std::optional FromTL( +std::optional FromTL( not_null to, - const MTPuserStarGift &gift) { + const MTPsavedStarGift &gift) { const auto session = &to->session(); const auto &data = gift.data(); auto parsed = FromTL(session, data.vgift()); @@ -845,8 +846,12 @@ std::optional FromTL( unique->starsForTransfer = data.vtransfer_stars().value_or(-1); unique->exportAt = data.vcan_export_at().value_or_empty(); } - return Data::UserStarGift{ + using Id = Data::SavedStarGiftId; + return Data::SavedStarGift{ .info = std::move(*parsed), + .id = (to->isUser() + ? Id::User(data.vmsg_id().value_or_empty()) + : Id::Chat(to, data.vsaved_id().value_or_empty())), .message = (data.vmessage() ? TextWithEntities{ .text = qs(data.vmessage()->data().vtext()), @@ -859,9 +864,8 @@ std::optional FromTL( .starsUpgradedBySender = int64( data.vupgrade_stars().value_or_empty()), .fromId = (data.vfrom_id() - ? peerFromUser(data.vfrom_id()->v) + ? peerFromMTP(*data.vfrom_id()) : PeerId()), - .messageId = data.vmsg_id().value_or_empty(), .date = data.vdate().v, .upgradable = data.is_can_upgrade(), .anonymous = data.is_name_hidden(), @@ -914,11 +918,9 @@ Data::UniqueGiftOriginalDetails FromTL( auto result = Data::UniqueGiftOriginalDetails(); result.date = data.vdate().v; result.senderId = data.vsender_id() - ? peerFromUser( - UserId(data.vsender_id().value_or_empty())) + ? peerFromMTP(*data.vsender_id()) : PeerId(); - result.recipientId = peerFromUser( - UserId(data.vrecipient_id().v)); + result.recipientId = peerFromMTP(data.vrecipient_id()); result.message = data.vmessage() ? ParseTextWithEntities(session, *data.vmessage()) : TextWithEntities(); diff --git a/Telegram/SourceFiles/api/api_premium.h b/Telegram/SourceFiles/api/api_premium.h index 912856aff..a7757a490 100644 --- a/Telegram/SourceFiles/api/api_premium.h +++ b/Telegram/SourceFiles/api/api_premium.h @@ -259,9 +259,9 @@ enum class RequirePremiumState { [[nodiscard]] std::optional FromTL( not_null session, const MTPstarGift &gift); -[[nodiscard]] std::optional FromTL( +[[nodiscard]] std::optional FromTL( not_null to, - const MTPuserStarGift &gift); + const MTPsavedStarGift &gift); [[nodiscard]] Data::UniqueGiftModel FromTL( not_null session, diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index f926b0468..193e2e71b 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -274,6 +274,7 @@ void SendExistingDocument( document->mtpInput(), MTPInputPhoto(), // video_cover MTPint(), // ttl_seconds + MTPint(), // video_timestamp MTPstring()); // query }; SendExistingMedia( @@ -552,6 +553,7 @@ void SendConfirmedFile( file->document, MTPVector(), // alt_documents MTPPhoto(), // video_cover + MTPint(), // video_timestamp MTPint()); } else if (file->type == SendMediaType::Audio) { const auto ttlSeconds = file->to.options.ttlSeconds; @@ -563,6 +565,7 @@ void SendConfirmedFile( file->document, MTPVector(), // alt_documents MTPPhoto(), // video_cover + MTPint(), // video_timestamp MTP_int(ttlSeconds)); } else if (file->type == SendMediaType::Round) { using Flag = MTPDmessageMediaDocument::Flag; @@ -575,6 +578,7 @@ void SendConfirmedFile( file->document, MTPVector(), // alt_documents MTPPhoto(), // video_cover + MTPint(), // video_timestamp MTP_int(ttlSeconds)); } else { Unexpected("Type in sendFilesConfirmed."); diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 31a235a7a..d15a73f49 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3378,7 +3378,8 @@ void ApiWrap::forwardMessages( MTP_int(topMsgId), MTP_int(action.options.scheduled), (sendAs ? sendAs->input : MTP_inputPeerEmpty()), - Data::ShortcutIdToMTP(_session, action.options.shortcutId) + Data::ShortcutIdToMTP(_session, action.options.shortcutId), + MTPint() // video_timestamp )).done([=](const MTPUpdates &result) { if (!scheduled) { this->updates().checkForSentToScheduled(result); @@ -4148,6 +4149,7 @@ void ApiWrap::uploadAlbumMedia( fields.vfile_reference()), MTPInputPhoto(), // video_cover MTP_int(data.vttl_seconds().value_or_empty()), + MTPint(), // video_timestamp MTPstring()); // query sendAlbumWithUploaded(item, groupId, media); } break; diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index ecf4cbc68..0be756f0d 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -1240,6 +1240,8 @@ void AddStarGiftTable( const auto selfBareId = session->userPeerId().value; const auto giftToSelf = (peerId == session->userPeerId()) && (entry.in || entry.bareGiftOwnerId == selfBareId); + const auto giftToChannel = entry.giftSavedId + && peerIsChannel(PeerId(entry.bareGiftListPeerId)); const auto raw = std::make_shared(nullptr); const auto showTooltip = [=]( @@ -1336,22 +1338,38 @@ void AddStarGiftTable( table, tr::lng_gift_unique_owner(), rpl::single(TextWithEntities{ unique->ownerName })); - } else if (peerId) { - if (!giftToSelf) { - const auto user = session->data().peer(peerId)->asUser(); - const auto withSendButton = entry.in && user && !user->isBot(); - auto send = withSendButton ? tr::lng_gift_send_small() : nullptr; - auto handler = send ? Fn([=] { - if (const auto window = show->resolveWindow()) { - Ui::ShowStarGiftBox(window, user); - } - }) : nullptr; + } else if (giftToChannel) { + AddTableRow( + table, + tr::lng_credits_box_history_entry_peer_in(), + (entry.bareActorId + ? MakePeerTableValue(table, show, PeerId(entry.bareActorId)) + : MakeHiddenPeerTableValue(table)), + st::giveawayGiftCodePeerMargin); + if (!entry.fromGiftsList) { AddTableRow( table, - tr::lng_credits_box_history_entry_peer_in(), - MakePeerTableValue(table, show, peerId, send, handler), + tr::lng_credits_box_history_entry_peer(), + MakePeerTableValue( + table, + show, + PeerId(entry.bareGiftListPeerId)), st::giveawayGiftCodePeerMargin); } + } else if (peerId && !giftToSelf) { + const auto user = session->data().peer(peerId)->asUser(); + const auto withSendButton = entry.in && user && !user->isBot(); + auto send = withSendButton ? tr::lng_gift_send_small() : nullptr; + auto handler = send ? Fn([=] { + if (const auto window = show->resolveWindow()) { + Ui::ShowStarGiftBox(window, user); + } + }) : nullptr; + AddTableRow( + table, + tr::lng_credits_box_history_entry_peer_in(), + MakePeerTableValue(table, show, peerId, send, handler), + st::giveawayGiftCodePeerMargin); } else if (!entry.soldOutInfo) { AddTableRow( table, diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index f79ee88f8..be47e59a1 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -1584,7 +1584,8 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback( MTP_int(topMsgId), MTP_int(options.scheduled), MTP_inputPeerEmpty(), // send_as - Data::ShortcutIdToMTP(session, options.shortcutId) + Data::ShortcutIdToMTP(session, options.shortcutId), + MTPint() // video_timestamp )).done([=](const MTPUpdates &updates, mtpRequestId reqId) { threadHistory->session().api().applyUpdates(updates); state->requests.remove(reqId); diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index 0ebdd126b..922ada959 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -8,11 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/star_gift_box.h" #include "apiwrap.h" +#include "api/api_credits.h" +#include "api/api_premium.h" #include "base/event_filter.h" #include "base/random.h" #include "base/timer_rpl.h" #include "base/unixtime.h" -#include "api/api_premium.h" #include "boxes/filters/edit_filter_chats_list.h" #include "boxes/gift_premium_box.h" #include "boxes/peer_list_controllers.h" @@ -1084,7 +1085,7 @@ void SendGift( .giftId = gift.info.id, .randomId = details.randomId, .message = details.text, - .user = peer->asUser(), + .recipient = peer, .limitedCount = gift.info.limitedCount, .anonymous = details.anonymous, .upgraded = details.upgraded, @@ -1169,7 +1170,7 @@ void SendStarsFormRequest( void UpgradeGift( not_null window, - MsgId messageId, + Data::SavedStarGiftId savedId, bool keepDetails, int stars, Fn done) { @@ -1189,7 +1190,7 @@ void UpgradeGift( using Flag = MTPpayments_UpgradeStarGift::Flag; session->api().request(MTPpayments_UpgradeStarGift( MTP_flags(keepDetails ? Flag::f_keep_original_details : Flag()), - MTP_int(messageId.bare) + Api::InputSavedStarGiftId(savedId) )).done([=](const MTPUpdates &result) { session->api().applyUpdates(result); formDone(Payments::CheckoutResult::Paid, &result); @@ -1206,7 +1207,7 @@ void UpgradeGift( window, MTP_inputInvoiceStarGiftUpgrade( MTP_flags(keepDetails ? Flag::f_keep_original_details : Flag()), - MTP_int(messageId.bare)), + Api::InputSavedStarGiftId(savedId)), std::move(formDone)); } @@ -2475,7 +2476,7 @@ struct UpgradeArgs : StarGiftUpgradeArgs { auto &patterns = state->data.patterns; auto &backdrops = state->data.backdrops; consumer.put_next(Data::UniqueGift{ - .title = (state->data.itemId + .title = (state->data.savedId ? tr::lng_gift_upgrade_title(tr::now) : tr::lng_gift_upgrade_preview_title(tr::now)), .model = models[index(state->modelIndices, models)], @@ -2499,7 +2500,7 @@ void AddUpgradeGiftCover( AddUniqueGiftCover( container, MakeUpgradeGiftStream(args), - (args.itemId + (args.savedId ? tr::lng_gift_upgrade_about() : (args.peer->isBroadcast() ? tr::lng_gift_upgrade_preview_about_channel @@ -2573,7 +2574,7 @@ void UpgradeBox( bool preserveDetails = false; }; const auto state = std::make_shared(); - const auto preview = !args.itemId; + const auto preview = !args.savedId; if (!preview) { const auto skip = st::defaultVerticalListSkip; @@ -2624,7 +2625,7 @@ void UpgradeBox( } } }; - UpgradeGift(controller, args.itemId, keepDetails, cost, done); + UpgradeGift(controller, args.savedId, keepDetails, cost, done); }); if (!preview) { auto star = session->data().customEmojiManager().creditsEmoji(); diff --git a/Telegram/SourceFiles/boxes/star_gift_box.h b/Telegram/SourceFiles/boxes/star_gift_box.h index 61b82f81a..f161186ff 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.h +++ b/Telegram/SourceFiles/boxes/star_gift_box.h @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "data/data_star_gift.h" + namespace ChatHelpers { class Show; } // namespace ChatHelpers @@ -83,7 +85,7 @@ struct StarGiftUpgradeArgs { base::required stargiftId; Fn ready; not_null peer; - MsgId itemId = 0; + Data::SavedStarGiftId savedId; int cost = 0; bool canAddSender = false; bool canAddComment = false; diff --git a/Telegram/SourceFiles/boxes/transfer_gift_box.cpp b/Telegram/SourceFiles/boxes/transfer_gift_box.cpp index d92204e0b..befba0e52 100644 --- a/Telegram/SourceFiles/boxes/transfer_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/transfer_gift_box.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/transfer_gift_box.h" #include "apiwrap.h" +#include "api/api_credits.h" #include "base/unixtime.h" #include "data/data_star_gift.h" #include "data/data_user.h" @@ -284,7 +285,7 @@ void TransferGift( not_null window, not_null to, std::shared_ptr gift, - MsgId messageId, + Data::SavedStarGiftId savedId, Fn done) { Expects(to->isUser()); @@ -302,8 +303,8 @@ void TransferGift( }; if (gift->starsForTransfer <= 0) { session->api().request(MTPpayments_TransferStarGift( - MTP_int(messageId.bare), - to->asUser()->inputUser + Api::InputSavedStarGiftId(savedId), + to->input )).done([=](const MTPUpdates &result) { session->api().applyUpdates(result); formDone(Payments::CheckoutResult::Paid, &result); @@ -318,8 +319,8 @@ void TransferGift( Ui::RequestStarsFormAndSubmit( window, MTP_inputInvoiceStarGiftTransfer( - MTP_int(messageId.bare), - to->asUser()->inputUser), + Api::InputSavedStarGiftId(savedId), + to->input), std::move(formDone)); } @@ -327,7 +328,7 @@ void ShowTransferToBox( not_null controller, not_null peer, std::shared_ptr gift, - MsgId msgId) { + Data::SavedStarGiftId savedId) { const auto stars = gift->starsForTransfer; controller->show(Box([=](not_null box) { box->setTitle(tr::lng_gift_transfer_title( @@ -362,7 +363,7 @@ void ShowTransferToBox( } } }; - TransferGift(controller, peer, gift, msgId, done); + TransferGift(controller, peer, gift, savedId, done); }; Ui::ConfirmBox(box, { @@ -395,12 +396,12 @@ void ShowTransferToBox( void ShowTransferGiftBox( not_null window, std::shared_ptr gift, - MsgId msgId) { + Data::SavedStarGiftId savedId) { auto controller = std::make_unique( window, gift, [=](not_null peer) { - ShowTransferToBox(window, peer, gift, msgId); + ShowTransferToBox(window, peer, gift, savedId); }); const auto controllerRaw = controller.get(); auto initBox = [=](not_null box) { diff --git a/Telegram/SourceFiles/boxes/transfer_gift_box.h b/Telegram/SourceFiles/boxes/transfer_gift_box.h index 2b5ee2240..e058e88c3 100644 --- a/Telegram/SourceFiles/boxes/transfer_gift_box.h +++ b/Telegram/SourceFiles/boxes/transfer_gift_box.h @@ -13,9 +13,10 @@ class SessionController; namespace Data { struct UniqueGift; +class SavedStarGiftId; } // namespace Data void ShowTransferGiftBox( not_null window, std::shared_ptr gift, - MsgId msgId); + Data::SavedStarGiftId savedId); diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index b757c5104..22041523d 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -714,10 +714,6 @@ bool ChannelData::canRestrictParticipant( return adminRights() & AdminRight::BanUsers; } -bool ChannelData::canManageGifts() const { - return amCreator(); // todo channel gifts -} - void ChannelData::setBotVerifyDetails(Ui::BotVerifyDetails details) { if (!details) { if (_botVerifyDetails) { @@ -1153,7 +1149,8 @@ void ApplyChannelUpdate( | Flag::ViewAsMessages | Flag::CanViewRevenue | Flag::PaidMediaAllowed - | Flag::CanViewCreditsRevenue; + | Flag::CanViewCreditsRevenue + | Flag::StargiftsAvailable; channel->setFlags((channel->flags() & ~mask) | (update.is_can_set_username() ? Flag::CanSetUsername : Flag()) | (update.is_can_view_participants() @@ -1174,6 +1171,9 @@ void ApplyChannelUpdate( | (update.is_can_view_revenue() ? Flag::CanViewRevenue : Flag()) | (update.is_can_view_stars_revenue() ? Flag::CanViewCreditsRevenue + : Flag()) + | (update.is_stargifts_available() + ? Flag::StargiftsAvailable : Flag())); channel->setUserpicPhoto(update.vchat_photo()); if (const auto migratedFrom = update.vmigrated_from_chat_id()) { @@ -1187,6 +1187,7 @@ void ApplyChannelUpdate( channel->setRestrictedCount(update.vbanned_count().value_or_empty()); channel->setKickedCount(update.vkicked_count().value_or_empty()); channel->setSlowmodeSeconds(update.vslowmode_seconds().value_or_empty()); + channel->setPeerGiftsCount(update.vstargifts_count().value_or_empty()); if (const auto next = update.vslowmode_next_send_date()) { channel->growSlowmodeLastMessage( next->v - channel->slowmodeSeconds()); diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index af2c2602c..620cca9d1 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -69,6 +69,7 @@ enum class ChannelDataFlag : uint64 { PaidMediaAllowed = (1ULL << 33), CanViewCreditsRevenue = (1ULL << 34), SignatureProfiles = (1ULL << 35), + StargiftsAvailable = (1ULL << 36), }; inline constexpr bool is_flag_type(ChannelDataFlag) { return true; }; using ChannelDataFlags = base::flags; @@ -253,6 +254,9 @@ public: [[nodiscard]] bool viewForumAsMessages() const { return flags() & Flag::ViewAsMessages; } + [[nodiscard]] bool stargiftsAvailable() const { + return flags() & Flag::StargiftsAvailable; + } [[nodiscard]] static ChatRestrictionsInfo KickedRestrictedRights( not_null participant); @@ -375,7 +379,6 @@ public: [[nodiscard]] bool canEditAdmin(not_null user) const; [[nodiscard]] bool canRestrictParticipant( not_null participant) const; - [[nodiscard]] bool canManageGifts() const; void setBotVerifyDetails(Ui::BotVerifyDetails details); void setBotVerifyDetailsIcon(DocumentId iconId); diff --git a/Telegram/SourceFiles/data/data_credits.h b/Telegram/SourceFiles/data/data_credits.h index 6bdf5563b..adf692218 100644 --- a/Telegram/SourceFiles/data/data_credits.h +++ b/Telegram/SourceFiles/data/data_credits.h @@ -66,6 +66,8 @@ struct CreditsHistoryEntry final { uint64 bareGiftStickerId = 0; uint64 bareGiftOwnerId = 0; uint64 bareActorId = 0; + uint64 bareGiftListPeerId = 0; + uint64 giftSavedId = 0; uint64 stargiftId = 0; std::shared_ptr uniqueGift; StarsAmount starrefAmount; diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index 83bdcd1e2..739cc7839 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -141,6 +141,8 @@ struct GiftCode { std::shared_ptr unique; TextWithEntities message; ChannelData *channel = nullptr; + PeerData *channelFrom = nullptr; + uint64 channelSavedId = 0; MsgId giveawayMsgId = 0; MsgId upgradeMsgId = 0; int starsConverted = 0; diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 5cff6c49a..9059994e0 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -652,6 +652,13 @@ bool PeerData::canManageTopics() const { return false; } +bool PeerData::canManageGifts() const { + if (const auto channel = asChannel()) { + return channel->canPostMessages(); + } + return isSelf(); +} + bool PeerData::canEditMessagesIndefinitely() const { if (const auto user = asUser()) { return user->isSelf(); diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index ca416bb5c..83174a5fc 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -384,6 +384,7 @@ public: [[nodiscard]] bool canCreatePolls() const; [[nodiscard]] bool canCreateTopics() const; [[nodiscard]] bool canManageTopics() const; + [[nodiscard]] bool canManageGifts() const; [[nodiscard]] bool canExportChatHistory() const; // Returns true if about text was changed. diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index b73b211a5..fade93dad 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_main_list.h" #include "data/data_groups.h" #include "data/data_cloud_file.h" +#include "data/data_star_gift.h" #include "history/history_location_manager.h" #include "base/timer.h" @@ -87,7 +88,7 @@ struct GiftUpdate { Delete, }; - FullMsgId itemId; + Data::SavedStarGiftId id; Action action = {}; }; diff --git a/Telegram/SourceFiles/data/data_star_gift.h b/Telegram/SourceFiles/data/data_star_gift.h index 8b79881c4..90b3cc975 100644 --- a/Telegram/SourceFiles/data/data_star_gift.h +++ b/Telegram/SourceFiles/data/data_star_gift.h @@ -74,13 +74,60 @@ struct StarGift { const StarGift &) = default; }; -struct UserStarGift { +class SavedStarGiftId { +public: + [[nodiscard]] static SavedStarGiftId User(MsgId messageId) { + auto result = SavedStarGiftId(); + result.entityId = uint64(messageId.bare); + return result; + } + [[nodiscard]] static SavedStarGiftId Chat( + not_null peer, + uint64 savedId) { + auto result = SavedStarGiftId(); + result.peer = peer; + result.entityId = savedId; + return result; + } + + [[nodiscard]] bool isUser() const { + return !peer; + } + [[nodiscard]] bool isChat() const { + return peer != nullptr; + } + + [[nodiscard]] MsgId userMessageId() const { + return peer ? MsgId(0) : MsgId(entityId); + } + [[nodiscard]] PeerData *chat() const { + return peer; + } + [[nodiscard]] uint64 chatSavedId() const { + return peer ? entityId : 0; + } + + explicit operator bool() const { + return entityId != 0; + } + + friend inline bool operator==( + const SavedStarGiftId &a, + const SavedStarGiftId &b) = default; + +private: + PeerData *peer = nullptr; + uint64 entityId = 0; + +}; + +struct SavedStarGift { StarGift info; + SavedStarGiftId id; TextWithEntities message; int64 starsConverted = 0; int64 starsUpgradedBySender = 0; PeerId fromId = 0; - MsgId messageId = 0; TimeId date = 0; bool upgradable = false; bool anonymous = false; diff --git a/Telegram/SourceFiles/data/data_subscriptions.h b/Telegram/SourceFiles/data/data_subscriptions.h index c0d4de5a2..d6e72b911 100644 --- a/Telegram/SourceFiles/data/data_subscriptions.h +++ b/Telegram/SourceFiles/data/data_subscriptions.h @@ -18,7 +18,6 @@ struct PeerSubscription final { } }; -using PhotoId = uint64; struct SubscriptionEntry final { explicit operator bool() const { return !id.isEmpty(); @@ -31,7 +30,7 @@ struct SubscriptionEntry final { QDateTime until; PeerSubscription subscription; uint64 barePeerId = 0; - PhotoId photoId = PhotoId(0); + uint64 photoId = 0; bool cancelled = false; bool cancelledByBot = false; bool expired = false; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index d23f3d1b7..75047ade1 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -192,7 +192,7 @@ void History::itemVanished(not_null item) { if (const auto gift = media->gift()) { using GiftAction = Data::GiftUpdate::Action; owner().notifyGiftUpdate({ - .itemId = item->fullId(), + .id = Data::SavedStarGiftId::User(item->id), .action = GiftAction::Delete, }); } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 1ff690236..33ea0b2e9 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -5443,9 +5443,32 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { const auto cost = TextWithEntities{ tr::lng_action_gift_for_stars(tr::now, lt_count, stars), }; - const auto anonymous = _from->isServiceUser(); - if (anonymous || _history->peer->isSelf()) { - // todo channel gifts + const auto giftPeer = action.vpeer() + ? peerFromMTP(*action.vpeer()) + : PeerId(); + const auto service = _from->isServiceUser(); + const auto toChannel = service && peerIsChannel(giftPeer); + const auto anonymous = service && !toChannel; + if (toChannel) { + const auto fromId = action.vfrom_id() + ? peerFromMTP(*action.vfrom_id()) + : PeerId(); + const auto from = fromId ? peer->owner().peer(fromId) : peer; + const auto channel = peer->owner().channel( + peerToChannel(giftPeer)); + Assert(channel != nullptr); + result.links.push_back(from->createOpenLink()); + result.links.push_back(channel->createOpenLink()); + result.text = tr::lng_action_gift_sent_channel( + tr::now, + lt_user, + Ui::Text::Link(from->shortName(), 1), + lt_name, + Ui::Text::Link(channel->name(), 2), + lt_cost, + cost, + Ui::Text::WithEntities); + } else if (anonymous || _history->peer->isSelf()) { result.text = (anonymous ? tr::lng_action_gift_received_anonymous : tr::lng_action_gift_self_bought)( @@ -5671,6 +5694,13 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { .unclaimed = data.is_unclaimed(), }); }, [&](const MTPDmessageActionStarGift &data) { + const auto service = _from->isServiceUser(); + const auto from = data.vfrom_id() + ? peerFromMTP(*data.vfrom_id()) + : PeerId(); + const auto to = data.vpeer() + ? peerFromMTP(*data.vpeer()) + : PeerId(); using Fields = Data::GiftCode; auto fields = Fields{ .message = (data.vmessage() @@ -5681,6 +5711,13 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { data.vmessage()->data().ventities().v), } : TextWithEntities()), + .channel = ((service && peerIsChannel(to)) + ? history()->owner().channel(peerToChannel(to)).get() + : nullptr), + .channelFrom = ((service && from) + ? history()->owner().peer(from).get() + : nullptr), + .channelSavedId = data.vsaved_id().value_or_empty(), .upgradeMsgId = data.vupgrade_msg_id().value_or_empty(), .starsConverted = int(data.vconvert_stars().value_or_empty()), .starsUpgradedBySender = int( @@ -5706,8 +5743,22 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { _from, std::move(fields)); }, [&](const MTPDmessageActionStarGiftUnique &data) { + const auto service = _from->isServiceUser(); + const auto from = data.vfrom_id() + ? peerFromMTP(*data.vfrom_id()) + : PeerId(); + const auto to = data.vpeer() + ? peerFromMTP(*data.vpeer()) + : PeerId(); using Fields = Data::GiftCode; auto fields = Fields{ + .channel = ((service && peerIsChannel(to)) + ? history()->owner().channel(peerToChannel(to)).get() + : nullptr), + .channelFrom = ((service && from) + ? history()->owner().peer(from).get() + : nullptr), + .channelSavedId = data.vsaved_id().value_or_empty(), .type = Data::GiftType::StarGift, .transferred = data.is_transferred(), .refunded = data.is_refunded(), 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 a0e972d3f..04a9c342f 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -90,6 +90,8 @@ QString PremiumGift::title() { TextWithEntities PremiumGift::subtitle() { if (starGift()) { + const auto toChannel = _data.channel + && _parent->history()->peer->isServiceUser(); return !_data.message.empty() ? _data.message : _data.refunded @@ -115,19 +117,32 @@ TextWithEntities PremiumGift::subtitle() { : (_data.starsToUpgrade && !_data.converted && _parent->history()->peer->isSelf()) - ? tr::lng_action_gift_self_about_unique( // todo channel gifts + ? tr::lng_action_gift_self_about_unique( + tr::now, + Ui::Text::RichLangValue) + : (_data.starsToUpgrade + && !_data.converted + && _parent->history()->peer->isServiceUser() + && _data.channel) + ? tr::lng_action_gift_channel_about_unique( tr::now, Ui::Text::RichLangValue) : (!_data.converted && !_data.starsConverted) ? (_data.saved - ? tr::lng_action_gift_can_remove_text - : tr::lng_action_gift_got_gift_text)( - tr::now, - Ui::Text::RichLangValue) + ? (toChannel + ? tr::lng_action_gift_can_remove_channel + : tr::lng_action_gift_can_remove_text) + : (toChannel + ? tr::lng_action_gift_got_gift_channel + : tr::lng_action_gift_got_gift_text))( + tr::now, + Ui::Text::RichLangValue) : (_data.converted ? tr::lng_gift_got_stars : _parent->history()->peer->isSelf() - ? tr::lng_action_gift_self_about // todo channel gifts + ? tr::lng_action_gift_self_about + : toChannel + ? tr::lng_action_gift_channel_about : tr::lng_action_gift_got_stars_text)( tr::now, lt_count, @@ -258,20 +273,23 @@ ClickHandlerPtr PremiumGift::createViewLink() { return; } *requesting = true; - controller->session().api().request(MTPpayments_GetUserStarGift( - MTP_vector(1, MTP_int(upgradeTo)) - )).done([=](const MTPpayments_UserStarGifts &result) { + controller->session().api().request(MTPpayments_GetSavedStarGift( + MTP_vector( + 1, + MTP_inputSavedStarGiftUser(MTP_int(upgradeTo))) + )).done([=](const MTPpayments_SavedStarGifts &result) { *requesting = false; if (const auto window = weak.get()) { const auto &data = result.data(); window->session().data().processUsers(data.vusers()); + window->session().data().processChats(data.vchats()); const auto self = window->session().user(); const auto &list = data.vgifts().v; if (list.empty()) { showForWeakWindow(weak); } else if (auto parsed = Api::FromTL(self, list[0])) { window->show(Box( - Settings::UserStarGiftBox, + Settings::SavedStarGiftBox, window, self, *parsed)); diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp index 602e4d4cd..027e8f8a4 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp @@ -34,7 +34,7 @@ constexpr auto kPerPage = 50; [[nodiscard]] GiftDescriptor DescriptorForGift( not_null to, - const Data::UserStarGift &gift) { + const Data::SavedStarGift &gift) { return GiftTypeStars{ .info = gift.info, .from = ((gift.anonymous || !gift.fromId) @@ -64,7 +64,7 @@ public: private: struct Entry { - Data::UserStarGift gift; + Data::SavedStarGift gift; GiftDescriptor descriptor; }; struct View { @@ -142,10 +142,10 @@ InnerWidget::InnerWidget( void InnerWidget::subscribeToUpdates() { _peer->owner().giftUpdates( ) | rpl::start_with_next([=](const Data::GiftUpdate &update) { - const auto itemId = [](const Entry &entry) { - return FullMsgId(entry.gift.fromId, entry.gift.messageId); + const auto savedId = [](const Entry &entry) { + return entry.gift.id; }; - const auto i = ranges::find(_entries, update.itemId, itemId); + const auto i = ranges::find(_entries, update.id, savedId); if (i == end(_entries)) { return; } @@ -204,14 +204,18 @@ void InnerWidget::paintEvent(QPaintEvent *e) { } void InnerWidget::loadMore() { - if (_allLoaded || _loadMoreRequestId || !_peer->isUser()) { - return; // todo channel gifts + if (_allLoaded || _loadMoreRequestId) { + return; } - _loadMoreRequestId = _api.request(MTPpayments_GetUserStarGifts( - _peer->asUser()->inputUser, + using Flag = MTPpayments_GetSavedStarGifts::Flag; + const auto withUnsaved = _peer->isSelf() + || (_peer->isChannel() && _peer->asChannel()->canManageGifts()); + _loadMoreRequestId = _api.request(MTPpayments_GetSavedStarGifts( + MTP_flags(withUnsaved ? Flag() : Flag::f_exclude_unsaved), + _peer->input, MTP_string(_offset), MTP_int(kPerPage) - )).done([=](const MTPpayments_UserStarGifts &result) { + )).done([=](const MTPpayments_SavedStarGifts &result) { _loadMoreRequestId = 0; const auto &data = result.data(); if (const auto next = data.vnext_offset()) { @@ -223,6 +227,7 @@ void InnerWidget::loadMore() { const auto owner = &_peer->owner(); owner->processUsers(data.vusers()); + owner->processChats(data.vchats()); _entries.reserve(_entries.size() + data.vgifts().v.size()); for (const auto &gift : data.vgifts().v) { @@ -327,7 +332,7 @@ void InnerWidget::validateButtons() { void InnerWidget::showGift(int index) { _window->show(Box( - ::Settings::UserStarGiftBox, + ::Settings::SavedStarGiftBox, _window, _peer, _entries[index].gift)); diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.h b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.h index f7cd71001..26423e71e 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.h +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.h @@ -16,7 +16,7 @@ struct PeerListState; namespace Info::PeerGifts { struct ListState { - std::vector list; + std::vector list; QString offset; }; diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index 176ea586d..e7c59e109 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -33,11 +33,11 @@ inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile sti inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#f041c42d flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#74067321 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto ttl_seconds:flags.0?int query:flags.1?string = InputMedia; +inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; +inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#fb52dc99 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; +inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; @@ -103,7 +103,7 @@ channel#e00998b7 flags:# creator:flags.0?true left:flags.2?true broadcast:flags. channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#9ff3b858 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification = ChatFull; +channelFull#52d6806b flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int = ChatFull; chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; @@ -124,7 +124,7 @@ messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_ messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#dbbdf614 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo ttl_seconds:flags.2?int = MessageMedia; +messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; @@ -183,8 +183,8 @@ messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector availability_issued:int availability_total:int = StarGift; +starGiftUnique#f2fe7e4a flags:# id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int = StarGift; payments.starGiftsNotModified#a388a368 = payments.StarGifts; payments.starGifts#901689ea hash:int gifts:Vector = payments.StarGifts; -userStarGift#325835e1 flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true from_id:flags.1?long date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long = UserStarGift; - -payments.userStarGifts#6b65b517 flags:# count:int gifts:Vector next_offset:flags.0?string users:Vector = payments.UserStarGifts; - messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; @@ -1918,7 +1914,7 @@ botVerification#f93cd45c bot_id:long icon:long description:string = BotVerificat starGiftAttributeModel#39d99013 name:string document:Document rarity_permille:int = StarGiftAttribute; starGiftAttributePattern#13acff19 name:string document:Document rarity_permille:int = StarGiftAttribute; starGiftAttributeBackdrop#94271762 name:string center_color:int edge_color:int pattern_color:int text_color:int rarity_permille:int = StarGiftAttribute; -starGiftAttributeOriginalDetails#c02c4f4b flags:# sender_id:flags.0?long recipient_id:long date:int message:flags.1?TextWithEntities = StarGiftAttribute; +starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; payments.starGiftUpgradePreview#167bd90b sample_attributes:Vector = payments.StarGiftUpgradePreview; @@ -1929,6 +1925,15 @@ payments.uniqueStarGift#caa2f60b gift:StarGift users:Vector = payments.Uni messages.webPagePreview#b53e8b21 media:MessageMedia users:Vector = messages.WebPagePreview; +savedStarGift#6056dba5 flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long = SavedStarGift; + +payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; + +inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; +inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; + +payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2123,7 +2128,7 @@ messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; messages.sendMessage#983f9745 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long = Updates; messages.sendMedia#7852834e flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long = Updates; -messages.forwardMessages#d5039208 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut = Updates; +messages.forwardMessages#6d74da08 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut video_timestamp:flags.20?int = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; @@ -2507,9 +2512,8 @@ payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; payments.getStarsGiveawayOptions#bd1efd3e = Vector; payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.getUserStarGifts#5e72c7e1 user_id:InputUser offset:string limit:int = payments.UserStarGifts; -payments.saveStarGift#92fd2aae flags:# unsave:flags.0?true msg_id:int = Bool; -payments.convertStarGift#72770c83 msg_id:int = Bool; +payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; +payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; @@ -2517,10 +2521,13 @@ payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true o payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#cf4f0781 flags:# keep_original_details:flags.0?true msg_id:int = Updates; -payments.transferStarGift#333fb526 msg_id:int to_id:InputUser = Updates; -payments.getUserStarGift#b502e4a5 msg_id:Vector = payments.UserStarGifts; +payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; +payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; +payments.getSavedStarGifts#23830de9 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_limited:flags.3?true exclude_unique:flags.4?true sort_by_value:flags.5?true peer:InputPeer offset:string limit:int = payments.SavedStarGifts; +payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; +payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; +payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; diff --git a/Telegram/SourceFiles/payments/payments_form.cpp b/Telegram/SourceFiles/payments/payments_form.cpp index 741bf12cc..7f4e26a9f 100644 --- a/Telegram/SourceFiles/payments/payments_form.cpp +++ b/Telegram/SourceFiles/payments/payments_form.cpp @@ -122,7 +122,7 @@ not_null SessionFromId(const InvoiceId &id) { } else if (const auto slug = std::get_if(&id.value)) { return slug->session; } else if (const auto gift = std::get_if(&id.value)) { - return &gift->user->session(); + return &gift->recipient->session(); } const auto &giftCode = v::get(id.value); const auto users = std::get_if( @@ -385,12 +385,12 @@ MTPInputInvoice Form::inputInvoice() const { MTP_flags((gift->anonymous ? Flag::f_hide_name : Flag(0)) | (gift->message.empty() ? Flag(0) : Flag::f_message) | (gift->upgraded ? Flag::f_include_upgrade : Flag(0))), - gift->user->inputUser, + gift->recipient->input, MTP_long(gift->giftId), MTP_textWithEntities( MTP_string(gift->message.text), Api::EntitiesToMTP( - &gift->user->session(), + &gift->recipient->session(), gift->message.entities, Api::ConvertOption::SkipLocal))); } diff --git a/Telegram/SourceFiles/payments/payments_form.h b/Telegram/SourceFiles/payments/payments_form.h index e2df89143..8dae0d008 100644 --- a/Telegram/SourceFiles/payments/payments_form.h +++ b/Telegram/SourceFiles/payments/payments_form.h @@ -177,7 +177,7 @@ struct InvoiceStarGift { uint64 giftId = 0; uint64 randomId = 0; TextWithEntities message; - not_null user; + not_null recipient; int limitedCount = 0; bool anonymous = false; bool upgraded = false; diff --git a/Telegram/SourceFiles/payments/payments_non_panel_process.cpp b/Telegram/SourceFiles/payments/payments_non_panel_process.cpp index 0b9e292fd..c76430820 100644 --- a/Telegram/SourceFiles/payments/payments_non_panel_process.cpp +++ b/Telegram/SourceFiles/payments/payments_non_panel_process.cpp @@ -117,7 +117,7 @@ void ProcessCreditsPayment( auto source = !starGift ? SmallBalanceSource(SmallBalanceBot{ .botId = form->botId }) : SmallBalanceSource(SmallBalanceStarGift{ - .userId = peerToUser(starGift->user->id) + .recipientId = starGift->recipient->id, }); MaybeRequestBalanceIncrease(show, form->invoice.credits, source, done); } diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index 8a3f793ca..6adaf6e68 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -172,17 +172,27 @@ private: }; +[[nodiscard]] Data::SavedStarGiftId EntryToSavedStarGiftId( + not_null session, + const Data::CreditsHistoryEntry &entry) { + return (entry.bareGiftListPeerId && entry.giftSavedId) + ? Data::SavedStarGiftId::Chat( + session->data().peer(PeerId(entry.bareGiftListPeerId)), + entry.giftSavedId) + : Data::SavedStarGiftId::User(MsgId(entry.bareMsgId)); +} + void ToggleStarGiftSaved( std::shared_ptr show, not_null sender, - MsgId itemId, + Data::SavedStarGiftId savedId, bool save, Fn done) { using Flag = MTPpayments_SaveStarGift::Flag; const auto api = &show->session().api(); api->request(MTPpayments_SaveStarGift( MTP_flags(save ? Flag(0) : Flag::f_unsave), - MTP_int(itemId.bare) + Api::InputSavedStarGiftId(savedId) )).done([=] { done(true); show->showToast((save @@ -229,12 +239,12 @@ void ConfirmConvertStarGift( void ConvertStarGift( std::shared_ptr show, not_null sender, - MsgId itemId, + Data::SavedStarGiftId savedId, int stars, Fn done) { const auto api = &show->session().api(); api->request(MTPpayments_ConvertStarGift( - MTP_int(itemId) + Api::InputSavedStarGiftId(savedId) )).done([=] { if (const auto window = show->resolveWindow()) { window->showSettings(Settings::CreditsId()); @@ -851,14 +861,15 @@ void FillUniqueGiftMenu( shareBoxSt ? *shareBoxSt : ShareBoxStyleOverrides()); }, st.share ? st.share : &st::menuIconShare); - const auto messageId = MsgId(e.bareMsgId); + const auto savedId = EntryToSavedStarGiftId(&show->session(), e); const auto transfer = e.in - && messageId + && savedId + && (savedId.isUser() ? e.in : savedId.chat()->canManageGifts()) && (unique->starsForTransfer >= 0); if (transfer) { menu->addAction(tr::lng_gift_transfer_button(tr::now), [=] { if (const auto window = show->resolveWindow()) { - ShowTransferGiftBox(window, unique, messageId); + ShowTransferGiftBox(window, unique, savedId); } }, st.transfer ? st.transfer : &st::menuIconReplace); } @@ -1102,6 +1113,11 @@ void GenericCreditsEntryBox( const auto giftToSelf = isStarGift && (e.barePeerId == selfPeerId) && (e.in || e.bareGiftOwnerId == selfPeerId); + const auto giftToChannel = isStarGift && e.giftSavedId; + const auto giftToChannelCanManage = isStarGift + && e.giftSavedId + && session->data().peer( + PeerId(e.bareGiftListPeerId))->canManageGifts(); if (!uniqueGift) { Ui::AddSkip(content); @@ -1292,16 +1308,27 @@ void GenericCreditsEntryBox( && giftToSelf && !(couldConvert || nonConvertible)) ? tr::lng_action_gift_self_about_unique( - Ui::Text::WithEntities) // todo channel gifts + Ui::Text::WithEntities) + : (e.starsToUpgrade + && giftToChannelCanManage + && !(couldConvert || nonConvertible)) + ? tr::lng_action_gift_channel_about_unique( + Ui::Text::WithEntities) : ((couldConvert || nonConvertible) ? (e.savedToProfile - ? tr::lng_action_gift_can_remove_text - : tr::lng_action_gift_got_gift_text)( - Ui::Text::WithEntities) + ? (giftToChannel + ? tr::lng_action_gift_can_remove_channel + : tr::lng_action_gift_can_remove_text) + : (giftToChannel + ? tr::lng_action_gift_got_gift_channel + : tr::lng_action_gift_got_gift_text))( + Ui::Text::WithEntities) : rpl::combine( (canConvert - ? (giftToSelf // todo channel gifts + ? (giftToSelf ? tr::lng_action_gift_self_about + : giftToChannelCanManage + ? tr::lng_action_gift_channel_about : tr::lng_action_gift_got_stars_text) : tr::lng_gift_got_stars)( lt_count, @@ -1374,14 +1401,12 @@ void GenericCreditsEntryBox( && !e.giftRefunded; const auto toggleVisibility = [=, weak = Ui::MakeWeak(box)](bool save) { const auto showSection = !e.fromGiftsList; - const auto itemId = MsgId(e.bareMsgId); + const auto savedId = EntryToSavedStarGiftId(&show->session(), e); const auto done = [=](bool ok) { if (ok) { using GiftAction = Data::GiftUpdate::Action; show->session().data().notifyGiftUpdate({ - .itemId = FullMsgId( - starGiftSender->id, - itemId), + .id = savedId, .action = (save ? GiftAction::Save : GiftAction::Unsave), @@ -1403,24 +1428,27 @@ void GenericCreditsEntryBox( } } }; - ToggleStarGiftSaved(show, starGiftSender, itemId, save, done); + ToggleStarGiftSaved(show, starGiftSender, savedId, save, done); }; const auto upgradeGuard = std::make_shared(); const auto upgrade = [=] { - const auto itemId = MsgId(e.bareMsgId); const auto window = show->resolveWindow(); if (!window || *upgradeGuard) { return; } *upgradeGuard = true; + const auto savedId = EntryToSavedStarGiftId(&window->session(), e); + const auto openWhenDone = giftToChannel + ? window->session().data().peer(PeerId(e.bareGiftOwnerId)).get() + : starGiftSender; using namespace Ui; ShowStarGiftUpgradeBox({ .controller = window, .stargiftId = e.stargiftId, .ready = [=](bool) { *upgradeGuard = false; }, - .peer = starGiftSender, - .itemId = itemId, + .peer = openWhenDone, + .savedId = savedId, .cost = e.starsUpgradedBySender ? 0 : e.starsToUpgrade, .canAddSender = !giftToSelf && !e.anonymous, .canAddComment = (!giftToSelf @@ -1433,7 +1461,7 @@ void GenericCreditsEntryBox( }; const auto canUpgrade = e.stargiftId && e.canUpgradeGift - && (e.in || giftToSelf) + && (e.in || giftToSelf || giftToChannelCanManage) && !e.uniqueGift; const auto canUpgradeFree = canUpgrade && (e.starsUpgradedBySender > 0); @@ -1448,15 +1476,15 @@ void GenericCreditsEntryBox( return; } state->convertButtonBusy = true; - const auto itemId = MsgId(e.bareMsgId); + const auto savedId = EntryToSavedStarGiftId( + &show->session(), + e); if (stars) { const auto done = [=](bool ok) { if (ok) { using GiftAction = Data::GiftUpdate::Action; show->session().data().notifyGiftUpdate({ - .itemId = FullMsgId( - starGiftSender->id, - itemId), + .id = savedId, .action = GiftAction::Convert, }); } @@ -1471,7 +1499,7 @@ void GenericCreditsEntryBox( ConvertStarGift( show, starGiftSender, - itemId, + savedId, stars, done); } @@ -1503,34 +1531,40 @@ void GenericCreditsEntryBox( tr::lng_credits_box_out_about_link(tr::now)), Ui::Text::WithEntities), st::creditsBoxAboutDivider))); - } else if (gotStarGift) { + } else if (gotStarGift || giftToChannelCanManage) { + const auto hiddenPhrase = giftToChannelCanManage + ? tr::lng_gift_hidden_hint_channel + : tr::lng_gift_hidden_hint; + const auto visiblePhrase = giftToChannelCanManage + ? tr::lng_gift_visible_hint_channel + : tr::lng_gift_visible_hint; auto withHide = rpl::combine( - tr::lng_gift_visible_hint(), + visiblePhrase(), tr::lng_gift_visible_hide() ) | rpl::map([](QString &&hint, QString &&hide) { return TextWithEntities{ std::move(hint) }.append(' ').append( Ui::Text::Link(std::move(hide))); }); - auto text = !e.savedToProfile // todo channel gifts - ? tr::lng_gift_hidden_hint(Ui::Text::WithEntities) + auto text = !e.savedToProfile + ? hiddenPhrase(Ui::Text::WithEntities) : canToggle ? std::move(withHide) - : tr::lng_gift_visible_hint(Ui::Text::WithEntities); + : visiblePhrase(Ui::Text::WithEntities); if (e.anonymous && e.barePeerId) { text = rpl::combine( std::move(text), - tr::lng_gift_anonymous_hint() + (giftToChannelCanManage + ? tr::lng_gift_anonymous_hint_channel + : tr::lng_gift_anonymous_hint)() ) | rpl::map([](TextWithEntities &&a, QString &&b) { return a.append("\n\n").append(b); }); } const auto label = box->addRow( - object_ptr>( + object_ptr( box, - object_ptr( - box, - std::move(text), - st::creditsBoxAboutDivider)))->entity(); + std::move(text), + st::creditsBoxAboutDivider)); label->setClickHandlerFilter([=](const auto &...) { toggleVisibility(!e.savedToProfile); return false; @@ -1612,7 +1646,9 @@ void GenericCreditsEntryBox( : canUpgradeFree ? tr::lng_gift_upgrade_free() : (canToggle && !e.savedToProfile) - ? tr::lng_gift_show_on_page() + ? (e.giftSavedId + ? tr::lng_gift_show_on_channel + : tr::lng_gift_show_on_page)() : tr::lng_box_ok())); const auto send = [=, weak = Ui::MakeWeak(box)] { if (toRejoin) { @@ -1779,11 +1815,12 @@ void GlobalStarGiftBox( st); } -void UserStarGiftBox( +void SavedStarGiftBox( not_null box, not_null controller, not_null owner, - const Data::UserStarGift &data) { + const Data::SavedStarGift &data) { + const auto chatGiftPeer = data.id.chat(); Settings::ReceiptCreditsBox( box, controller, @@ -1791,10 +1828,13 @@ void UserStarGiftBox( .description = data.message, .date = base::unixtime::parse(data.date), .credits = StarsAmount(data.info.stars), - .bareMsgId = uint64(data.messageId.bare), + .bareMsgId = uint64(data.id.userMessageId().bare), .barePeerId = data.fromId.value, .bareGiftStickerId = data.info.document->id, .bareGiftOwnerId = owner->id.value, + .bareActorId = data.fromId.value, + .bareGiftListPeerId = chatGiftPeer ? chatGiftPeer->id.value : 0, + .giftSavedId = data.id.chatSavedId(), .stargiftId = data.info.id, .uniqueGift = data.info.unique, .peerType = Data::CreditsHistoryEntry::PeerType::Peer, @@ -1820,8 +1860,10 @@ void StarGiftViewBox( not_null controller, const Data::GiftCode &data, not_null item) { - const auto incoming = data.upgrade ? item->out() : !item->out(); const auto peer = item->history()->peer; + const auto toChannel = peer->isServiceUser() && data.channel; + const auto incoming = !toChannel + && (data.upgrade ? item->out() : !item->out()); const auto fromId = incoming ? peer->id : peer->session().userPeerId(); const auto toId = incoming ? peer->session().userPeerId() : peer->id; const auto entry = Data::CreditsHistoryEntry{ @@ -1835,6 +1877,9 @@ void StarGiftViewBox( .bareGiftOwnerId = (data.unique ? data.unique->ownerId.value : toId.value), + .bareActorId = (toChannel ? data.channelFrom->id.value : 0), + .bareGiftListPeerId = (toChannel ? data.channel->id.value : 0), + .giftSavedId = data.channelSavedId, .stargiftId = data.stargiftId, .uniqueGift = data.unique, .peerType = Data::CreditsHistoryEntry::PeerType::Peer, @@ -1995,7 +2040,7 @@ void SmallBalanceBox( }, [](SmallBalanceDeepLink value) { return QString(); }, [&](SmallBalanceStarGift value) { - return owner->peer(peerFromUser(value.userId))->shortName(); + return owner->peer(value.recipientId)->shortName(); }); auto needed = show->session().credits().balanceValue( diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.h b/Telegram/SourceFiles/settings/settings_credits_graphics.h index 97eeaf13b..599ced1f3 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.h +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.h @@ -23,7 +23,7 @@ struct CreditsHistoryEntry; struct SubscriptionEntry; struct GiftCode; struct CreditTopupOption; -struct UserStarGift; +struct SavedStarGift; struct StarGift; } // namespace Data @@ -149,11 +149,11 @@ void GlobalStarGiftBox( std::shared_ptr show, const Data::StarGift &data, CreditsEntryBoxStyleOverrides st = {}); -void UserStarGiftBox( +void SavedStarGiftBox( not_null box, not_null controller, not_null owner, - const Data::UserStarGift &data); + const Data::SavedStarGift &data); void StarGiftViewBox( not_null box, not_null controller, @@ -198,7 +198,7 @@ struct SmallBalanceDeepLink { QString purpose; }; struct SmallBalanceStarGift { - UserId userId = 0; + PeerId recipientId; }; struct SmallBalanceSource : std::variant< SmallBalanceBot, diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 76fe469a3..8830f8dd6 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -1241,7 +1241,8 @@ void Filler::addSendGift() { || user->isVerifyCodes() || !user->session().premiumCanBuy())) { return; - } else if (channel && channel->isForbidden()) { + } else if (channel + && (channel->isForbidden() || !channel->stargiftsAvailable())) { return; }