Full upgradable variants preview.
This commit is contained in:
@@ -121,7 +121,7 @@ namespace {
|
||||
return true;
|
||||
};
|
||||
if (!updateThumbnail()) {
|
||||
document->owner().session().downloaderTaskFinished(
|
||||
document->session().downloaderTaskFinished(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (updateThumbnail()) {
|
||||
state->loadingLifetime.destroy();
|
||||
|
||||
@@ -1731,14 +1731,14 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
||||
}
|
||||
return result;
|
||||
};
|
||||
auto &api = history->owner().session().api();
|
||||
auto &api = history->session().api();
|
||||
auto &histories = history->owner().histories();
|
||||
const auto donePhraseArgs = CreateForwardedMessagePhraseArgs(
|
||||
result,
|
||||
msgIds);
|
||||
const auto showRecentForwardsToSelf = result.size() == 1
|
||||
&& result.front()->peer()->isSelf()
|
||||
&& history->owner().session().premium();
|
||||
&& history->session().premium();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
for (const auto thread : result) {
|
||||
if (!comment.text.isEmpty()) {
|
||||
|
||||
@@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/send_credits_box.h" // CreditsEmojiSmall
|
||||
#include "boxes/share_box.h"
|
||||
#include "boxes/star_gift_box.h"
|
||||
#include "boxes/star_gift_preview_box.h"
|
||||
#include "boxes/star_gift_resale_box.h"
|
||||
#include "calls/group/calls_group_common.h"
|
||||
#include "core/application.h"
|
||||
@@ -1190,11 +1191,14 @@ void AuctionGotGiftsBox(
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<Data::UniqueGift> MakePreviewAuctionStream(
|
||||
[[nodiscard]] rpl::producer<UniqueGiftCover> MakePreviewAuctionStream(
|
||||
const Data::StarGift &info,
|
||||
rpl::producer<Data::UniqueGiftAttributes> attributes) {
|
||||
Expects(attributes);
|
||||
|
||||
const auto cover = [](Data::UniqueGift gift) {
|
||||
return UniqueGiftCover{ std::move(gift) };
|
||||
};
|
||||
auto initial = Data::UniqueGift{
|
||||
.title = info.resellTitle,
|
||||
.model = Data::UniqueGiftModel{
|
||||
@@ -1207,14 +1211,14 @@ void AuctionGotGiftsBox(
|
||||
? info.background->backdrop()
|
||||
: Data::UniqueGiftBackdrop()),
|
||||
};
|
||||
return rpl::single(initial) | rpl::then(std::move(
|
||||
return rpl::single(cover(initial)) | rpl::then(std::move(
|
||||
attributes
|
||||
) | rpl::map([=](const Data::UniqueGiftAttributes &values)
|
||||
-> rpl::producer<Data::UniqueGift> {
|
||||
-> rpl::producer<UniqueGiftCover> {
|
||||
if (values.backdrops.empty()
|
||||
|| values.models.empty()
|
||||
|| values.patterns.empty()) {
|
||||
return rpl::never<Data::UniqueGift>();
|
||||
return rpl::never<UniqueGiftCover>();
|
||||
}
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
@@ -1256,12 +1260,12 @@ void AuctionGotGiftsBox(
|
||||
auto &models = state->data.models;
|
||||
auto &patterns = state->data.patterns;
|
||||
auto &backdrops = state->data.backdrops;
|
||||
consumer.put_next(Data::UniqueGift{
|
||||
consumer.put_next(cover({
|
||||
.title = info.resellTitle,
|
||||
.model = models[index(state->modelIndices, models)],
|
||||
.pattern = patterns[index(state->patternIndices, patterns)],
|
||||
.backdrop = backdrops[index(state->backdropIndices, backdrops)],
|
||||
});
|
||||
}));
|
||||
};
|
||||
|
||||
put();
|
||||
@@ -1520,18 +1524,7 @@ void AuctionInfoBox(
|
||||
st::boxRowPadding + st::uniqueGiftValueAvailableMargin,
|
||||
style::al_top
|
||||
)->setClickHandlerFilter([=](const auto &...) {
|
||||
//if (state->previewRequested) {
|
||||
// return false;
|
||||
//}
|
||||
//state->previewRequested = true;
|
||||
//const auto &value = state->value.current();
|
||||
//const auto &gift = *value.gift;
|
||||
//state->previewLifetime = ShowStarGiftResale(
|
||||
// window,
|
||||
// peer,
|
||||
// gift.id,
|
||||
// gift.resellTitle,
|
||||
// [=] { state->previewRequested = false; });
|
||||
show->show(Box(StarGiftPreviewBox, window, *now.gift, list));
|
||||
return false;
|
||||
});
|
||||
}, box->lifetime());
|
||||
|
||||
@@ -2798,7 +2798,7 @@ void SetupResalePriceButton(
|
||||
|
||||
void AddUniqueGiftCover(
|
||||
not_null<VerticalLayout*> container,
|
||||
rpl::producer<Data::UniqueGift> data,
|
||||
rpl::producer<UniqueGiftCover> data,
|
||||
UniqueGiftCoverArgs &&args) {
|
||||
const auto cover = container->add(object_ptr<RpWidget>(container));
|
||||
|
||||
@@ -2812,16 +2812,18 @@ void AddUniqueGiftCover(
|
||||
style::FlatLabel st;
|
||||
PeerData *by = nullptr;
|
||||
QColor bg;
|
||||
QColor fg;
|
||||
};
|
||||
const auto released = cover->lifetime().make_state<Released>();
|
||||
released->st = st::uniqueGiftReleasedBy;
|
||||
released->st.palette.linkFg = released->link.color();
|
||||
|
||||
const auto repaintedHook = args.repaintedHook;
|
||||
if (args.resalePrice) {
|
||||
auto background = rpl::duplicate(
|
||||
data
|
||||
) | rpl::map([=](const Data::UniqueGift &unique) {
|
||||
auto result = unique.backdrop.patternColor;
|
||||
) | rpl::map([=](const UniqueGiftCover &cover) {
|
||||
auto result = cover.values.backdrop.patternColor;
|
||||
result.setAlphaF(kGradientButtonBgOpacity * result.alphaF());
|
||||
return result;
|
||||
});
|
||||
@@ -2870,12 +2872,15 @@ void AddUniqueGiftCover(
|
||||
cover,
|
||||
rpl::duplicate(
|
||||
data
|
||||
) | rpl::map([](const Data::UniqueGift &now) { return now.title; }),
|
||||
) | rpl::map([](const UniqueGiftCover &now) {
|
||||
return now.values.title;
|
||||
}),
|
||||
st::uniqueGiftTitle);
|
||||
title->setTextColorOverride(QColor(255, 255, 255));
|
||||
released->subtitleText = args.subtitle
|
||||
? std::move(args.subtitle)
|
||||
: rpl::duplicate(data) | rpl::map([=](const Data::UniqueGift &gift) {
|
||||
: rpl::duplicate(data) | rpl::map([=](const UniqueGiftCover &cover) {
|
||||
const auto &gift = cover.values;
|
||||
released->by = gift.releasedBy;
|
||||
return gift.releasedBy
|
||||
? tr::lng_gift_unique_number_by(
|
||||
@@ -2940,6 +2945,7 @@ void AddUniqueGiftCover(
|
||||
std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||
std::unique_ptr<Text::CustomEmoji> emoji;
|
||||
base::flat_map<float64, QImage> emojis;
|
||||
bool forced = false;
|
||||
rpl::lifetime lifetime;
|
||||
};
|
||||
struct State {
|
||||
@@ -2947,11 +2953,23 @@ void AddUniqueGiftCover(
|
||||
GiftView next;
|
||||
Animations::Simple crossfade;
|
||||
bool animating = false;
|
||||
bool updateAttributesPending = false;
|
||||
};
|
||||
const auto state = cover->lifetime().make_state<State>();
|
||||
const auto lottieSize = st::creditsHistoryEntryStarGiftSize;
|
||||
const auto updateLinkFg = args.subtitleLinkColored;
|
||||
const auto updateColors = [=](float64 progress) {
|
||||
if (repaintedHook) {
|
||||
repaintedHook(state->now.gift, state->next.gift, progress);
|
||||
}
|
||||
released->bg = (progress == 0.)
|
||||
? state->now.gift->backdrop.patternColor
|
||||
: (progress == 1.)
|
||||
? state->next.gift->backdrop.patternColor
|
||||
: anim::color(
|
||||
state->now.gift->backdrop.patternColor,
|
||||
state->next.gift->backdrop.patternColor,
|
||||
progress);
|
||||
const auto color = (progress == 0.)
|
||||
? state->now.gift->backdrop.textColor
|
||||
: (progress == 1.)
|
||||
@@ -2963,22 +2981,16 @@ void AddUniqueGiftCover(
|
||||
if (updateLinkFg) {
|
||||
released->link.update(color);
|
||||
}
|
||||
released->fg = color;
|
||||
subtitle->setTextColorOverride(color);
|
||||
released->bg = (progress == 0.)
|
||||
? state->now.gift->backdrop.patternColor
|
||||
: (progress == 1.)
|
||||
? state->next.gift->backdrop.patternColor
|
||||
: anim::color(
|
||||
state->now.gift->backdrop.patternColor,
|
||||
state->next.gift->backdrop.patternColor,
|
||||
progress);
|
||||
};
|
||||
std::move(
|
||||
rpl::duplicate(
|
||||
data
|
||||
) | rpl::start_with_next([=](const Data::UniqueGift &gift) {
|
||||
) | rpl::start_with_next([=](const UniqueGiftCover &now) {
|
||||
const auto setup = [&](GiftView &to) {
|
||||
to.gift = gift;
|
||||
const auto document = gift.model.document;
|
||||
to.gift = now.values;
|
||||
to.forced = now.force;
|
||||
const auto document = now.values.model.document;
|
||||
to.media = document->createMediaView();
|
||||
to.media->automaticLoad({}, nullptr);
|
||||
rpl::single() | rpl::then(
|
||||
@@ -3003,7 +3015,7 @@ void AddUniqueGiftCover(
|
||||
}, to.lifetime);
|
||||
}, to.lifetime);
|
||||
to.emoji = document->owner().customEmojiManager().create(
|
||||
gift.pattern.document,
|
||||
now.values.pattern.document,
|
||||
[=] { cover->update(); },
|
||||
Data::CustomEmojiSizeTag::Large);
|
||||
[[maybe_unused]] const auto preload = to.emoji->ready();
|
||||
@@ -3013,11 +3025,122 @@ void AddUniqueGiftCover(
|
||||
setup(state->now);
|
||||
cover->update();
|
||||
updateColors(0.);
|
||||
} else if (!state->next.gift) {
|
||||
} else if (!state->next.gift || now.force) {
|
||||
setup(state->next);
|
||||
}
|
||||
}, cover->lifetime());
|
||||
|
||||
const auto attrs = args.attributesInfo
|
||||
? CreateChild<RpWidget>(cover)
|
||||
: nullptr;
|
||||
auto updateAttrs = Fn<void(const Data::UniqueGift &)>([](const auto &) {
|
||||
});
|
||||
if (attrs) {
|
||||
struct AttributeState {
|
||||
Ui::Text::String name;
|
||||
Ui::Text::String type;
|
||||
Ui::Text::String percent;
|
||||
};
|
||||
struct AttributesState {
|
||||
AttributeState model;
|
||||
AttributeState pattern;
|
||||
AttributeState backdrop;
|
||||
};
|
||||
const auto astate = cover->lifetime().make_state<AttributesState>();
|
||||
const auto setType = [&](AttributeState &state, tr::phrase<> text) {
|
||||
state.type = Ui::Text::String(
|
||||
st::uniqueAttributeType,
|
||||
text(tr::now));
|
||||
};
|
||||
setType(astate->model, tr::lng_auction_preview_model);
|
||||
setType(astate->pattern, tr::lng_auction_preview_symbol);
|
||||
setType(astate->backdrop, tr::lng_auction_preview_backdrop);
|
||||
|
||||
updateAttrs = [=](const Data::UniqueGift &gift) {
|
||||
const auto set = [&](
|
||||
AttributeState &state,
|
||||
const Data::UniqueGiftAttribute &value) {
|
||||
state.name = Ui::Text::String(
|
||||
st::uniqueAttributeName,
|
||||
value.name);
|
||||
state.percent = Ui::Text::String(
|
||||
st::uniqueAttributePercent,
|
||||
QString::number(value.rarityPermille / 10.) + '%');
|
||||
};
|
||||
set(astate->model, gift.model);
|
||||
set(astate->pattern, gift.pattern);
|
||||
set(astate->backdrop, gift.backdrop);
|
||||
attrs->update();
|
||||
};
|
||||
const auto height = st::uniqueAttributeTop
|
||||
+ st::uniqueAttributePadding.top()
|
||||
+ st::uniqueAttributeName.font->height
|
||||
+ st::uniqueAttributeType.font->height
|
||||
+ st::uniqueAttributePadding.bottom();
|
||||
attrs->resize(attrs->width(), height);
|
||||
attrs->paintOn([=](QPainter &p) {
|
||||
const auto skip = st::giftBoxGiftSkip.x();
|
||||
const auto available = attrs->width() - 2 * skip;
|
||||
const auto single = available / 3;
|
||||
if (single <= 0) {
|
||||
return;
|
||||
}
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
auto bg = released->bg;
|
||||
bg.setAlphaF(kGradientButtonBgOpacity * bg.alphaF());
|
||||
const auto innert = st::uniqueAttributeTop;
|
||||
const auto innerh = height - innert;
|
||||
const auto radius = innerh / 3.;
|
||||
const auto paint = [&](int x, const AttributeState &state) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(bg);
|
||||
p.drawRoundedRect(x, innert, single, innerh, radius, radius);
|
||||
p.setPen(QColor(255, 255, 255));
|
||||
const auto padding = st::uniqueAttributePadding;
|
||||
const auto inner = single - padding.left() - padding.right();
|
||||
const auto namew = std::min(inner, state.name.maxWidth());
|
||||
state.name.draw(p, {
|
||||
.position = QPoint(
|
||||
x + (single - namew) / 2,
|
||||
innert + padding.top()),
|
||||
.availableWidth = namew,
|
||||
.elisionLines = 1,
|
||||
});
|
||||
p.setPen(released->fg);
|
||||
const auto typew = std::min(inner, state.type.maxWidth());
|
||||
state.type.draw(p, {
|
||||
.position = QPoint(
|
||||
x + (single - typew) / 2,
|
||||
innert + padding.top() + state.name.minHeight()),
|
||||
.availableWidth = typew,
|
||||
});
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(anim::color(released->bg, released->fg, 0.3));
|
||||
const auto r = st::uniqueAttributePercent.font->height / 2.;
|
||||
const auto left = x + single - state.percent.maxWidth();
|
||||
const auto top = st::uniqueAttributePercentPadding.top();
|
||||
const auto percent = QRect(
|
||||
left,
|
||||
top,
|
||||
state.percent.maxWidth(),
|
||||
st::uniqueAttributeType.font->height);
|
||||
p.drawRoundedRect(
|
||||
percent.marginsAdded(st::uniqueAttributePercentPadding),
|
||||
r,
|
||||
r);
|
||||
p.setPen(QColor(255, 255, 255));
|
||||
state.percent.draw(p, {
|
||||
.position = percent.topLeft(),
|
||||
});
|
||||
};
|
||||
auto left = 0;
|
||||
paint(left, astate->model);
|
||||
paint(left + single + skip, astate->backdrop);
|
||||
paint(attrs->width() - single - left, astate->pattern);
|
||||
});
|
||||
}
|
||||
updateAttrs(*state->now.gift);
|
||||
|
||||
cover->widthValue() | rpl::start_with_next([=](int width) {
|
||||
const auto skip = st::uniqueGiftBottom;
|
||||
if (width <= 3 * skip) {
|
||||
@@ -3043,14 +3166,32 @@ void AddUniqueGiftCover(
|
||||
}
|
||||
|
||||
subtitle->moveToLeft(skip, top);
|
||||
top += subtitle->height() + skip;
|
||||
|
||||
cover->resize(width, subtitle->y() + subtitle->height() + skip);
|
||||
if (attrs) {
|
||||
attrs->resizeToWidth(width
|
||||
- st::giftBoxPadding.left()
|
||||
- st::giftBoxPadding.right());
|
||||
attrs->moveToLeft(st::giftBoxPadding.left(), top);
|
||||
top += attrs->height() + (skip / 2);
|
||||
}
|
||||
|
||||
cover->resize(width, top);
|
||||
}, cover->lifetime());
|
||||
|
||||
cover->paintRequest() | rpl::start_with_next([=] {
|
||||
auto p = QPainter(cover);
|
||||
|
||||
auto progress = state->crossfade.value(state->animating ? 1. : 0.);
|
||||
if (state->updateAttributesPending && progress >= 0.5) {
|
||||
state->updateAttributesPending = false;
|
||||
updateAttrs(*state->next.gift);
|
||||
} else if (state->updateAttributesPending
|
||||
&& !state->animating
|
||||
&& !state->crossfade.animating()) {
|
||||
state->updateAttributesPending = false;
|
||||
updateAttrs(*state->now.gift);
|
||||
}
|
||||
if (state->animating) {
|
||||
updateColors(progress);
|
||||
}
|
||||
@@ -3105,10 +3246,13 @@ void AddUniqueGiftCover(
|
||||
};
|
||||
|
||||
if (progress < 1.) {
|
||||
const auto finished = paint(state->now, 1. - progress);
|
||||
const auto finished = paint(state->now, 1. - progress)
|
||||
|| (state->next.forced
|
||||
&& (!state->animating || !state->crossfade.animating()));
|
||||
const auto next = finished ? state->next.lottie.get() : nullptr;
|
||||
if (next && next->ready()) {
|
||||
state->animating = true;
|
||||
state->updateAttributesPending = true;
|
||||
state->crossfade.start([=] {
|
||||
cover->update();
|
||||
}, 0., 1., kCrossfadeDuration);
|
||||
@@ -3803,12 +3947,12 @@ struct UpgradeArgs : StarGiftUpgradeArgs {
|
||||
std::vector<UpgradePrice> nextPrices;
|
||||
};
|
||||
|
||||
[[nodiscard]] rpl::producer<Data::UniqueGift> MakeUpgradeGiftStream(
|
||||
[[nodiscard]] rpl::producer<UniqueGiftCover> MakeUpgradeGiftStream(
|
||||
const UpgradeArgs &args) {
|
||||
if (args.models.empty()
|
||||
|| args.patterns.empty()
|
||||
|| args.backdrops.empty()) {
|
||||
return rpl::never<Data::UniqueGift>();
|
||||
return rpl::never<UniqueGiftCover>();
|
||||
}
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
@@ -3846,14 +3990,14 @@ struct UpgradeArgs : StarGiftUpgradeArgs {
|
||||
auto &models = state->data.models;
|
||||
auto &patterns = state->data.patterns;
|
||||
auto &backdrops = state->data.backdrops;
|
||||
consumer.put_next(Data::UniqueGift{
|
||||
consumer.put_next(UniqueGiftCover{ Data::UniqueGift{
|
||||
.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)],
|
||||
.pattern = patterns[index(state->patternIndices, patterns)],
|
||||
.backdrop = backdrops[index(state->backdropIndices, backdrops)],
|
||||
});
|
||||
} });
|
||||
};
|
||||
|
||||
put();
|
||||
|
||||
@@ -72,11 +72,20 @@ struct UniqueGiftCoverArgs {
|
||||
bool subtitleLinkColored = false;
|
||||
rpl::producer<CreditsAmount> resalePrice;
|
||||
Fn<void()> resaleClick;
|
||||
bool attributesInfo = false;
|
||||
Fn<void(
|
||||
std::optional<Data::UniqueGift> now,
|
||||
std::optional<Data::UniqueGift> next,
|
||||
float64 progress)> repaintedHook;
|
||||
};
|
||||
struct UniqueGiftCover {
|
||||
Data::UniqueGift values;
|
||||
bool force = false;
|
||||
};
|
||||
|
||||
void AddUniqueGiftCover(
|
||||
not_null<VerticalLayout*> container,
|
||||
rpl::producer<Data::UniqueGift> data,
|
||||
rpl::producer<UniqueGiftCover> data,
|
||||
UniqueGiftCoverArgs &&args);
|
||||
void AddWearGiftCover(
|
||||
not_null<VerticalLayout*> container,
|
||||
|
||||
1406
Telegram/SourceFiles/boxes/star_gift_preview_box.cpp
Normal file
1406
Telegram/SourceFiles/boxes/star_gift_preview_box.cpp
Normal file
File diff suppressed because it is too large
Load Diff
29
Telegram/SourceFiles/boxes/star_gift_preview_box.h
Normal file
29
Telegram/SourceFiles/boxes/star_gift_preview_box.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Data {
|
||||
struct StarGift;
|
||||
struct UniqueGiftAttributes;
|
||||
} // namespace Data
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class GenericBox;
|
||||
|
||||
void StarGiftPreviewBox(
|
||||
not_null<GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const Data::StarGift &gift,
|
||||
const Data::UniqueGiftAttributes &attributes);
|
||||
|
||||
} // namespace Ui
|
||||
@@ -1548,7 +1548,7 @@ void StickerSetBox::Inner::fillDeleteStickerBox(
|
||||
const auto buttonWidth = state->saveButton
|
||||
? state->saveButton->width()
|
||||
: 0;
|
||||
state->requestId = document->owner().session().api().request(
|
||||
state->requestId = document->session().api().request(
|
||||
MTPstickers_RemoveStickerFromSet(document->mtpInput()
|
||||
)).done([=](const TLStickerSet &result) {
|
||||
result.match([&](const MTPDmessages_stickerSet &d) {
|
||||
@@ -1590,7 +1590,7 @@ void StickerSetBox::Inner::fillDeleteStickerBox(
|
||||
state->requestId.value() | rpl::map(rpl::mappers::_1 > 0));
|
||||
}
|
||||
box->addButton(tr::lng_close(), [=] {
|
||||
document->owner().session().api().request(
|
||||
document->session().api().request(
|
||||
state->requestId.current()).cancel();
|
||||
box->closeBox();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user