Process gift updates in list.

This commit is contained in:
John Preston 2024-09-24 23:00:22 +04:00
parent 779e9b658b
commit 962d4d29ee
12 changed files with 177 additions and 34 deletions

View file

@ -3014,6 +3014,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gift_limited_of_one" = "unique";
"lng_gift_limited_of_count" = "1 of {amount}";
"lng_gift_anonymous_hint" = "Only you 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 to visitors of your page.";
"lng_gift_availability" = "Availability";
"lng_gift_from_hidden" = "Hidden User";
"lng_gift_availability_left#one" = "{count} of {amount} left";

View file

@ -251,7 +251,7 @@ void StickerPremiumMark::paint(
: (singleSize.height() - (bg.height() / factor) - radius);
const auto point = position + QPoint(shiftx, shifty);
p.drawImage(point, bg);
if (_premium) {
if (_premium && _part != RectPart::Center) {
validateStar();
p.drawImage(point, _star);
} else {

View file

@ -69,6 +69,7 @@ struct CreditsHistoryEntry final {
bool converted = false;
bool anonymous = false;
bool savedToProfile = false;
bool fromGiftsList = false;
bool reaction = false;
bool refunded = false;
bool pending = false;

View file

@ -579,6 +579,10 @@ const Invoice *Media::invoice() const {
return nullptr;
}
const GiftCode *Media::gift() const {
return nullptr;
}
CloudImage *Media::location() const {
return nullptr;
}
@ -2331,8 +2335,8 @@ not_null<PeerData*> MediaGiftBox::from() const {
return _from;
}
const GiftCode &MediaGiftBox::data() const {
return _data;
const GiftCode *MediaGiftBox::gift() const {
return &_data;
}
TextWithEntities MediaGiftBox::notificationText() const {

View file

@ -172,6 +172,7 @@ public:
virtual const Call *call() const;
virtual GameData *game() const;
virtual const Invoice *invoice() const;
virtual const GiftCode *gift() const;
virtual CloudImage *location() const;
virtual PollData *poll() const;
virtual const WallPaper *paper() const;
@ -621,7 +622,7 @@ public:
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
[[nodiscard]] not_null<PeerData*> from() const;
[[nodiscard]] const GiftCode &data() const;
[[nodiscard]] const GiftCode *gift() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;

View file

@ -1645,6 +1645,14 @@ rpl::producer<not_null<HistoryItem*>> Session::newItemAdded() const {
return _newItemAdded.events();
}
void Session::notifyGiftUpdate(GiftUpdate &&update) {
_giftUpdates.fire(std::move(update));
}
rpl::producer<GiftUpdate> Session::giftUpdates() const {
return _giftUpdates.events();
}
HistoryItem *Session::changeMessageId(PeerId peerId, MsgId wasId, MsgId nowId) {
const auto list = messagesListForInsert(peerId);
const auto i = list->find(wasId);

View file

@ -77,6 +77,18 @@ struct RepliesReadTillUpdate {
bool out = false;
};
struct GiftUpdate {
enum class Action : uchar {
Save,
Unsave,
Convert,
Delete,
};
FullMsgId itemId;
Action action = {};
};
class Session final {
public:
using ViewElement = HistoryView::Element;
@ -281,6 +293,8 @@ public:
[[nodiscard]] rpl::producer<not_null<const ViewElement*>> viewLayoutChanged() const;
void notifyNewItemAdded(not_null<HistoryItem*> item);
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> newItemAdded() const;
void notifyGiftUpdate(GiftUpdate &&update);
[[nodiscard]] rpl::producer<GiftUpdate> giftUpdates() const;
void requestItemRepaint(not_null<const HistoryItem*> item);
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRepaintRequest() const;
void requestViewRepaint(not_null<const ViewElement*> view);
@ -924,6 +938,7 @@ private:
rpl::event_stream<not_null<const HistoryItem*>> _itemLayoutChanges;
rpl::event_stream<not_null<const ViewElement*>> _viewLayoutChanges;
rpl::event_stream<not_null<HistoryItem*>> _newItemAdded;
rpl::event_stream<GiftUpdate> _giftUpdates;
rpl::event_stream<not_null<const HistoryItem*>> _itemRepaintRequest;
rpl::event_stream<not_null<const ViewElement*>> _viewRepaintRequest;
rpl::event_stream<not_null<const HistoryItem*>> _itemResizeRequest;

View file

@ -175,6 +175,15 @@ void History::itemVanished(not_null<HistoryItem*> item) {
&& unreadCount() > 0) {
setUnreadCount(unreadCount() - 1);
}
if (const auto media = item->media()) {
if (const auto gift = media->gift()) {
using GiftAction = Data::GiftUpdate::Action;
owner().notifyGiftUpdate({
.itemId = item->fullId(),
.action = GiftAction::Delete,
});
}
}
}
void History::takeLocalDraft(not_null<History*> from) {

View file

@ -2374,6 +2374,7 @@ bool Message::hasFromPhoto() const {
} else if (item->isPost()) {
return true;
} else if (item->isEmpty()
|| item->isFakeAboutView()
|| (context() == Context::Replies && item->isDiscussionPost())) {
return false;
} else if (delegate()->elementIsChatWide()) {

View file

@ -37,7 +37,7 @@ PremiumGift::PremiumGift(
not_null<Data::MediaGiftBox*> gift)
: _parent(parent)
, _gift(gift)
, _data(gift->data()) {
, _data(*gift->gift()) {
}
PremiumGift::~PremiumGift() = default;
@ -155,7 +155,7 @@ ClickHandlerPtr PremiumGift::createViewLink() {
const auto itemId = _parent->data()->fullId();
const auto peer = _parent->history()->peer;
const auto date = _parent->data()->date();
const auto data = _gift->data();
const auto data = *_gift->gift();
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {

View file

@ -76,7 +76,9 @@ private:
int visibleBottom) override;
void paintEvent(QPaintEvent *e) override;
void subscribeToUpdates();
void loadMore();
void refreshButtons();
void validateButtons();
void showGift(int index);
@ -119,6 +121,52 @@ InnerWidget::InnerWidget(
, _totalCount(_user->peerGiftsCount())
, _api(&_user->session().mtp()) {
_singleMin = _delegate.buttonSize();
if (user->isSelf()) {
subscribeToUpdates();
}
}
void InnerWidget::subscribeToUpdates() {
_user->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 i = ranges::find(_entries, update.itemId, itemId);
if (i == end(_entries)) {
return;
}
const auto index = int(i - begin(_entries));
using Action = Data::GiftUpdate::Action;
if (update.action == Action::Convert
|| update.action == Action::Delete) {
_entries.erase(i);
if (_totalCount > 0) {
--_totalCount;
}
for (auto &view : _views) {
if (view.entry >= index) {
--view.entry;
}
}
} else if (update.action == Action::Save
|| update.action == Action::Unsave) {
i->gift.hidden = (update.action == Action::Unsave);
v::match(i->descriptor, [](GiftTypePremium &) {
}, [&](GiftTypeStars &data) {
data.hidden = i->gift.hidden;
});
for (auto &view : _views) {
if (view.entry == index) {
view.entry = -1;
}
}
} else {
return;
}
refreshButtons();
}, lifetime());
}
void InnerWidget::visibleTopBottomUpdated(
@ -170,17 +218,21 @@ void InnerWidget::loadMore() {
});
}
}
_viewsForWidth = 0;
_viewsFromRow = 0;
_viewsTillRow = 0;
resizeToWidth(width());
validateButtons();
refreshButtons();
}).fail([=] {
_loadMoreRequestId = 0;
_allLoaded = true;
}).send();
}
void InnerWidget::refreshButtons() {
_viewsForWidth = 0;
_viewsFromRow = 0;
_viewsTillRow = 0;
resizeToWidth(width());
validateButtons();
}
void InnerWidget::validateButtons() {
if (!_perRow) {
return;

View file

@ -38,6 +38,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/channel_statistics/boosts/giveaway/boost_badge.h" // InfiniteRadialAnimationWidget.
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
#include "info/statistics/info_statistics_list_controllers.h"
#include "info/info_controller.h"
#include "info/info_memento.h"
#include "iv/iv_instance.h"
#include "lang/lang_keys.h"
#include "lottie/lottie_single_player.h"
@ -158,21 +160,19 @@ private:
void ToggleStarGiftSaved(
not_null<Window::SessionController*> window,
not_null<HistoryItem*> item,
not_null<UserData*> sender,
MsgId itemId,
bool save,
Fn<void(bool)> done) {
Expects(item->history()->peer->isUser());
using Flag = MTPpayments_SaveStarGift::Flag;
const auto api = &window->session().api();
const auto weak = base::make_weak(window);
api->request(MTPpayments_SaveStarGift(
MTP_flags(save ? Flag(0) : Flag::f_unsave),
item->history()->peer->asUser()->inputUser,
MTP_int(item->id.bare)
sender->inputUser,
MTP_int(itemId.bare)
)).done([=] {
if (const auto strong = weak.get()) {
strong->showPeerInfo(strong->session().user());
strong->showToast((save
? tr::lng_gift_display_done
: tr::lng_gift_display_done_hide)(tr::now));
@ -206,16 +206,15 @@ void ConfirmConvertStarGift(
void ConvertStarGift(
not_null<Window::SessionController*> window,
not_null<HistoryItem*> item,
not_null<UserData*> sender,
MsgId itemId,
int stars,
Fn<void(bool)> done) {
Expects(item->history()->peer->isUser());
const auto api = &window->session().api();
const auto weak = base::make_weak(window);
api->request(MTPpayments_ConvertStarGift(
item->history()->peer->asUser()->inputUser,
MTP_int(item->id.bare)
sender->inputUser,
MTP_int(itemId)
)).done([=] {
if (const auto strong = weak.get()) {
strong->showSettings(Settings::CreditsId());
@ -734,6 +733,8 @@ void ReceiptCreditsBox(
const auto myStarGift = isStarGift && e.in;
const auto starGiftSender = (isStarGift && item)
? item->history()->peer->asUser()
: (isStarGift && e.in)
? controller->session().data().peer(PeerId(e.barePeerId))->asUser()
: nullptr;
const auto canConvert = myStarGift
&& !e.converted
@ -1081,6 +1082,15 @@ void ReceiptCreditsBox(
tr::lng_credits_box_out_about_link(tr::now)),
Ui::Text::WithEntities),
st::creditsBoxAboutDivider)));
} else if (myStarGift && e.fromGiftsList) {
box->addRow(object_ptr<Ui::CenterWrap<>>(
box,
object_ptr<Ui::FlatLabel>(
box,
(e.savedToProfile
? tr::lng_gift_visible_hint()
: tr::lng_gift_hidden_hint()),
st::creditsBoxAboutDivider)));
} else if (myStarGift && e.anonymous) {
box->addRow(object_ptr<Ui::CenterWrap<>>(
box,
@ -1157,11 +1167,29 @@ void ReceiptCreditsBox(
if (canConvert) {
const auto save = !e.savedToProfile;
const auto window = weakWindow.get();
const auto item = session->data().message(
starGiftSender->id,
MsgId(e.bareMsgId));
if (window && item) {
ToggleStarGiftSaved(window, item, save, [=](bool ok) {
const auto showSection = !e.fromGiftsList;
const auto itemId = MsgId(e.bareMsgId);
if (window) {
const auto done = [=](bool ok) {
if (const auto window = weakWindow.get()) {
if (ok) {
using GiftAction = Data::GiftUpdate::Action;
window->session().data().notifyGiftUpdate({
.itemId = FullMsgId(
starGiftSender->id,
itemId),
.action = (save
? GiftAction::Save
: GiftAction::Unsave),
});
if (showSection) {
window->showSection(
std::make_shared<Info::Memento>(
window->session().user(),
Info::Section::Type::PeerGifts));
}
}
}
if (const auto strong = weak.data()) {
if (ok) {
strong->closeBox();
@ -1169,7 +1197,13 @@ void ReceiptCreditsBox(
state->confirmButtonBusy = false;
}
}
});
};
ToggleStarGiftSaved(
window,
starGiftSender,
itemId,
save,
done);
}
} else if (toRenew && s.expired) {
Api::CheckChatInvite(controller, s.inviteHash, nullptr, [=] {
@ -1265,11 +1299,20 @@ void ReceiptCreditsBox(
}
state->convertButtonBusy = true;
const auto window = weakWindow.get();
const auto item = session->data().message(
starGiftSender->id,
MsgId(e.bareMsgId));
if (window && item && stars) {
ConvertStarGift(window, item, stars, [=](bool ok) {
const auto itemId = MsgId(e.bareMsgId);
if (window && stars) {
const auto done = [=](bool ok) {
if (const auto window = weakWindow.get()) {
if (ok) {
using GiftAction = Data::GiftUpdate::Action;
window->session().data().notifyGiftUpdate({
.itemId = FullMsgId(
starGiftSender->id,
itemId),
.action = GiftAction::Convert,
});
}
}
if (const auto strong = weak.data()) {
if (ok) {
strong->closeBox();
@ -1277,7 +1320,13 @@ void ReceiptCreditsBox(
state->convertButtonBusy = false;
}
}
});
};
ConvertStarGift(
window,
starGiftSender,
itemId,
stars,
done);
}
});
});
@ -1366,6 +1415,7 @@ void UserStarGiftBox(
.converted = false,
.anonymous = data.anonymous,
.savedToProfile = !data.hidden,
.fromGiftsList = true,
.in = data.mine,
.gift = true,
},