mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Load more saved gifts for crafting.
This commit is contained in:
@@ -4119,6 +4119,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_gift_collection_reorder_exit" = "Apply Reorder";
|
||||
"lng_gift_collection_remove_from" = "Remove from Collection";
|
||||
"lng_gift_locked_title" = "Gift Locked";
|
||||
"lng_gift_craft_menu_button" = "Craft";
|
||||
"lng_gift_craft_info_title" = "Gift Crafting";
|
||||
"lng_gift_craft_info_about" = "Turn your gifts into rare, epic\nand legendary versions.";
|
||||
"lng_gift_craft_rare_title" = "Get Rare Models";
|
||||
|
||||
@@ -1304,7 +1304,7 @@ void AuctionInfoBox(
|
||||
|
||||
struct State {
|
||||
explicit State(not_null<Main::Session*> session)
|
||||
: delegate(session, GiftButtonMode::Minimal) {
|
||||
: delegate(session, GiftButtonMode::Minimal) {
|
||||
}
|
||||
|
||||
Delegate delegate;
|
||||
|
||||
@@ -1594,315 +1594,6 @@ void CheckMaybeGiftLocked(
|
||||
})).send();
|
||||
}
|
||||
|
||||
[[nodiscard]] object_ptr<RpWidget> MakeGiftsList(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer,
|
||||
rpl::producer<GiftsDescriptor> gifts,
|
||||
Fn<void()> loadMore,
|
||||
Fn<void(GiftDescriptor)> handler = nullptr) {
|
||||
auto result = object_ptr<VisibleRangeWidget>((QWidget*)nullptr);
|
||||
const auto raw = result.data();
|
||||
|
||||
Data::AmPremiumValue(&window->session()) | rpl::on_next([=] {
|
||||
raw->update();
|
||||
}, raw->lifetime());
|
||||
|
||||
struct State {
|
||||
Delegate delegate;
|
||||
std::vector<int> order;
|
||||
std::vector<bool> validated;
|
||||
std::vector<GiftDescriptor> list;
|
||||
std::vector<std::unique_ptr<GiftButton>> buttons;
|
||||
std::shared_ptr<Api::PremiumGiftCodeOptions> api;
|
||||
std::shared_ptr<Data::UniqueGift> transferRequested;
|
||||
rpl::variable<VisibleRange> visibleRange;
|
||||
uint64 resaleRequestingId = 0;
|
||||
rpl::lifetime resaleLifetime;
|
||||
bool sending = false;
|
||||
int perRow = 1;
|
||||
};
|
||||
const auto state = raw->lifetime().make_state<State>(State{
|
||||
.delegate = Delegate(&window->session(), GiftButtonMode::Full),
|
||||
});
|
||||
const auto single = state->delegate.buttonSize();
|
||||
const auto shadow = st::defaultDropdownMenu.wrap.shadow;
|
||||
const auto extend = shadow.extend;
|
||||
|
||||
auto &packs = window->session().giftBoxStickersPacks();
|
||||
packs.updated() | rpl::on_next([=] {
|
||||
for (const auto &button : state->buttons) {
|
||||
if (const auto raw = button.get()) {
|
||||
raw->update();
|
||||
}
|
||||
}
|
||||
}, raw->lifetime());
|
||||
|
||||
const auto rebuild = [=] {
|
||||
const auto width = st::boxWideWidth;
|
||||
const auto padding = st::giftBoxPadding;
|
||||
const auto available = width - padding.left() - padding.right();
|
||||
const auto range = state->visibleRange.current();
|
||||
const auto count = int(state->list.size());
|
||||
|
||||
auto &buttons = state->buttons;
|
||||
if (buttons.size() < count) {
|
||||
buttons.resize(count);
|
||||
}
|
||||
auto &validated = state->validated;
|
||||
validated.resize(count);
|
||||
|
||||
auto x = padding.left();
|
||||
auto y = padding.top();
|
||||
const auto perRow = state->perRow;
|
||||
const auto singlew = single.width() + st::giftBoxGiftSkip.x();
|
||||
const auto singleh = single.height() + st::giftBoxGiftSkip.y();
|
||||
const auto rowFrom = std::max(range.top - y, 0) / singleh;
|
||||
const auto rowTill = (std::max(range.bottom - y + st::giftBoxGiftSkip.y(), 0) + singleh - 1)
|
||||
/ singleh;
|
||||
Assert(rowTill >= rowFrom);
|
||||
const auto first = rowFrom * perRow;
|
||||
const auto last = std::min(rowTill * perRow, count);
|
||||
auto checkedFrom = 0;
|
||||
auto checkedTill = int(buttons.size());
|
||||
const auto ensureButton = [&](int index) {
|
||||
auto &button = buttons[index];
|
||||
if (!button) {
|
||||
validated[index] = false;
|
||||
for (; checkedFrom != first; ++checkedFrom) {
|
||||
if (buttons[checkedFrom]) {
|
||||
button = std::move(buttons[checkedFrom]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!button) {
|
||||
for (; checkedTill != last; ) {
|
||||
--checkedTill;
|
||||
if (buttons[checkedTill]) {
|
||||
button = std::move(buttons[checkedTill]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!button) {
|
||||
button = std::make_unique<GiftButton>(raw, &state->delegate);
|
||||
}
|
||||
const auto raw = button.get();
|
||||
if (validated[index]) {
|
||||
return;
|
||||
}
|
||||
raw->show();
|
||||
validated[index] = true;
|
||||
const auto &descriptor = state->list[state->order[index]];
|
||||
raw->setDescriptor(descriptor, GiftButton::Mode::Full);
|
||||
raw->setClickedCallback([=] {
|
||||
if (handler) {
|
||||
handler(descriptor);
|
||||
return;
|
||||
}
|
||||
const auto star = std::get_if<GiftTypeStars>(&descriptor);
|
||||
const auto send = crl::guard(raw, [=] {
|
||||
window->show(Box(
|
||||
SendGiftBox,
|
||||
window,
|
||||
peer,
|
||||
state->api,
|
||||
descriptor,
|
||||
nullptr));
|
||||
});
|
||||
const auto unique = star ? star->info.unique : nullptr;
|
||||
const auto premiumNeeded = star && star->info.requirePremium;
|
||||
if (unique && star->resale) {
|
||||
window->show(Box(
|
||||
Settings::GlobalStarGiftBox,
|
||||
window->uiShow(),
|
||||
star->info,
|
||||
Settings::StarGiftResaleInfo{
|
||||
.recipientId = peer->id,
|
||||
.forceTon = star->forceTon,
|
||||
},
|
||||
Settings::CreditsEntryBoxStyleOverrides()));
|
||||
} else if (unique && star->mine && !peer->isSelf()) {
|
||||
if (ShowTransferGiftLater(window->uiShow(), unique)) {
|
||||
return;
|
||||
}
|
||||
const auto done = [=] {
|
||||
window->session().credits().load(true);
|
||||
window->showPeerHistory(peer);
|
||||
};
|
||||
if (state->transferRequested == unique) {
|
||||
return;
|
||||
}
|
||||
state->transferRequested = unique;
|
||||
const auto savedId = star->transferId;
|
||||
using Payments::CheckoutResult;
|
||||
const auto formReady = [=](
|
||||
uint64 formId,
|
||||
CreditsAmount price,
|
||||
std::optional<CheckoutResult> failure) {
|
||||
state->transferRequested = nullptr;
|
||||
if (!failure && !price.stars()) {
|
||||
LOG(("API Error: "
|
||||
"Bad transfer invoice currenct."));
|
||||
} else if (!failure
|
||||
|| *failure == CheckoutResult::Free) {
|
||||
unique->starsForTransfer = failure
|
||||
? 0
|
||||
: price.whole();
|
||||
ShowTransferToBox(
|
||||
window,
|
||||
peer,
|
||||
unique,
|
||||
savedId,
|
||||
done);
|
||||
} else if (*failure == CheckoutResult::Cancelled) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
RequestOurForm(
|
||||
window->uiShow(),
|
||||
MTP_inputInvoiceStarGiftTransfer(
|
||||
Api::InputSavedStarGiftId(savedId, unique),
|
||||
peer->input()),
|
||||
formReady);
|
||||
} else if (star && star->resale) {
|
||||
const auto id = star->info.id;
|
||||
if (state->resaleRequestingId == id) {
|
||||
return;
|
||||
}
|
||||
state->resaleRequestingId = id;
|
||||
state->resaleLifetime = ShowStarGiftResale(
|
||||
window,
|
||||
peer,
|
||||
id,
|
||||
star->info.resellTitle,
|
||||
[=] { state->resaleRequestingId = 0; });
|
||||
} else if (star && star->info.auction()) {
|
||||
if (!IsSoldOut(star->info)
|
||||
&& premiumNeeded
|
||||
&& !peer->session().premium()) {
|
||||
Settings::ShowPremiumGiftPremium(window, star->info);
|
||||
} else {
|
||||
const auto id = star->info.id;
|
||||
if (state->resaleRequestingId == id) {
|
||||
return;
|
||||
}
|
||||
state->resaleRequestingId = id;
|
||||
state->resaleLifetime = ShowStarGiftAuction(
|
||||
window,
|
||||
peer,
|
||||
id,
|
||||
[=] { state->resaleRequestingId = 0; },
|
||||
crl::guard(raw, [=] {
|
||||
state->resaleLifetime.destroy();
|
||||
}));
|
||||
}
|
||||
} else if (star && IsSoldOut(star->info)) {
|
||||
window->show(Box(SoldOutBox, window, *star));
|
||||
} else if (premiumNeeded && !peer->session().premium()) {
|
||||
Settings::ShowPremiumGiftPremium(window, star->info);
|
||||
} else if (star
|
||||
&& star->info.lockedUntilDate
|
||||
&& star->info.lockedUntilDate > base::unixtime::now()) {
|
||||
const auto ready = crl::guard(raw, [=] {
|
||||
if (premiumNeeded && !peer->session().premium()) {
|
||||
Settings::ShowPremiumGiftPremium(
|
||||
window,
|
||||
v::get<GiftTypeStars>(descriptor).info);
|
||||
} else {
|
||||
send();
|
||||
}
|
||||
});
|
||||
CheckMaybeGiftLocked(window, star->info.id, ready);
|
||||
} else if (star
|
||||
&& star->info.perUserTotal
|
||||
&& !star->info.perUserRemains) {
|
||||
window->showToast({
|
||||
.text = tr::lng_gift_sent_finished(
|
||||
tr::now,
|
||||
lt_count,
|
||||
star->info.perUserTotal,
|
||||
tr::rich),
|
||||
});
|
||||
} else {
|
||||
send();
|
||||
}
|
||||
});
|
||||
raw->setGeometry(QRect(QPoint(x, y), single), extend);
|
||||
};
|
||||
y += rowFrom * singleh;
|
||||
for (auto row = rowFrom; row != rowTill; ++row) {
|
||||
for (auto col = 0; col != perRow; ++col) {
|
||||
const auto index = row * perRow + col;
|
||||
if (index >= count) {
|
||||
break;
|
||||
}
|
||||
const auto last = !((col + 1) % perRow);
|
||||
if (last) {
|
||||
x = padding.left() + available - single.width();
|
||||
}
|
||||
ensureButton(index);
|
||||
if (last) {
|
||||
x = padding.left();
|
||||
y += singleh;
|
||||
} else {
|
||||
x += singlew;
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto till = std::min(int(buttons.size()), rowTill * perRow);
|
||||
for (auto i = count; i < till; ++i) {
|
||||
if (const auto button = buttons[i].get()) {
|
||||
button->hide();
|
||||
}
|
||||
}
|
||||
|
||||
const auto page = range.bottom - range.top;
|
||||
if (loadMore && page > 0 && range.bottom + page > raw->height()) {
|
||||
loadMore();
|
||||
}
|
||||
};
|
||||
|
||||
state->visibleRange = raw->visibleRange();
|
||||
state->visibleRange.value(
|
||||
) | rpl::on_next(rebuild, raw->lifetime());
|
||||
|
||||
std::move(
|
||||
gifts
|
||||
) | rpl::on_next([=](const GiftsDescriptor &gifts) {
|
||||
const auto width = st::boxWideWidth;
|
||||
const auto padding = st::giftBoxPadding;
|
||||
const auto available = width - padding.left() - padding.right();
|
||||
state->perRow = available / single.width();
|
||||
state->list = std::move(gifts.list);
|
||||
state->api = gifts.api;
|
||||
|
||||
const auto count = int(state->list.size());
|
||||
state->order = ranges::views::ints
|
||||
| ranges::views::take(count)
|
||||
| ranges::to_vector;
|
||||
state->validated.clear();
|
||||
|
||||
if (SortForBirthday(peer)) {
|
||||
ranges::stable_partition(state->order, [&](int i) {
|
||||
const auto &gift = state->list[i];
|
||||
const auto stars = std::get_if<GiftTypeStars>(&gift);
|
||||
return stars && stars->info.birthday && !stars->info.unique;
|
||||
});
|
||||
}
|
||||
|
||||
const auto rows = (count + state->perRow - 1) / state->perRow;
|
||||
const auto height = padding.top()
|
||||
+ (rows * single.height())
|
||||
+ ((rows - 1) * st::giftBoxGiftSkip.y())
|
||||
+ padding.bottom();
|
||||
raw->resize(raw->width(), height);
|
||||
rebuild();
|
||||
}, raw->lifetime());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FillBg(not_null<RpWidget*> box) {
|
||||
box->paintRequest() | rpl::on_next([=] {
|
||||
auto p = QPainter(box);
|
||||
@@ -1957,13 +1648,18 @@ void AddBlock(
|
||||
|
||||
state->gifts = GiftsPremium(&window->session(), peer);
|
||||
|
||||
auto result = MakeGiftsList(window, peer, state->gifts.value(
|
||||
auto gifts = state->gifts.value(
|
||||
) | rpl::map([=](const PremiumGiftsDescriptor &gifts) {
|
||||
return GiftsDescriptor{
|
||||
gifts.list | ranges::to<std::vector<GiftDescriptor>>,
|
||||
gifts.api,
|
||||
};
|
||||
}), nullptr);
|
||||
});
|
||||
auto result = MakeGiftsList({
|
||||
.window = window,
|
||||
.peer = peer,
|
||||
.gifts = std::move(gifts),
|
||||
});
|
||||
result->lifetime().add([state = std::move(state)] {});
|
||||
return result;
|
||||
}
|
||||
@@ -1996,7 +1692,8 @@ void AddBlock(
|
||||
tabSelected(tab);
|
||||
}, tabs.widget->lifetime());
|
||||
result->add(std::move(tabs.widget));
|
||||
result->add(MakeGiftsList(window, peer, rpl::combine(
|
||||
|
||||
auto gifts = rpl::combine(
|
||||
state->gifts.value(),
|
||||
state->priceTab.value(),
|
||||
rpl::single(rpl::empty) | rpl::then(state->myUpdated.events())
|
||||
@@ -2042,7 +1739,8 @@ void AddBlock(
|
||||
return GiftsDescriptor{
|
||||
gifts | ranges::to<std::vector<GiftDescriptor>>(),
|
||||
};
|
||||
}), [=] {
|
||||
});
|
||||
const auto loadMore = [=] {
|
||||
if (state->priceTab.current() == kPriceTabMy
|
||||
&& !state->my.offset.isEmpty()
|
||||
&& !state->myLoading) {
|
||||
@@ -2062,6 +1760,12 @@ void AddBlock(
|
||||
state->myUpdated.fire({});
|
||||
});
|
||||
}
|
||||
};
|
||||
result->add(MakeGiftsList({
|
||||
.window = window,
|
||||
.peer = peer,
|
||||
.gifts = std::move(gifts),
|
||||
.loadMore = loadMore,
|
||||
}));
|
||||
|
||||
return result;
|
||||
@@ -4653,18 +4357,354 @@ CreditsAmount TonFromStars(
|
||||
CreditsType::Ton);
|
||||
}
|
||||
|
||||
object_ptr<RpWidget> MakeGiftsSendList(
|
||||
struct DefaultGiftHandlerState {
|
||||
not_null<Window::SessionController*> window;
|
||||
not_null<PeerData*> peer;
|
||||
std::shared_ptr<Api::PremiumGiftCodeOptions> api;
|
||||
std::shared_ptr<Data::UniqueGift> transferRequested;
|
||||
uint64 resaleRequestingId = 0;
|
||||
rpl::lifetime resaleLifetime;
|
||||
|
||||
base::has_weak_ptr guard;
|
||||
};
|
||||
|
||||
void DefaultGiftHandler(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer,
|
||||
rpl::producer<GiftsDescriptor> gifts,
|
||||
Fn<void()> loadMore,
|
||||
Fn<void(GiftDescriptor)> handler) {
|
||||
return MakeGiftsList(
|
||||
window,
|
||||
peer,
|
||||
std::move(gifts),
|
||||
std::move(loadMore),
|
||||
std::move(handler));
|
||||
not_null<DefaultGiftHandlerState*> state,
|
||||
Info::PeerGifts::GiftDescriptor descriptor) {
|
||||
const auto star = std::get_if<GiftTypeStars>(&descriptor);
|
||||
const auto send = crl::guard(&state->guard, [=] {
|
||||
window->show(Box(
|
||||
SendGiftBox,
|
||||
window,
|
||||
state->peer,
|
||||
state->api,
|
||||
descriptor,
|
||||
nullptr));
|
||||
});
|
||||
const auto peer = state->peer;
|
||||
const auto unique = star ? star->info.unique : nullptr;
|
||||
const auto premiumNeeded = star && star->info.requirePremium;
|
||||
if (unique && star->resale) {
|
||||
window->show(Box(
|
||||
Settings::GlobalStarGiftBox,
|
||||
window->uiShow(),
|
||||
star->info,
|
||||
Settings::StarGiftResaleInfo{
|
||||
.recipientId = peer->id,
|
||||
.forceTon = star->forceTon,
|
||||
},
|
||||
Settings::CreditsEntryBoxStyleOverrides()));
|
||||
} else if (unique && star->mine && !peer->isSelf()) {
|
||||
if (ShowTransferGiftLater(window->uiShow(), unique)) {
|
||||
return;
|
||||
}
|
||||
const auto done = [=] {
|
||||
window->session().credits().load(true);
|
||||
window->showPeerHistory(peer);
|
||||
};
|
||||
if (state->transferRequested == unique) {
|
||||
return;
|
||||
}
|
||||
state->transferRequested = unique;
|
||||
const auto savedId = star->transferId;
|
||||
using Payments::CheckoutResult;
|
||||
const auto formReady = [=](
|
||||
uint64 formId,
|
||||
CreditsAmount price,
|
||||
std::optional<CheckoutResult> failure) {
|
||||
state->transferRequested = nullptr;
|
||||
if (!failure && !price.stars()) {
|
||||
LOG(("API Error: Bad transfer invoice currenct."));
|
||||
} else if (!failure
|
||||
|| *failure == CheckoutResult::Free) {
|
||||
unique->starsForTransfer = failure
|
||||
? 0
|
||||
: price.whole();
|
||||
ShowTransferToBox(
|
||||
window,
|
||||
peer,
|
||||
unique,
|
||||
savedId,
|
||||
done);
|
||||
} else if (*failure == CheckoutResult::Cancelled) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
RequestOurForm(
|
||||
window->uiShow(),
|
||||
MTP_inputInvoiceStarGiftTransfer(
|
||||
Api::InputSavedStarGiftId(savedId, unique),
|
||||
peer->input()),
|
||||
formReady);
|
||||
} else if (star && star->resale) {
|
||||
const auto id = star->info.id;
|
||||
if (state->resaleRequestingId == id) {
|
||||
return;
|
||||
}
|
||||
state->resaleRequestingId = id;
|
||||
state->resaleLifetime = ShowStarGiftResale(
|
||||
window,
|
||||
peer,
|
||||
id,
|
||||
star->info.resellTitle,
|
||||
[=] { state->resaleRequestingId = 0; });
|
||||
} else if (star && star->info.auction()) {
|
||||
if (!IsSoldOut(star->info)
|
||||
&& premiumNeeded
|
||||
&& !peer->session().premium()) {
|
||||
Settings::ShowPremiumGiftPremium(window, star->info);
|
||||
} else {
|
||||
const auto id = star->info.id;
|
||||
if (state->resaleRequestingId == id) {
|
||||
return;
|
||||
}
|
||||
state->resaleRequestingId = id;
|
||||
state->resaleLifetime = ShowStarGiftAuction(
|
||||
window,
|
||||
peer,
|
||||
id,
|
||||
[=] { state->resaleRequestingId = 0; },
|
||||
crl::guard(&state->guard, [=] {
|
||||
state->resaleLifetime.destroy();
|
||||
}));
|
||||
}
|
||||
} else if (star && IsSoldOut(star->info)) {
|
||||
window->show(Box(SoldOutBox, window, *star));
|
||||
} else if (premiumNeeded && !peer->session().premium()) {
|
||||
Settings::ShowPremiumGiftPremium(window, star->info);
|
||||
} else if (star
|
||||
&& star->info.lockedUntilDate
|
||||
&& star->info.lockedUntilDate > base::unixtime::now()) {
|
||||
const auto ready = crl::guard(window, [=] {
|
||||
if (premiumNeeded && !peer->session().premium()) {
|
||||
Settings::ShowPremiumGiftPremium(
|
||||
window,
|
||||
v::get<GiftTypeStars>(descriptor).info);
|
||||
} else {
|
||||
send();
|
||||
}
|
||||
});
|
||||
CheckMaybeGiftLocked(window, star->info.id, ready);
|
||||
} else if (star
|
||||
&& star->info.perUserTotal
|
||||
&& !star->info.perUserRemains) {
|
||||
window->showToast({
|
||||
.text = tr::lng_gift_sent_finished(
|
||||
tr::now,
|
||||
lt_count,
|
||||
star->info.perUserTotal,
|
||||
tr::rich),
|
||||
});
|
||||
} else {
|
||||
send();
|
||||
}
|
||||
}
|
||||
|
||||
object_ptr<RpWidget> MakeGiftsList(GiftsListArgs &&args) {
|
||||
using namespace Info::PeerGifts;
|
||||
|
||||
auto result = object_ptr<VisibleRangeWidget>((QWidget*)nullptr);
|
||||
const auto raw = result.data();
|
||||
|
||||
const auto mode = args.mode;
|
||||
const auto peer = args.peer;
|
||||
const auto window = args.window;
|
||||
const auto session = &window->session();
|
||||
|
||||
Data::AmPremiumValue(session) | rpl::on_next([=] {
|
||||
raw->update();
|
||||
}, raw->lifetime());
|
||||
|
||||
struct State {
|
||||
Delegate delegate;
|
||||
DefaultGiftHandlerState handlerState;
|
||||
std::vector<int> order;
|
||||
std::vector<bool> validated;
|
||||
std::vector<GiftDescriptor> list;
|
||||
std::vector<std::unique_ptr<GiftButton>> buttons;
|
||||
rpl::variable<VisibleRange> visibleRange;
|
||||
bool sending = false;
|
||||
int perRow = 1;
|
||||
};
|
||||
const auto buttonMode = (mode == GiftsListMode::Craft)
|
||||
? GiftButtonMode::Craft
|
||||
: GiftButtonMode::Full;
|
||||
const auto state = raw->lifetime().make_state<State>(State{
|
||||
.delegate = Delegate(session, buttonMode),
|
||||
.handlerState = {
|
||||
.window = window,
|
||||
.peer = peer,
|
||||
},
|
||||
});
|
||||
const auto single = state->delegate.buttonSize();
|
||||
const auto shadow = st::defaultDropdownMenu.wrap.shadow;
|
||||
const auto extend = shadow.extend;
|
||||
|
||||
const auto handler = args.handler
|
||||
? args.handler
|
||||
: crl::guard(raw, [=](const GiftDescriptor &descriptor) {
|
||||
DefaultGiftHandler(window, &state->handlerState, descriptor);
|
||||
});
|
||||
|
||||
auto &packs = session->giftBoxStickersPacks();
|
||||
packs.updated() | rpl::on_next([=] {
|
||||
for (const auto &button : state->buttons) {
|
||||
if (const auto raw = button.get()) {
|
||||
raw->update();
|
||||
}
|
||||
}
|
||||
}, raw->lifetime());
|
||||
|
||||
const auto loadMore = args.loadMore;
|
||||
const auto alreadySelected = args.selected;
|
||||
const auto rebuild = [=] {
|
||||
const auto width = st::boxWideWidth;
|
||||
const auto padding = st::giftBoxPadding;
|
||||
const auto available = width - padding.left() - padding.right();
|
||||
const auto range = state->visibleRange.current();
|
||||
const auto count = int(state->list.size());
|
||||
|
||||
auto &buttons = state->buttons;
|
||||
if (buttons.size() < count) {
|
||||
buttons.resize(count);
|
||||
}
|
||||
auto &validated = state->validated;
|
||||
validated.resize(count);
|
||||
|
||||
auto x = padding.left();
|
||||
auto y = padding.top();
|
||||
const auto perRow = state->perRow;
|
||||
const auto singlew = single.width() + st::giftBoxGiftSkip.x();
|
||||
const auto singleh = single.height() + st::giftBoxGiftSkip.y();
|
||||
const auto rangeFrom = range.top - y;
|
||||
const auto rowFrom = std::max(rangeFrom, 0) / singleh;
|
||||
const auto rangeTill = range.bottom - y + st::giftBoxGiftSkip.y();
|
||||
const auto rowTill = (std::max(rangeTill, 0) + singleh - 1)
|
||||
/ singleh;
|
||||
Assert(rowTill >= rowFrom);
|
||||
const auto first = rowFrom * perRow;
|
||||
const auto last = std::min(rowTill * perRow, count);
|
||||
auto checkedFrom = 0;
|
||||
auto checkedTill = int(buttons.size());
|
||||
const auto ensureButton = [&](int index) {
|
||||
auto &button = buttons[index];
|
||||
if (!button) {
|
||||
validated[index] = false;
|
||||
for (; checkedFrom != first; ++checkedFrom) {
|
||||
if (buttons[checkedFrom]) {
|
||||
button = std::move(buttons[checkedFrom]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!button) {
|
||||
for (; checkedTill != last; ) {
|
||||
--checkedTill;
|
||||
if (buttons[checkedTill]) {
|
||||
button = std::move(buttons[checkedTill]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!button) {
|
||||
button = std::make_unique<GiftButton>(raw, &state->delegate);
|
||||
}
|
||||
const auto raw = button.get();
|
||||
if (validated[index]) {
|
||||
return;
|
||||
}
|
||||
raw->show();
|
||||
validated[index] = true;
|
||||
const auto &descriptor = state->list[state->order[index]];
|
||||
if (mode == GiftsListMode::Craft) {
|
||||
const auto already = ranges::contains(
|
||||
alreadySelected,
|
||||
v::get<GiftTypeStars>(descriptor).info.unique->slug,
|
||||
&Data::UniqueGift::slug);
|
||||
raw->toggleSelected(
|
||||
already,
|
||||
GiftSelectionMode::Inset,
|
||||
anim::type::instant);
|
||||
raw->setAttribute(Qt::WA_TransparentForMouseEvents, already);
|
||||
}
|
||||
raw->setDescriptor(descriptor, buttonMode);
|
||||
raw->setClickedCallback([=] {
|
||||
handler(descriptor);
|
||||
});
|
||||
raw->setGeometry(QRect(QPoint(x, y), single), extend);
|
||||
};
|
||||
y += rowFrom * singleh;
|
||||
for (auto row = rowFrom; row != rowTill; ++row) {
|
||||
for (auto col = 0; col != perRow; ++col) {
|
||||
const auto index = row * perRow + col;
|
||||
if (index >= count) {
|
||||
break;
|
||||
}
|
||||
const auto last = !((col + 1) % perRow);
|
||||
if (last) {
|
||||
x = padding.left() + available - single.width();
|
||||
}
|
||||
ensureButton(index);
|
||||
if (last) {
|
||||
x = padding.left();
|
||||
y += singleh;
|
||||
} else {
|
||||
x += singlew;
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto till = std::min(int(buttons.size()), rowTill * perRow);
|
||||
for (auto i = count; i < till; ++i) {
|
||||
if (const auto button = buttons[i].get()) {
|
||||
button->hide();
|
||||
}
|
||||
}
|
||||
|
||||
const auto page = range.bottom - range.top;
|
||||
if (loadMore && page > 0 && range.bottom + page > raw->height()) {
|
||||
loadMore();
|
||||
}
|
||||
};
|
||||
|
||||
state->visibleRange = raw->visibleRange();
|
||||
state->visibleRange.value(
|
||||
) | rpl::on_next(rebuild, raw->lifetime());
|
||||
|
||||
std::move(
|
||||
args.gifts
|
||||
) | rpl::on_next([=](const GiftsDescriptor &gifts) {
|
||||
const auto width = st::boxWideWidth;
|
||||
const auto padding = st::giftBoxPadding;
|
||||
const auto available = width - padding.left() - padding.right();
|
||||
state->perRow = available / single.width();
|
||||
state->list = std::move(gifts.list);
|
||||
state->handlerState.api = gifts.api;
|
||||
|
||||
const auto count = int(state->list.size());
|
||||
state->order = ranges::views::ints
|
||||
| ranges::views::take(count)
|
||||
| ranges::to_vector;
|
||||
state->validated.clear();
|
||||
|
||||
if (SortForBirthday(peer)) {
|
||||
ranges::stable_partition(state->order, [&](int i) {
|
||||
const auto &gift = state->list[i];
|
||||
const auto stars = std::get_if<GiftTypeStars>(&gift);
|
||||
return stars && stars->info.birthday && !stars->info.unique;
|
||||
});
|
||||
}
|
||||
|
||||
const auto rows = (count + state->perRow - 1) / state->perRow;
|
||||
const auto height = padding.top()
|
||||
+ (rows * single.height())
|
||||
+ ((rows - 1) * st::giftBoxGiftSkip.y())
|
||||
+ padding.bottom();
|
||||
raw->resize(raw->width(), height);
|
||||
rebuild();
|
||||
}, raw->lifetime());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SendGiftBox(
|
||||
|
||||
@@ -156,12 +156,21 @@ struct GiftsDescriptor {
|
||||
std::vector<Info::PeerGifts::GiftDescriptor> list;
|
||||
std::shared_ptr<Api::PremiumGiftCodeOptions> api;
|
||||
};
|
||||
[[nodiscard]] object_ptr<RpWidget> MakeGiftsSendList(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<PeerData*> peer,
|
||||
rpl::producer<GiftsDescriptor> gifts,
|
||||
Fn<void()> loadMore,
|
||||
Fn<void(Info::PeerGifts::GiftDescriptor)> handler = nullptr);
|
||||
enum class GiftsListMode {
|
||||
Send,
|
||||
Craft,
|
||||
CraftResale,
|
||||
};
|
||||
struct GiftsListArgs {
|
||||
not_null<Window::SessionController*> window;
|
||||
GiftsListMode mode = GiftsListMode::Send;
|
||||
not_null<PeerData*> peer;
|
||||
rpl::producer<GiftsDescriptor> gifts;
|
||||
std::vector<std::shared_ptr<Data::UniqueGift>> selected;
|
||||
Fn<void()> loadMore;
|
||||
Fn<void(Info::PeerGifts::GiftDescriptor)> handler;
|
||||
};
|
||||
[[nodiscard]] object_ptr<RpWidget> MakeGiftsList(GiftsListArgs &&args);
|
||||
|
||||
void SendGiftBox(
|
||||
not_null<GenericBox*> box,
|
||||
|
||||
@@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/gradient_round_button.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/top_background_gradient.h"
|
||||
#include "ui/ui_utility.h"
|
||||
@@ -51,8 +52,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
constexpr auto kCraftGiftsLimit = 30;
|
||||
|
||||
using namespace Info::PeerGifts;
|
||||
|
||||
struct ColorScheme {
|
||||
@@ -562,6 +561,104 @@ AbstractButton *MakeRemoveButton(
|
||||
};
|
||||
}
|
||||
|
||||
void AddCraftGiftsList(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<VerticalLayout*> container,
|
||||
Data::CraftGiftsDescriptor descriptor,
|
||||
const std::vector<GiftForCraft> &selected,
|
||||
Fn<void(std::shared_ptr<Data::UniqueGift>)> chosen) {
|
||||
struct State {
|
||||
rpl::event_stream<> updated;
|
||||
Data::CraftGiftsDescriptor data;
|
||||
QString offset;
|
||||
rpl::variable<bool> empty = true;
|
||||
rpl::lifetime loading;
|
||||
};
|
||||
const auto state = container->lifetime().make_state<State>();
|
||||
state->data = std::move(descriptor);
|
||||
|
||||
using Descriptor = Info::PeerGifts::GiftDescriptor;
|
||||
using StarGift = Info::PeerGifts::GiftTypeStars;
|
||||
auto handler = crl::guard(container, [=](Descriptor descriptor) {
|
||||
Expects(v::is<StarGift>(descriptor));
|
||||
|
||||
const auto unique = v::get<StarGift>(descriptor).info.unique;
|
||||
chosen(unique);
|
||||
});
|
||||
|
||||
auto gifts = rpl::single(
|
||||
rpl::empty
|
||||
) | rpl::then(state->updated.events()) | rpl::map([=] {
|
||||
auto result = GiftsDescriptor();
|
||||
const auto selfId = window->session().userPeerId();
|
||||
for (const auto &gift : state->data.list) {
|
||||
result.list.push_back(Info::PeerGifts::GiftTypeStars{
|
||||
.info = gift.info,
|
||||
.resale = true,
|
||||
.mine = (gift.info.unique->ownerId == selfId),
|
||||
});
|
||||
}
|
||||
state->empty = result.list.empty();
|
||||
return result;
|
||||
});
|
||||
const auto peer = window->session().user();
|
||||
const auto loadMore = [=] {
|
||||
if (!state->offset.isEmpty() && !state->loading) {
|
||||
state->loading = Data::CraftGiftsSlice(
|
||||
&peer->session(),
|
||||
state->data.giftId,
|
||||
state->data.offset
|
||||
) | rpl::on_next([=](Data::CraftGiftsDescriptor &&slice) {
|
||||
state->loading.destroy();
|
||||
state->data.offset = slice.list.empty()
|
||||
? QString()
|
||||
: slice.offset;
|
||||
state->data.list.insert(
|
||||
end(state->data.list),
|
||||
std::make_move_iterator(begin(slice.list)),
|
||||
std::make_move_iterator(end(slice.list)));
|
||||
state->updated.fire({});
|
||||
});
|
||||
}
|
||||
};
|
||||
container->add(MakeGiftsList({
|
||||
.window = window,
|
||||
.mode = GiftsListMode::Craft,
|
||||
.peer = peer,
|
||||
.gifts = std::move(gifts),
|
||||
.selected = (selected
|
||||
| ranges::views::transform(&GiftForCraft::unique)
|
||||
| ranges::to_vector),
|
||||
.loadMore = loadMore,
|
||||
.handler = handler,
|
||||
}));
|
||||
|
||||
const auto skip = st::defaultSubsectionTitlePadding.top();
|
||||
const auto wrap = container->add(
|
||||
object_ptr<SlideWrap<FlatLabel>>(
|
||||
container,
|
||||
object_ptr<FlatLabel>(
|
||||
container,
|
||||
tr::lng_gift_craft_select_none(),
|
||||
st::craftYourListEmpty),
|
||||
(st::boxRowPadding + QMargins(0, 0, 0, skip))),
|
||||
style::al_top);
|
||||
state->empty.value() | rpl::on_next([=](bool empty) {
|
||||
// Scroll doesn't jump up if we show before rows are cleared,
|
||||
// and we hide after rows are added.
|
||||
if (empty) {
|
||||
wrap->show(anim::type::instant);
|
||||
} else {
|
||||
crl::on_main(wrap, [=] {
|
||||
if (!state->empty.current()) {
|
||||
wrap->hide(anim::type::instant);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, wrap->lifetime());
|
||||
wrap->entity()->setTryMakeSimilarLines(true);
|
||||
}
|
||||
|
||||
void ShowSelectGiftBox(
|
||||
not_null<Window::SessionController*> controller,
|
||||
uint64 giftId,
|
||||
@@ -573,24 +670,17 @@ void ShowSelectGiftBox(
|
||||
GiftButton *button = nullptr;
|
||||
};
|
||||
struct State {
|
||||
explicit State(not_null<Main::Session*> session)
|
||||
: delegate(session, GiftButtonMode::Minimal) {
|
||||
}
|
||||
|
||||
Delegate delegate;
|
||||
std::vector<Entry> entries;
|
||||
|
||||
std::vector<Data::SavedStarGift> myList;
|
||||
QString myOffset;
|
||||
bool myFinished = false;
|
||||
|
||||
Data::CraftGiftsDescriptor craft;
|
||||
Data::ResaleGiftsDescriptor resale;
|
||||
|
||||
rpl::lifetime craftLifetime;
|
||||
rpl::lifetime resaleLifetime;
|
||||
};
|
||||
|
||||
const auto session = &controller->session();
|
||||
const auto state = std::make_shared<State>(session);
|
||||
const auto state = std::make_shared<State>();
|
||||
|
||||
const auto make = [=](not_null<GenericBox*> box) {
|
||||
box->setTitle(tr::lng_gift_craft_select_title());
|
||||
@@ -602,65 +692,18 @@ void ShowSelectGiftBox(
|
||||
box->verticalLayout(),
|
||||
tr::lng_gift_craft_select_your());
|
||||
|
||||
if (state->myList.empty()) {
|
||||
box->addRow(
|
||||
object_ptr<FlatLabel>(
|
||||
box,
|
||||
tr::lng_gift_craft_select_none(),
|
||||
st::craftYourListEmpty),
|
||||
style::al_top
|
||||
)->setTryMakeSimilarLines(true);
|
||||
}
|
||||
const auto got = crl::guard(box, [=](
|
||||
std::shared_ptr<Data::UniqueGift> gift) {
|
||||
chosen(GiftForCraft{ .unique = gift });
|
||||
box->closeBox();
|
||||
});
|
||||
|
||||
const auto single = state->delegate.buttonSize();
|
||||
const auto extend = state->delegate.buttonExtend();
|
||||
const auto full = single.grownBy(extend).height();
|
||||
const auto skip = st::boxRowPadding.left() / 2;
|
||||
const auto gifts = box->addRow(
|
||||
object_ptr<VisibleRangeWidget>(box),
|
||||
QMargins());
|
||||
for (auto &gift : state->myList) {
|
||||
const auto row = (state->entries.size() / 3);
|
||||
const auto col = (state->entries.size() % 3);
|
||||
state->entries.push_back(Entry{
|
||||
.gift = gift,
|
||||
.button = CreateChild<GiftButton>(gifts, &state->delegate),
|
||||
});
|
||||
const auto button = state->entries.back().button;
|
||||
const auto proj = &GiftForCraft::slugId;
|
||||
if (ranges::contains(selected, gift.info.unique->slug, proj)) {
|
||||
button->toggleSelected(
|
||||
true,
|
||||
GiftSelectionMode::Inset,
|
||||
anim::type::instant);
|
||||
button->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
} else {
|
||||
button->setClickedCallback([=] {
|
||||
chosen({ gift.info.unique, gift.manageId });
|
||||
box->closeBox();
|
||||
});
|
||||
}
|
||||
button->show();
|
||||
button->setDescriptor(GiftTypeStars{
|
||||
.info = {
|
||||
.id = gift.info.id,
|
||||
.unique = gift.info.unique,
|
||||
.document = gift.info.unique->model.document,
|
||||
},
|
||||
}, GiftButton::Mode::Minimal);
|
||||
const auto width = (st::boxWideWidth
|
||||
- 2 * skip
|
||||
- st::boxRowPadding.left()
|
||||
- st::boxRowPadding.right()) / 3;
|
||||
const auto x = st::boxRowPadding.left() + (width + skip) * col;
|
||||
const auto y = extend.top() + full * row;
|
||||
button->setGeometry(
|
||||
QRect(x, y, width, single.height()),
|
||||
extend);
|
||||
}
|
||||
gifts->resize(
|
||||
gifts->width(),
|
||||
(state->myList.size() + 2) / 3 * full);
|
||||
AddCraftGiftsList(
|
||||
controller,
|
||||
box->verticalLayout(),
|
||||
state->craft,
|
||||
selected,
|
||||
got);
|
||||
|
||||
if (const auto count = state->resale.count) {
|
||||
AddSubsectionTitle(
|
||||
@@ -669,18 +712,13 @@ void ShowSelectGiftBox(
|
||||
lt_count,
|
||||
rpl::single(count * 1.)));
|
||||
|
||||
const auto bought = crl::guard(box, [=](
|
||||
std::shared_ptr<Data::UniqueGift> gift) {
|
||||
chosen(GiftForCraft{ .unique = gift });
|
||||
box->closeBox();
|
||||
});
|
||||
AddResaleGiftsList(
|
||||
controller,
|
||||
controller->session().user(),
|
||||
session->user(),
|
||||
box->verticalLayout(),
|
||||
state->resale,
|
||||
rpl::single(false),
|
||||
bought,
|
||||
got,
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -693,33 +731,17 @@ void ShowSelectGiftBox(
|
||||
controller->show(Box(make));
|
||||
});
|
||||
|
||||
session->api().request(MTPpayments_GetCraftStarGifts(
|
||||
MTP_long(giftId),
|
||||
MTP_string(),
|
||||
MTP_int(kCraftGiftsLimit)
|
||||
)).done([=](const MTPpayments_SavedStarGifts &result) {
|
||||
const auto user = session->user();
|
||||
const auto owner = &session->data();
|
||||
const auto &data = result.data();
|
||||
owner->processUsers(data.vusers());
|
||||
owner->processChats(data.vchats());
|
||||
|
||||
auto list = std::vector<Data::SavedStarGift>();
|
||||
list.reserve(data.vgifts().v.size());
|
||||
for (const auto &gift : data.vgifts().v) {
|
||||
if (auto parsed = Api::FromTL(user, gift)) {
|
||||
list.push_back(std::move(*parsed));
|
||||
}
|
||||
}
|
||||
|
||||
state->myList = std::move(list);
|
||||
state->myOffset = qs(data.vnext_offset().value_or_empty());
|
||||
state->myFinished = !data.vnext_offset();
|
||||
state->craftLifetime = Data::CraftGiftsSlice(
|
||||
session,
|
||||
giftId
|
||||
) | rpl::on_next([=](Data::CraftGiftsDescriptor &&info) {
|
||||
state->craftLifetime.destroy();
|
||||
|
||||
state->craft = std::move(info);
|
||||
if (state->resale.giftId) {
|
||||
show();
|
||||
}
|
||||
}).send();
|
||||
});
|
||||
|
||||
state->resaleLifetime = Data::ResaleGiftsSlice(
|
||||
session,
|
||||
@@ -729,7 +751,7 @@ void ShowSelectGiftBox(
|
||||
state->resaleLifetime.destroy();
|
||||
|
||||
state->resale = std::move(info);
|
||||
if (!state->myList.empty() || state->myFinished) {
|
||||
if (state->craft.giftId) {
|
||||
show();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -652,7 +652,7 @@ void AddResaleGiftsList(
|
||||
});
|
||||
}
|
||||
|
||||
container->add(MakeGiftsSendList(window, peer, rpl::single(
|
||||
auto gifts = rpl::single(
|
||||
rpl::empty
|
||||
) | rpl::then(rpl::merge(
|
||||
state->updated.events() | rpl::type_erased,
|
||||
@@ -662,16 +662,21 @@ void AddResaleGiftsList(
|
||||
const auto selfId = window->session().userPeerId();
|
||||
const auto forceTon = state->ton.current();
|
||||
for (const auto &gift : state->data.list) {
|
||||
const auto mine = (gift.unique->ownerId == selfId);
|
||||
if (mine && forCraft) {
|
||||
continue;
|
||||
}
|
||||
result.list.push_back(Info::PeerGifts::GiftTypeStars{
|
||||
.info = gift,
|
||||
.forceTon = forceTon,
|
||||
.resale = true,
|
||||
.mine = (gift.unique->ownerId == selfId),
|
||||
});
|
||||
.mine = mine,
|
||||
});
|
||||
}
|
||||
state->empty = result.list.empty();
|
||||
return result;
|
||||
}), [=] {
|
||||
});
|
||||
const auto loadMore = [=] {
|
||||
if (!state->data.offset.isEmpty()
|
||||
&& !state->loading) {
|
||||
state->loading = ResaleGiftsSlice(
|
||||
@@ -691,7 +696,15 @@ void AddResaleGiftsList(
|
||||
state->updated.fire({});
|
||||
});
|
||||
}
|
||||
}, customHandler));
|
||||
};
|
||||
container->add(MakeGiftsList({
|
||||
.window = window,
|
||||
.mode = forCraft ? GiftsListMode::CraftResale : GiftsListMode::Send,
|
||||
.peer = peer,
|
||||
.gifts = std::move(gifts),
|
||||
.loadMore = loadMore,
|
||||
.handler = customHandler,
|
||||
}));
|
||||
|
||||
const auto skip = st::defaultSubsectionTitlePadding.top();
|
||||
const auto wrap = container->add(
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace {
|
||||
|
||||
constexpr auto kMyGiftsPerPage = 50;
|
||||
constexpr auto kResaleGiftsPerPage = 50;
|
||||
constexpr auto kCraftGiftsPerPage = 50;
|
||||
|
||||
[[nodiscard]] MTPStarGiftAttributeId AttributeToTL(GiftAttributeId id) {
|
||||
switch (id.type) {
|
||||
@@ -305,4 +306,45 @@ rpl::producer<ResaleGiftsDescriptor> ResaleGiftsSlice(
|
||||
};
|
||||
}
|
||||
|
||||
rpl::producer<CraftGiftsDescriptor> CraftGiftsSlice(
|
||||
not_null<Main::Session*> session,
|
||||
uint64 giftId,
|
||||
QString offset) {
|
||||
return [=](auto consumer) {
|
||||
const auto requestId = session->api().request(
|
||||
MTPpayments_GetCraftStarGifts(
|
||||
MTP_long(giftId),
|
||||
MTP_string(),
|
||||
MTP_int(kCraftGiftsPerPage))
|
||||
).done([=](const MTPpayments_SavedStarGifts &result) {
|
||||
const auto user = session->user();
|
||||
const auto owner = &session->data();
|
||||
const auto &data = result.data();
|
||||
owner->processUsers(data.vusers());
|
||||
owner->processChats(data.vchats());
|
||||
|
||||
auto info = CraftGiftsDescriptor{
|
||||
.giftId = giftId,
|
||||
.offset = qs(data.vnext_offset().value_or_empty()),
|
||||
.count = data.vcount().v,
|
||||
};
|
||||
info.list.reserve(data.vgifts().v.size());
|
||||
for (const auto &gift : data.vgifts().v) {
|
||||
if (auto parsed = Api::FromTL(user, gift)) {
|
||||
info.list.push_back(std::move(*parsed));
|
||||
}
|
||||
}
|
||||
consumer.put_next(std::move(info));
|
||||
consumer.put_done();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
consumer.put_next({});
|
||||
consumer.put_done();
|
||||
}).send();
|
||||
|
||||
auto lifetime = rpl::lifetime();
|
||||
lifetime.add([=] { session->api().request(requestId).cancel(); });
|
||||
return lifetime;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
@@ -408,4 +408,16 @@ struct ResaleGiftsFilter {
|
||||
ResaleGiftsFilter filter = {},
|
||||
QString offset = QString());
|
||||
|
||||
struct CraftGiftsDescriptor {
|
||||
uint64 giftId = 0;
|
||||
QString offset;
|
||||
std::vector<SavedStarGift> list;
|
||||
int count = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] rpl::producer<CraftGiftsDescriptor> CraftGiftsSlice(
|
||||
not_null<Main::Session*> session,
|
||||
uint64 giftId,
|
||||
QString offset = QString());
|
||||
|
||||
} // namespace Data
|
||||
|
||||
@@ -270,7 +270,7 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) {
|
||||
: data.from
|
||||
? Ui::MakeUserpicThumbnail(data.from)
|
||||
: Ui::MakeHiddenAuthorThumbnail();
|
||||
if (small() && !resale) {
|
||||
if (small() && !resale || (_mode == GiftButtonMode::Craft)) {
|
||||
_price = {};
|
||||
_stars.reset();
|
||||
return;
|
||||
@@ -337,7 +337,7 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) {
|
||||
_uniquePatternEmoji = nullptr;
|
||||
_uniquePatternCache.clear();
|
||||
|
||||
if (small() && !resale) {
|
||||
if (_price.isEmpty()) {
|
||||
_button = QRect();
|
||||
return;
|
||||
}
|
||||
@@ -817,7 +817,8 @@ void GiftButton::paint(QPainter &p, float64 craftProgress) {
|
||||
QRect(
|
||||
(width - size.width()) / 2,
|
||||
((_mode == GiftButtonMode::CraftPreview
|
||||
|| _mode == GiftButtonMode::Minimal)
|
||||
|| _mode == GiftButtonMode::Minimal
|
||||
|| _mode == GiftButtonMode::Craft)
|
||||
? (extend.top()
|
||||
+ ((height
|
||||
- extend.top()
|
||||
@@ -970,7 +971,7 @@ void GiftButton::paint(QPainter &p, float64 craftProgress) {
|
||||
|
||||
v::match(_descriptor, [](const GiftTypePremium &) {
|
||||
}, [&](const GiftTypeStars &data) {
|
||||
if (!unique || _mode == Mode::CraftPreview) {
|
||||
if (!unique || _mode == Mode::Craft || _mode == Mode::CraftPreview) {
|
||||
} else if (data.pinned && _mode != GiftButtonMode::Selection) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
const auto &icon = st::giftBoxPinIcon;
|
||||
|
||||
@@ -138,6 +138,7 @@ struct GiftBadge {
|
||||
|
||||
enum class GiftButtonMode : uint8 {
|
||||
Full,
|
||||
Craft,
|
||||
Minimal,
|
||||
Selection,
|
||||
CraftPreview,
|
||||
|
||||
Reference in New Issue
Block a user