Implement buying gifts for myself.

This commit is contained in:
John Preston 2024-12-31 21:40:18 +04:00
parent a7321c9beb
commit 8895b4e8a3
8 changed files with 349 additions and 128 deletions

View file

@ -2019,11 +2019,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_gift_unique_received" = "{user} sent you a unique collectible item"; "lng_action_gift_unique_received" = "{user} sent you a unique collectible item";
"lng_action_gift_sent" = "You sent a gift for {cost}"; "lng_action_gift_sent" = "You sent a gift for {cost}";
"lng_action_gift_unique_sent" = "You sent a unique collectible item"; "lng_action_gift_unique_sent" = "You sent a unique collectible item";
"lng_action_gift_upgraded" = "{user} turned the gift from you to a unique collectible"; "lng_action_gift_upgraded" = "{user} turned the gift from you into a unique collectible";
"lng_action_gift_upgraded_mine" = "You turned the gift from {user} to a unique collectible"; "lng_action_gift_upgraded_mine" = "You turned the gift from {user} into a unique collectible";
"lng_action_gift_upgraded_self" = "You turned this gift into a unique collectible";
"lng_action_gift_transferred" = "{user} transferred you a gift"; "lng_action_gift_transferred" = "{user} transferred you a gift";
"lng_action_gift_transferred_mine" = "You transferred a gift to {user}"; "lng_action_gift_transferred_mine" = "You transferred a gift to {user}";
"lng_action_gift_received_anonymous" = "Unknown user sent you a gift for {cost}"; "lng_action_gift_received_anonymous" = "Unknown user sent you a gift for {cost}";
"lng_action_gift_self_bought" = "You bought a gift for {cost}";
"lng_action_gift_self_subtitle" = "Saved Gift";
"lng_action_gift_self_about#one" = "Display this gift on your page or convert it to **{count}** Star.";
"lng_action_gift_self_about#other" = "Display this gift on your page or convert it to **{count}** Stars.";
"lng_action_gift_self_about_unique" = "You can display this gift on your page or turn it into unique collectible and send to others.";
"lng_action_gift_for_stars#one" = "{count} Star"; "lng_action_gift_for_stars#one" = "{count} Star";
"lng_action_gift_for_stars#other" = "{count} Stars"; "lng_action_gift_for_stars#other" = "{count} Stars";
"lng_action_gift_got_subtitle" = "Gift from {user}"; "lng_action_gift_got_subtitle" = "Gift from {user}";
@ -3230,12 +3236,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gift_send_title" = "Send a Gift"; "lng_gift_send_title" = "Send a Gift";
"lng_gift_send_message" = "Enter Message"; "lng_gift_send_message" = "Enter Message";
"lng_gift_send_anonymous" = "Hide My Name"; "lng_gift_send_anonymous" = "Hide My Name";
"lng_gift_send_anonymous_self" = "Hide my name and message from visitors to my profile.";
"lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message."; "lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message.";
"lng_gift_send_unique" = "Make Unique for {price}"; "lng_gift_send_unique" = "Make Unique for {price}";
"lng_gift_send_unique_about" = "Enable this to let {user} turn your gift into a unique collectible. {link}"; "lng_gift_send_unique_about" = "Enable this to let {user} turn your gift into a unique collectible. {link}";
"lng_gift_send_unique_link" = "Learn More >"; "lng_gift_send_unique_link" = "Learn More >";
"lng_gift_send_premium_about" = "Only {user} will see your message."; "lng_gift_send_premium_about" = "Only {user} will see your message.";
"lng_gift_send_button" = "Send a Gift for {cost}"; "lng_gift_send_button" = "Send a Gift for {cost}";
"lng_gift_send_button_self" = "Buy a Gift for {cost}";
"lng_gift_sent_title" = "Gift Sent!"; "lng_gift_sent_title" = "Gift Sent!";
"lng_gift_sent_about#one" = "You spent **{count}** Star from your balance."; "lng_gift_sent_about#one" = "You spent **{count}** Star from your balance.";
"lng_gift_sent_about#other" = "You spent **{count}** Stars from your balance."; "lng_gift_sent_about#other" = "You spent **{count}** Stars from your balance.";
@ -3254,6 +3262,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gift_visibility_hidden" = "Not visible on your page"; "lng_gift_visibility_hidden" = "Not visible on your page";
"lng_gift_visibility_show" = "show"; "lng_gift_visibility_show" = "show";
"lng_gift_visibility_hide" = "hide"; "lng_gift_visibility_hide" = "hide";
"lng_gift_self_status" = "buy yourself a gift";
"lng_gift_self_title" = "Buy a Gift";
"lng_gift_self_about" = "Buy yourself a gift to display on your page or reserve for later.\n\nLimited-edition gifts upgraded to collectibles can be gifted to others later.";
"lng_gift_unique_owner" = "Owner"; "lng_gift_unique_owner" = "Owner";
"lng_gift_unique_owner_change" = "change"; "lng_gift_unique_owner_change" = "change";
"lng_gift_unique_status" = "Status"; "lng_gift_unique_status" = "Status";
@ -3307,6 +3318,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gift_upgrade_free" = "Upgrade for Free"; "lng_gift_upgrade_free" = "Upgrade for Free";
"lng_gift_upgrade_confirm" = "Confirm"; "lng_gift_upgrade_confirm" = "Confirm";
"lng_gift_upgrade_add_my" = "Add my name to the gift"; "lng_gift_upgrade_add_my" = "Add my name to the gift";
"lng_gift_upgrade_add_my_comment" = "Add my name and comment";
"lng_gift_upgrade_add_sender" = "Add sender's name to the gift"; "lng_gift_upgrade_add_sender" = "Add sender's name to the gift";
"lng_gift_upgrade_add_comment" = "Add sender's name and comment"; "lng_gift_upgrade_add_comment" = "Add sender's name and comment";
"lng_gift_upgraded_title" = "Gift Upgraded"; "lng_gift_upgraded_title" = "Gift Upgraded";

