Update API scheme on layer 198.

This commit is contained in:
John Preston 2025-01-15 14:26:22 +04:00
parent 569dd19932
commit a174119877
36 changed files with 403 additions and 160 deletions

View file

@ -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";

View file

@ -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

View file

@ -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<void()> done,
Fn<void(QString)> fail);
[[nodiscard]] MTPInputSavedStarGift InputSavedStarGiftId(
const Data::SavedStarGiftId &id);
} // namespace Api

View file

@ -285,6 +285,7 @@ mtpRequestId EditTextMessage(
document->mtpInput(),
MTPInputPhoto(), // video_cover
MTP_int(media->ttlSeconds()),
MTPint(), // video_timestamp
MTPstring()); // query
};
takeFileReference = [=] { return document->fileReference(); };

View file

@ -122,6 +122,7 @@ MTPInputMedia PrepareUploadedDocument(
MTP_vector<MTPInputDocument>(
ranges::to<QVector<MTPInputDocument>>(info.attachedStickers)),
MTPInputPhoto(), // video_cover
MTP_int(0), // video_timestamp
MTP_int(ttlSeconds));
}

View file

@ -809,8 +809,9 @@ std::optional<Data::StarGift> 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<Data::StarGift> FromTL(
});
}
std::optional<Data::UserStarGift> FromTL(
std::optional<Data::SavedStarGift> FromTL(
not_null<PeerData*> 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<Data::UserStarGift> 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<Data::UserStarGift> 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();

View file

@ -259,9 +259,9 @@ enum class RequirePremiumState {
[[nodiscard]] std::optional<Data::StarGift> FromTL(
not_null<Main::Session*> session,
const MTPstarGift &gift);
[[nodiscard]] std::optional<Data::UserStarGift> FromTL(
[[nodiscard]] std::optional<Data::SavedStarGift> FromTL(
not_null<PeerData*> to,
const MTPuserStarGift &gift);
const MTPsavedStarGift &gift);
[[nodiscard]] Data::UniqueGiftModel FromTL(
not_null<Main::Session*> session,

View file

@ -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<MTPDocument>(), // 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<MTPDocument>(), // 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<MTPDocument>(), // alt_documents
MTPPhoto(), // video_cover
MTPint(), // video_timestamp
MTP_int(ttlSeconds));
} else {
Unexpected("Type in sendFilesConfirmed.");

View file

@ -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;

View file

@ -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<Ui::ImportantTooltip*>(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<void()>([=] {
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<void()>([=] {
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,

View file

@ -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);

View file

@ -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::SessionController*> window,
MsgId messageId,
Data::SavedStarGiftId savedId,
bool keepDetails,
int stars,
Fn<void(Payments::CheckoutResult)> 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<State>();
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();

View file

@ -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<uint64> stargiftId;
Fn<void(bool)> ready;
not_null<PeerData*> peer;
MsgId itemId = 0;
Data::SavedStarGiftId savedId;
int cost = 0;
bool canAddSender = false;
bool canAddComment = false;

View file

@ -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::SessionController*> window,
not_null<PeerData*> to,
std::shared_ptr<Data::UniqueGift> gift,
MsgId messageId,
Data::SavedStarGiftId savedId,
Fn<void(Payments::CheckoutResult)> 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<Window::SessionController*> controller,
not_null<PeerData*> peer,
std::shared_ptr<Data::UniqueGift> gift,
MsgId msgId) {
Data::SavedStarGiftId savedId) {
const auto stars = gift->starsForTransfer;
controller->show(Box([=](not_null<Ui::GenericBox*> 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::SessionController*> window,
std::shared_ptr<Data::UniqueGift> gift,
MsgId msgId) {
Data::SavedStarGiftId savedId) {
auto controller = std::make_unique<Controller>(
window,
gift,
[=](not_null<PeerData*> peer) {
ShowTransferToBox(window, peer, gift, msgId);
ShowTransferToBox(window, peer, gift, savedId);
});
const auto controllerRaw = controller.get();
auto initBox = [=](not_null<PeerListBox*> box) {

View file

@ -13,9 +13,10 @@ class SessionController;
namespace Data {
struct UniqueGift;
class SavedStarGiftId;
} // namespace Data
void ShowTransferGiftBox(
not_null<Window::SessionController*> window,
std::shared_ptr<Data::UniqueGift> gift,
MsgId msgId);
Data::SavedStarGiftId savedId);

View file

@ -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());

View file

@ -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<ChannelDataFlag>;
@ -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<PeerData*> participant);
@ -375,7 +379,6 @@ public:
[[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const;
[[nodiscard]] bool canRestrictParticipant(
not_null<PeerData*> participant) const;
[[nodiscard]] bool canManageGifts() const;
void setBotVerifyDetails(Ui::BotVerifyDetails details);
void setBotVerifyDetailsIcon(DocumentId iconId);

View file

@ -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> uniqueGift;
StarsAmount starrefAmount;

View file

@ -141,6 +141,8 @@ struct GiftCode {
std::shared_ptr<UniqueGift> unique;
TextWithEntities message;
ChannelData *channel = nullptr;
PeerData *channelFrom = nullptr;
uint64 channelSavedId = 0;
MsgId giveawayMsgId = 0;
MsgId upgradeMsgId = 0;
int starsConverted = 0;

View file

@ -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();

View file

@ -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.

View file

@ -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 = {};
};

View file

@ -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<PeerData*> 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;

View file

@ -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;

View file

@ -192,7 +192,7 @@ void History::itemVanished(not_null<HistoryItem*> 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,
});
}

View file

@ -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(),

View file

@ -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<MTPint>(1, MTP_int(upgradeTo))
)).done([=](const MTPpayments_UserStarGifts &result) {
controller->session().api().request(MTPpayments_GetSavedStarGift(
MTP_vector<MTPInputSavedStarGift>(
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));

View file

@ -34,7 +34,7 @@ constexpr auto kPerPage = 50;
[[nodiscard]] GiftDescriptor DescriptorForGift(
not_null<PeerData*> 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));

View file

@ -16,7 +16,7 @@ struct PeerListState;
namespace Info::PeerGifts {
struct ListState {
std::vector<Data::UserStarGift> list;
std::vector<Data::SavedStarGift> list;
QString offset;
};

View file

@ -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<DocumentAttribute> stickers:flags.0?Vector<InputDocument> 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<DocumentAttribute> stickers:flags.0?Vector<InputDocument> 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<BotInfo> 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<long> 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<BotInfo> 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<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> 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<BotInfo> 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<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> 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<Document> 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<Document> 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<RequestedPe
messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction;
messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction;
messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction;
messageActionStarGift#d8f4f0a7 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long = MessageAction;
messageActionStarGiftUnique#26077b99 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long = MessageAction;
messageActionStarGift#4717e8a4 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long = MessageAction;
messageActionStarGiftUnique#acdfcb81 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long = MessageAction;
dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
@ -1475,9 +1475,9 @@ inputInvoiceSlug#c326caef slug:string = InputInvoice;
inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice;
inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice;
inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice;
inputInvoiceStarGift#25d8c1d8 flags:# hide_name:flags.0?true include_upgrade:flags.2?true user_id:InputUser gift_id:long message:flags.1?TextWithEntities = InputInvoice;
inputInvoiceStarGiftUpgrade#5ebe7262 flags:# keep_original_details:flags.0?true msg_id:int = InputInvoice;
inputInvoiceStarGiftTransfer#ae3ba9ed msg_id:int to_id:InputUser = InputInvoice;
inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice;
inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice;
inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice;
payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice;
@ -1877,15 +1877,11 @@ starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true
starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;
starGift#2cc73c8 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long = StarGift;
starGiftUnique#3482f322 flags:# id:long title:string slug:string num:int owner_id:flags.0?long owner_name:flags.1?string attributes:Vector<StarGiftAttribute> 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<StarGiftAttribute> availability_issued:int availability_total:int = StarGift;
payments.starGiftsNotModified#a388a368 = payments.StarGifts;
payments.starGifts#901689ea hash:int gifts:Vector<StarGift> = 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<UserStarGift> next_offset:flags.0?string users:Vector<User> = payments.UserStarGifts;
messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption;
reportResultChooseOption#f0e4e0b6 title:string options:Vector<MessageReportOption> = 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<StarGiftAttribute> = payments.StarGiftUpgradePreview;
@ -1929,6 +1925,15 @@ payments.uniqueStarGift#caa2f60b gift:StarGift users:Vector<User> = payments.Uni
messages.webPagePreview#b53e8b21 media:MessageMedia users:Vector<User> = 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<SavedStarGift> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = 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<ReceivedNotifyMessage>;
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<MessageEntity> 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<MessageEntity> 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<int> random_id:Vector<long> 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<int> random_id:Vector<long> 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<int> 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<StarsGiveawayOption>;
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<int> = 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<InputSavedStarGift> = 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<InputStickerSetItem> software:flags.3?string = messages.StickerSet;
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;

View file

@ -122,7 +122,7 @@ not_null<Main::Session*> SessionFromId(const InvoiceId &id) {
} else if (const auto slug = std::get_if<InvoiceCredits>(&id.value)) {
return slug->session;
} else if (const auto gift = std::get_if<InvoiceStarGift>(&id.value)) {
return &gift->user->session();
return &gift->recipient->session();
}
const auto &giftCode = v::get<InvoicePremiumGiftCode>(id.value);
const auto users = std::get_if<InvoicePremiumGiftCodeUsers>(
@ -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)));
}

View file

@ -177,7 +177,7 @@ struct InvoiceStarGift {
uint64 giftId = 0;
uint64 randomId = 0;
TextWithEntities message;
not_null<UserData*> user;
not_null<PeerData*> recipient;
int limitedCount = 0;
bool anonymous = false;
bool upgraded = false;

View file

@ -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);
}

View file

@ -172,17 +172,27 @@ private:
};
[[nodiscard]] Data::SavedStarGiftId EntryToSavedStarGiftId(
not_null<Main::Session*> 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<ChatHelpers::Show> show,
not_null<UserData*> sender,
MsgId itemId,
Data::SavedStarGiftId savedId,
bool save,
Fn<void(bool)> 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<ChatHelpers::Show> show,
not_null<UserData*> sender,
MsgId itemId,
Data::SavedStarGiftId savedId,
int stars,
Fn<void(bool)> 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<bool>();
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<Ui::CenterWrap<Ui::FlatLabel>>(
object_ptr<Ui::FlatLabel>(
box,
object_ptr<Ui::FlatLabel>(
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<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<PeerData*> 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<Window::SessionController*> controller,
const Data::GiftCode &data,
not_null<HistoryItem*> 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(

View file

@ -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<ChatHelpers::Show> show,
const Data::StarGift &data,
CreditsEntryBoxStyleOverrides st = {});
void UserStarGiftBox(
void SavedStarGiftBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
not_null<PeerData*> owner,
const Data::UserStarGift &data);
const Data::SavedStarGift &data);
void StarGiftViewBox(
not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller,
@ -198,7 +198,7 @@ struct SmallBalanceDeepLink {
QString purpose;
};
struct SmallBalanceStarGift {
UserId userId = 0;
PeerId recipientId;
};
struct SmallBalanceSource : std::variant<
SmallBalanceBot,

View file

@ -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;
}