View file

@ -1203,6 +1203,9 @@ void AddStarGiftTable(
const auto peerId = PeerId(entry.barePeerId); const auto peerId = PeerId(entry.barePeerId);
const auto session = &controller->session(); const auto session = &controller->session();
const auto unique = entry.uniqueGift.get(); const auto unique = entry.uniqueGift.get();
const auto chatPeerId = entry.fromGiftsList
? entry.bareGiftOwnerId
: entry.barePeerId;
if (unique) { if (unique) {
const auto ownerId = PeerId(entry.bareGiftOwnerId); const auto ownerId = PeerId(entry.bareGiftOwnerId);
const auto transfer = entry.in const auto transfer = entry.in
@ -1221,17 +1224,19 @@ void AddStarGiftTable(
MakePeerTableValue(table, controller, ownerId, send, handler), MakePeerTableValue(table, controller, ownerId, send, handler),
st::giveawayGiftCodePeerMargin); st::giveawayGiftCodePeerMargin);
} else if (peerId) { } else if (peerId) {
const auto user = session->data().peer(peerId)->asUser(); if (chatPeerId != session->userPeerId().value) {
const auto withSendButton = entry.in && user && !user->isBot(); const auto user = session->data().peer(peerId)->asUser();
auto send = withSendButton ? tr::lng_gift_send_small() : nullptr; const auto withSendButton = entry.in && user && !user->isBot();
auto handler = send ? Fn<void()>([=] { auto send = withSendButton ? tr::lng_gift_send_small() : nullptr;
Ui::ShowStarGiftBox(controller->parentController(), user); auto handler = send ? Fn<void()>([=] {
}) : nullptr; Ui::ShowStarGiftBox(controller->parentController(), user);
AddTableRow( }) : nullptr;
table, AddTableRow(
tr::lng_credits_box_history_entry_peer_in(), table,
MakePeerTableValue(table, controller, peerId, send, handler), tr::lng_credits_box_history_entry_peer_in(),
st::giveawayGiftCodePeerMargin); MakePeerTableValue(table, controller, peerId, send, handler),
st::giveawayGiftCodePeerMargin);
}
} else if (!entry.soldOutInfo) { } else if (!entry.soldOutInfo) {
AddTableRow( AddTableRow(
table, table,

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer_rpl.h" #include "base/timer_rpl.h"
#include "base/unixtime.h" #include "base/unixtime.h"
#include "api/api_premium.h" #include "api/api_premium.h"
#include "boxes/filters/edit_filter_chats_list.h"
#include "boxes/gift_premium_box.h" #include "boxes/gift_premium_box.h"
#include "boxes/peer_list_controllers.h" #include "boxes/peer_list_controllers.h"
#include "boxes/send_credits_box.h" #include "boxes/send_credits_box.h"
@ -138,7 +139,7 @@ class PreviewWrap final : public RpWidget {
public: public:
PreviewWrap( PreviewWrap(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Main::Session*> session, not_null<PeerData*> recipient,
rpl::producer<GiftDetails> details); rpl::producer<GiftDetails> details);
~PreviewWrap(); ~PreviewWrap();
@ -149,6 +150,7 @@ private:
void prepare(rpl::producer<GiftDetails> details); void prepare(rpl::producer<GiftDetails> details);
const not_null<History*> _history; const not_null<History*> _history;
const not_null<PeerData*> _recipient;
const std::unique_ptr<ChatTheme> _theme; const std::unique_ptr<ChatTheme> _theme;
const std::unique_ptr<ChatStyle> _style; const std::unique_ptr<ChatStyle> _style;
const std::unique_ptr<PreviewDelegate> _delegate; const std::unique_ptr<PreviewDelegate> _delegate;
@ -202,6 +204,7 @@ Context PreviewDelegate::elementContext() {
auto GenerateGiftMedia( auto GenerateGiftMedia(
not_null<Element*> parent, not_null<Element*> parent,
Element *replacing, Element *replacing,
not_null<PeerData*> recipient,
const GiftDetails &data) const GiftDetails &data)
-> Fn<void(Fn<void(std::unique_ptr<MediaGenericPart>)>)> { -> Fn<void(Fn<void(std::unique_ptr<MediaGenericPart>)>)> {
return [=](Fn<void(std::unique_ptr<MediaGenericPart>)> push) { return [=](Fn<void(std::unique_ptr<MediaGenericPart>)> push) {
@ -244,10 +247,12 @@ auto GenerateGiftMedia(
lt_count, lt_count,
gift.months); gift.months);
}, [&](const GiftTypeStars &gift) { }, [&](const GiftTypeStars &gift) {
return tr::lng_action_gift_got_subtitle( return recipient->isSelf()
tr::now, ? tr::lng_action_gift_self_subtitle(tr::now)
lt_user, : tr::lng_action_gift_got_subtitle(
parent->history()->session().user()->shortName()); tr::now,
lt_user,
recipient->session().user()->shortName());
}); });
auto textFallback = v::match(descriptor, [&](GiftTypePremium gift) { auto textFallback = v::match(descriptor, [&](GiftTypePremium gift) {
return tr::lng_action_gift_premium_about( return tr::lng_action_gift_premium_about(
@ -258,11 +263,17 @@ auto GenerateGiftMedia(
? tr::lng_action_gift_got_upgradable_text( ? tr::lng_action_gift_got_upgradable_text(
tr::now, tr::now,
Text::RichLangValue) Text::RichLangValue)
: tr::lng_action_gift_got_stars_text( : (recipient->isSelf() && gift.info.starsToUpgrade)
? tr::lng_action_gift_self_about_unique(
tr::now, tr::now,
lt_count, Text::RichLangValue)
gift.info.starsConverted, : (recipient->isSelf()
Text::RichLangValue); ? tr::lng_action_gift_self_about
: tr::lng_action_gift_got_stars_text)(
tr::now,
lt_count,
gift.info.starsConverted,
Text::RichLangValue);
}); });
auto description = data.text.empty() auto description = data.text.empty()
? std::move(textFallback) ? std::move(textFallback)
@ -386,10 +397,11 @@ void PrepareImage(
PreviewWrap::PreviewWrap( PreviewWrap::PreviewWrap(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Main::Session*> session, not_null<PeerData*> recipient,
rpl::producer<GiftDetails> details) rpl::producer<GiftDetails> details)
: RpWidget(parent) : RpWidget(parent)
, _history(session->data().history(session->userPeerId())) , _history(recipient->owner().history(recipient->session().userPeerId()))
, _recipient(recipient)
, _theme(Window::Theme::DefaultChatThemeOn(lifetime())) , _theme(Window::Theme::DefaultChatThemeOn(lifetime()))
, _style(std::make_unique<ChatStyle>( , _style(std::make_unique<ChatStyle>(
_history->session().colorIndicesValue())) _history->session().colorIndicesValue()))
@ -401,14 +413,14 @@ PreviewWrap::PreviewWrap(
_style->apply(_theme.get()); _style->apply(_theme.get());
using namespace HistoryView; using namespace HistoryView;
session->data().viewRepaintRequest( _history->owner().viewRepaintRequest(
) | rpl::start_with_next([=](not_null<const Element*> view) { ) | rpl::start_with_next([=](not_null<const Element*> view) {
if (view == _item.get()) { if (view == _item.get()) {
update(); update();
} }
}, lifetime()); }, lifetime());
session->downloaderTaskFinished() | rpl::start_with_next([=] { _history->session().downloaderTaskFinished() | rpl::start_with_next([=] {
update(); update();
}, lifetime()); }, lifetime());
@ -503,6 +515,8 @@ void PreviewWrap::prepare(rpl::producer<GiftDetails> details) {
const auto name = _history->session().user()->shortName(); const auto name = _history->session().user()->shortName();
const auto text = cost.isEmpty() const auto text = cost.isEmpty()
? tr::lng_action_gift_unique_received(tr::now, lt_user, name) ? tr::lng_action_gift_unique_received(tr::now, lt_user, name)
: _recipient->isSelf()
? tr::lng_action_gift_self_bought(tr::now, lt_cost, cost)
: tr::lng_action_gift_received( : tr::lng_action_gift_received(
tr::now, tr::now,
lt_user, lt_user,
@ -520,7 +534,7 @@ void PreviewWrap::prepare(rpl::producer<GiftDetails> details) {
auto owned = AdminLog::OwnedItem(_delegate.get(), item); auto owned = AdminLog::OwnedItem(_delegate.get(), item);
owned->overrideMedia(std::make_unique<MediaGeneric>( owned->overrideMedia(std::make_unique<MediaGeneric>(
owned.get(), owned.get(),
GenerateGiftMedia(owned.get(), _item.get(), details), GenerateGiftMedia(owned.get(), _item.get(), _recipient, details),
MediaGenericDescriptor{ MediaGenericDescriptor{
.maxWidth = st::chatIntroWidth, .maxWidth = st::chatIntroWidth,
.service = true, .service = true,
@ -1342,7 +1356,7 @@ void SendGiftBox(
const auto container = box->verticalLayout(); const auto container = box->verticalLayout();
container->add(object_ptr<PreviewWrap>( container->add(object_ptr<PreviewWrap>(
container, container,
session, peer,
state->details.value())); state->details.value()));
const auto limit = StarGiftMessageLimit(session); const auto limit = StarGiftMessageLimit(session);
@ -1394,7 +1408,8 @@ void SendGiftBox(
{ .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow }); { .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow });
if (const auto stars = std::get_if<GiftTypeStars>(&descriptor)) { if (const auto stars = std::get_if<GiftTypeStars>(&descriptor)) {
if (const auto cost = stars->info.starsToUpgrade; cost > 0) { const auto cost = stars->info.starsToUpgrade;
if (cost > 0 && !peer->isSelf()) {
const auto user = peer->asUser(); const auto user = peer->asUser();
Assert(user != nullptr); Assert(user != nullptr);
@ -1429,7 +1444,7 @@ void SendGiftBox(
container, container,
tr::lng_gift_send_anonymous(), tr::lng_gift_send_anonymous(),
st::settingsButtonNoIcon) st::settingsButtonNoIcon)
)->toggleOn(rpl::single(false))->toggledValue( )->toggleOn(rpl::single(peer->isSelf()))->toggledValue(
) | rpl::start_with_next([=](bool toggled) { ) | rpl::start_with_next([=](bool toggled) {
auto now = state->details.current(); auto now = state->details.current();
now.anonymous = toggled; now.anonymous = toggled;
@ -1442,11 +1457,13 @@ void SendGiftBox(
lt_user, lt_user,
rpl::single(peer->shortName()))); rpl::single(peer->shortName())));
}, [&](const GiftTypeStars &) { }, [&](const GiftTypeStars &) {
AddDividerText(container, tr::lng_gift_send_anonymous_about( AddDividerText(container, peer->isSelf()
lt_user, ? tr::lng_gift_send_anonymous_self()
rpl::single(peer->shortName()), : tr::lng_gift_send_anonymous_about(
lt_recipient, lt_user,
rpl::single(peer->shortName()))); rpl::single(peer->shortName()),
lt_recipient,
rpl::single(peer->shortName())));
}); });
const auto buttonWidth = st::boxWideWidth const auto buttonWidth = st::boxWideWidth
@ -1473,10 +1490,12 @@ void SendGiftBox(
}); });
SetButtonMarkedLabel( SetButtonMarkedLabel(
button, button,
tr::lng_gift_send_button( (peer->isSelf()
lt_cost, ? tr::lng_gift_send_button_self
std::move(cost), : tr::lng_gift_send_button)(
Text::WithEntities), lt_cost,
std::move(cost),
Text::WithEntities),
session, session,
st::creditsBoxButtonLabel, st::creditsBoxButtonLabel,
&st::giftBox.button.textFg); &st::giftBox.button.textFg);
@ -1715,71 +1734,209 @@ void GiftBox(
AddSkip(content); AddSkip(content);
AddSkip(box->verticalLayout()); AddSkip(box->verticalLayout());
const auto premiumClickHandlerFilter = [=](const auto &...) {
Settings::ShowPremium(window, u"gift_send"_q);
return false;
};
const auto starsClickHandlerFilter = [=](const auto &...) { const auto starsClickHandlerFilter = [=](const auto &...) {
window->showSettings(Settings::CreditsId()); window->showSettings(Settings::CreditsId());
return false; return false;
}; };
if (!peer->isSelf()) {
const auto premiumClickHandlerFilter = [=](const auto &...) {
Settings::ShowPremium(window, u"gift_send"_q);
return false;
};
AddBlock(content, window, {
.subtitle = tr::lng_gift_premium_subtitle(),
.about = tr::lng_gift_premium_about(
lt_name,
rpl::single(Text::Bold(peer->shortName())),
lt_features,
tr::lng_gift_premium_features() | Text::ToLink(),
Text::WithEntities),
.aboutFilter = premiumClickHandlerFilter,
.content = MakePremiumGifts(window, peer),
});
}
AddBlock(content, window, { AddBlock(content, window, {
.subtitle = tr::lng_gift_premium_subtitle(), .subtitle = (peer->isSelf()
.about = tr::lng_gift_premium_about( ? tr::lng_gift_self_title()
lt_name, : tr::lng_gift_stars_subtitle()),
rpl::single(Text::Bold(peer->shortName())), .about = (peer->isSelf()
lt_features, ? tr::lng_gift_self_about(Text::WithEntities)
tr::lng_gift_premium_features() | Text::ToLink(), : tr::lng_gift_stars_about(
Text::WithEntities), lt_name,
.aboutFilter = premiumClickHandlerFilter, rpl::single(Text::Bold(peer->shortName())),
.content = MakePremiumGifts(window, peer), lt_link,
}); tr::lng_gift_stars_link() | Text::ToLink(),
AddBlock(content, window, { Text::WithEntities)),
.subtitle = tr::lng_gift_stars_subtitle(),
.about = tr::lng_gift_stars_about(
lt_name,
rpl::single(Text::Bold(peer->shortName())),
lt_link,
tr::lng_gift_stars_link() | Text::ToLink(),
Text::WithEntities),
.aboutFilter = starsClickHandlerFilter, .aboutFilter = starsClickHandlerFilter,
.content = MakeStarsGifts(window, peer), .content = MakeStarsGifts(window, peer),
}); });
} }
struct SelfOption {
object_ptr<Ui::RpWidget> content = { nullptr };
Fn<bool(int, int, int)> overrideKey;
Fn<void()> activate;
};
class Controller final : public ContactsBoxController {
public:
Controller(
not_null<Main::Session*> session,
Fn<void(not_null<PeerData*>)> choose);
void noSearchSubmit();
bool overrideKeyboardNavigation(
int direction,
int fromIndex,
int toIndex) override;
private:
std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user) override;
void prepareViewHook() override;
void rowClicked(not_null<PeerListRow*> row) override;
const Fn<void(not_null<PeerData*>)> _choose;
SelfOption _selfOption;
};
[[nodiscard]] SelfOption MakeSelfOption(
not_null<Main::Session*> session,
Fn<void()> activate) {
class SelfController final : public PeerListController {
public:
SelfController(
not_null<Main::Session*> session,
Fn<void()> activate)
: _session(session)
, _activate(std::move(activate)) {
}
void prepare() override {
auto row = std::make_unique<PeerListRow>(_session->user());
row->setCustomStatus(tr::lng_gift_self_status(tr::now));
delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows();
}
void loadMoreRows() override {
}
void rowClicked(not_null<PeerListRow*> row) override {
_activate();
}
Main::Session &session() const override {
return *_session;
}
private:
const not_null<Main::Session*> _session;
Fn<void()> _activate;
};
auto result = object_ptr<Ui::VerticalLayout>((QWidget*)nullptr);
const auto container = result.data();
Ui::AddSkip(container);
const auto delegate = container->lifetime().make_state<
PeerListContentDelegateSimple
>();
const auto controller = container->lifetime().make_state<
SelfController
>(session, activate);
controller->setStyleOverrides(&st::peerListSingleRow);
const auto content = container->add(object_ptr<PeerListContent>(
container,
controller));
delegate->setContent(content);
controller->setDelegate(delegate);
Ui::AddSkip(container);
container->add(CreatePeerListSectionSubtitle(
container,
tr::lng_contacts_header()));
const auto overrideKey = [=](int direction, int from, int to) {
if (!content->isVisible()) {
return false;
} else if (direction > 0 && from < 0 && to >= 0) {
if (content->hasSelection()) {
const auto was = content->selectedIndex();
const auto now = content->selectSkip(1).reallyMovedTo;
if (was != now) {
return true;
}
content->clearSelection();
} else {
content->selectSkip(1);
return true;
}
} else if (direction < 0 && to < 0) {
if (!content->hasSelection()) {
content->selectLast();
} else if (from >= 0 || content->hasSelection()) {
content->selectSkip(-1);
}
}
return false;
};
return {
.content = std::move(result),
.overrideKey = overrideKey,
.activate = activate,
};
}
Controller::Controller(
not_null<Main::Session*> session,
Fn<void(not_null<PeerData*>)> choose)
: ContactsBoxController(session)
, _choose(std::move(choose))
, _selfOption(MakeSelfOption(session, [=] { _choose(session->user()); })) {
setStyleOverrides(&st::peerListSmallSkips);
}
void Controller::noSearchSubmit() {
if (const auto onstack = _selfOption.activate) {
onstack();
}
}
bool Controller::overrideKeyboardNavigation(
int direction,
int fromIndex,
int toIndex) {
return _selfOption.overrideKey
&& _selfOption.overrideKey(direction, fromIndex, toIndex);
}
std::unique_ptr<PeerListRow> Controller::createRow(
not_null<UserData*> user) {
if (user->isSelf()
|| user->isBot()
|| user->isServiceUser()
|| user->isInaccessible()) {
return nullptr;
}
return ContactsBoxController::createRow(user);
}
void Controller::prepareViewHook() {
delegate()->peerListSetAboveWidget(std::move(_selfOption.content));
}
void Controller::rowClicked(not_null<PeerListRow*> row) {
_choose(row->peer());
}
} // namespace } // namespace
void ChooseStarGiftRecipient( void ChooseStarGiftRecipient(
not_null<Window::SessionController*> controller) { not_null<Window::SessionController*> controller) {
class Controller final : public ContactsBoxController {
public:
Controller(
not_null<Main::Session*> session,
Fn<void(not_null<PeerData*>)> choose)
: ContactsBoxController(session)
, _choose(std::move(choose)) {
}
protected:
std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user) override {
if (user->isSelf()
|| user->isBot()
|| user->isServiceUser()
|| user->isInaccessible()) {
return nullptr;
}
return ContactsBoxController::createRow(user);
}
void rowClicked(not_null<PeerListRow*> row) override {
_choose(row->peer());
}
private:
const Fn<void(not_null<PeerData*>)> _choose;
};
auto initBox = [=](not_null<PeerListBox*> peersBox) { auto initBox = [=](not_null<PeerListBox*> peersBox) {
peersBox->setTitle(tr::lng_gift_premium_or_stars()); peersBox->setTitle(tr::lng_gift_premium_or_stars());
peersBox->addButton(tr::lng_cancel(), [=] { peersBox->closeBox(); }); peersBox->addButton(tr::lng_cancel(), [=] { peersBox->closeBox(); });
@ -2140,11 +2297,16 @@ void UpgradeBox(
const auto checkbox = container->add( const auto checkbox = container->add(
object_ptr<CenterWrap<Checkbox>>( object_ptr<CenterWrap<Checkbox>>(
container, container,
object_ptr<Checkbox>(container, args.canAddComment object_ptr<Checkbox>(
? tr::lng_gift_upgrade_add_comment(tr::now) container,
: args.canAddSender (args.canAddComment
? tr::lng_gift_upgrade_add_sender(tr::now) ? tr::lng_gift_upgrade_add_comment(tr::now)
: tr::lng_gift_upgrade_add_my(tr::now))), : args.canAddSender
? tr::lng_gift_upgrade_add_sender(tr::now)
: args.canAddMyComment
? tr::lng_gift_upgrade_add_my_comment(tr::now)
: tr::lng_gift_upgrade_add_my(tr::now)),
args.addDetailsDefault)),
st::defaultCheckbox.margin)->entity(); st::defaultCheckbox.margin)->entity();
checkbox->checkedChanges() | rpl::start_with_next([=](bool checked) { checkbox->checkedChanges() | rpl::start_with_next([=](bool checked) {
state->preserveDetails = checked; state->preserveDetails = checked;

View file

@ -59,6 +59,8 @@ struct StarGiftUpgradeArgs {
int cost = 0; int cost = 0;
bool canAddSender = false; bool canAddSender = false;
bool canAddComment = false; bool canAddComment = false;
bool canAddMyComment = false;
bool addDetailsDefault = false;
}; };
void ShowStarGiftUpgradeBox(StarGiftUpgradeArgs &&args); void ShowStarGiftUpgradeBox(StarGiftUpgradeArgs &&args);

View file

@ -5431,12 +5431,14 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
tr::lng_action_gift_for_stars(tr::now, lt_count, stars), tr::lng_action_gift_for_stars(tr::now, lt_count, stars),
}; };
const auto anonymous = _from->isServiceUser(); const auto anonymous = _from->isServiceUser();
if (anonymous) { if (anonymous || _history->peer->isSelf()) {
result.text = tr::lng_action_gift_received_anonymous( result.text = (anonymous
tr::now, ? tr::lng_action_gift_received_anonymous
lt_cost, : tr::lng_action_gift_self_bought)(
cost, tr::now,
Ui::Text::WithEntities); lt_cost,
cost,
Ui::Text::WithEntities);
} else { } else {
if (!isSelf) { if (!isSelf) {
result.links.push_back(peer->createOpenLink()); result.links.push_back(peer->createOpenLink());
@ -5463,17 +5465,21 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
const auto isSelf = _from->isSelf(); const auto isSelf = _from->isSelf();
const auto peer = isSelf ? _history->peer : _from; const auto peer = isSelf ? _history->peer : _from;
result.links.push_back(peer->createOpenLink()); result.links.push_back(peer->createOpenLink());
result.text = (action.is_upgrade() result.text = _history->peer->isSelf()
? (isSelf ? tr::lng_action_gift_upgraded_self(
? tr::lng_action_gift_upgraded_mine tr::now,
: tr::lng_action_gift_upgraded) Ui::Text::WithEntities)
: (isSelf : (action.is_upgrade()
? tr::lng_action_gift_transferred_mine ? (isSelf
: tr::lng_action_gift_transferred))( ? tr::lng_action_gift_upgraded_mine
tr::now, : tr::lng_action_gift_upgraded)
lt_user, : (isSelf
Ui::Text::Link(peer->shortName(), 1), // Link 1. ? tr::lng_action_gift_transferred_mine
Ui::Text::WithEntities); : tr::lng_action_gift_transferred))(
tr::now,
lt_user,
Ui::Text::Link(peer->shortName(), 1), // Link 1.
Ui::Text::WithEntities);
return result; return result;
}; };

View file

@ -57,12 +57,15 @@ QSize PremiumGift::size() {
QString PremiumGift::title() { QString PremiumGift::title() {
if (starGift()) { if (starGift()) {
return (outgoingGift() const auto peer = _parent->history()->peer;
? tr::lng_action_gift_sent_subtitle return peer->isSelf()
: tr::lng_action_gift_got_subtitle)( ? tr::lng_action_gift_self_subtitle(tr::now)
tr::now, : (outgoingGift()
lt_user, ? tr::lng_action_gift_sent_subtitle
_parent->history()->peer->shortName()); : tr::lng_action_gift_got_subtitle)(
tr::now,
lt_user,
peer->shortName());
} else if (creditsPrize()) { } else if (creditsPrize()) {
return tr::lng_prize_title(tr::now); return tr::lng_prize_title(tr::now);
} else if (const auto count = credits()) { } else if (const auto count = credits()) {
@ -99,8 +102,16 @@ TextWithEntities PremiumGift::subtitle() {
? tr::lng_action_gift_got_upgradable_text( ? tr::lng_action_gift_got_upgradable_text(
tr::now, tr::now,
Ui::Text::RichLangValue) Ui::Text::RichLangValue)
: (_data.starsToUpgrade
&& !_data.converted
&& _parent->history()->peer->isSelf())
? tr::lng_action_gift_self_about_unique(
tr::now,
Ui::Text::RichLangValue)
: ((_data.converted || !_data.starsConverted) : ((_data.converted || !_data.starsConverted)
? tr::lng_gift_got_stars ? tr::lng_gift_got_stars
: _parent->history()->peer->isSelf()
? tr::lng_action_gift_self_about
: tr::lng_action_gift_got_stars_text)( : tr::lng_action_gift_got_stars_text)(
tr::now, tr::now,
lt_count, lt_count,

View file

@ -420,13 +420,16 @@ auto GenerateUniqueGiftMedia(
replacing, replacing,
sticker, sticker,
st::chatUniqueStickerPadding)); st::chatUniqueStickerPadding));
const auto peer = parent->history()->peer;
pushText( pushText(
Ui::Text::Bold((outgoing Ui::Text::Bold(peer->isSelf()
? tr::lng_action_gift_sent_subtitle ? tr::lng_action_gift_self_subtitle(tr::now)
: tr::lng_action_gift_got_subtitle)( : (outgoing
tr::now, ? tr::lng_action_gift_sent_subtitle
lt_user, : tr::lng_action_gift_got_subtitle)(
parent->history()->peer->shortName())), tr::now,
lt_user,
peer->shortName())),
st::chatUniqueTitle, st::chatUniqueTitle,
white, white,
st::chatUniqueTitlePadding); st::chatUniqueTitlePadding);
@ -436,7 +439,7 @@ auto GenerateUniqueGiftMedia(
gift->backdrop.textColor, gift->backdrop.textColor,
st::chatUniqueTextPadding); st::chatUniqueTextPadding);
const auto withButton = !outgoing; const auto withButton = !outgoing || item->history()->peer->isSelf();
auto attributes = std::vector<AttributeTable::Entry>{ auto attributes = std::vector<AttributeTable::Entry>{
{ tr::lng_gift_unique_model(tr::now), gift->model.name }, { tr::lng_gift_unique_model(tr::now), gift->model.name },

View file

@ -1005,6 +1005,12 @@ void ReceiptCreditsBox(
}, widget->lifetime()); }, widget->lifetime());
} }
const auto selfPeerId = session->userPeerId().value;
const auto chatPeerId = e.fromGiftsList
? e.bareGiftOwnerId
: e.barePeerId;
const auto giftToSelf = isStarGift && (selfPeerId == chatPeerId);
if (!uniqueGift) { if (!uniqueGift) {
Ui::AddSkip(content); Ui::AddSkip(content);
Ui::AddSkip(content); Ui::AddSkip(content);
@ -1036,6 +1042,8 @@ void ReceiptCreditsBox(
? tr::lng_credits_box_history_entry_gift_converted(tr::now) ? tr::lng_credits_box_history_entry_gift_converted(tr::now)
: (isStarGift && !gotStarGift) : (isStarGift && !gotStarGift)
? tr::lng_gift_link_label_gift(tr::now) ? tr::lng_gift_link_label_gift(tr::now)
: giftToSelf
? tr::lng_action_gift_self_subtitle(tr::now)
: e.gift : e.gift
? tr::lng_credits_box_history_entry_gift_name(tr::now) ? tr::lng_credits_box_history_entry_gift_name(tr::now)
: (peer && !e.reaction) : (peer && !e.reaction)
@ -1188,6 +1196,11 @@ void ReceiptCreditsBox(
: e.starsUpgradedBySender : e.starsUpgradedBySender
? tr::lng_action_gift_got_upgradable_text( ? tr::lng_action_gift_got_upgradable_text(
Ui::Text::RichLangValue) Ui::Text::RichLangValue)
: (e.starsToUpgrade
&& giftToSelf
&& !(couldConvert || nonConvertible))
? tr::lng_action_gift_self_about_unique(
Ui::Text::WithEntities)
: ((couldConvert || nonConvertible) : ((couldConvert || nonConvertible)
? (e.savedToProfile ? (e.savedToProfile
? tr::lng_action_gift_can_remove_text ? tr::lng_action_gift_can_remove_text
@ -1195,7 +1208,9 @@ void ReceiptCreditsBox(
Ui::Text::WithEntities) Ui::Text::WithEntities)
: rpl::combine( : rpl::combine(
(canConvert (canConvert
? tr::lng_action_gift_got_stars_text ? (giftToSelf
? tr::lng_action_gift_self_about
: tr::lng_action_gift_got_stars_text)
: tr::lng_gift_got_stars)( : tr::lng_gift_got_stars)(
lt_count, lt_count,
rpl::single(e.starsConverted * 1.), rpl::single(e.starsConverted * 1.),
@ -1322,8 +1337,13 @@ void ReceiptCreditsBox(
.user = starGiftSender, .user = starGiftSender,
.itemId = itemId, .itemId = itemId,
.cost = e.starsUpgradedBySender ? 0 : e.starsToUpgrade, .cost = e.starsUpgradedBySender ? 0 : e.starsToUpgrade,
.canAddSender = !e.anonymous, .canAddSender = !giftToSelf && !e.anonymous,
.canAddComment = !e.anonymous && e.hasGiftComment, .canAddComment = (!giftToSelf
&& !e.anonymous
&& e.hasGiftComment),
.canAddMyComment = (giftToSelf && e.hasGiftComment),
.addDetailsDefault = (giftToSelf
|| (e.starsUpgradedBySender && !e.anonymous)),
}); });
} }
}; };