mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-03 21:54:05 +02:00
Implement "Choose gift to unpin" box feature.
This commit is contained in:
parent
bb8ecf2f84
commit
46e7b6d6df
10 changed files with 419 additions and 107 deletions
|
@ -3429,7 +3429,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_gift_display_done_channel" = "The gift is now shown in channel's Gifts.";
|
||||
"lng_gift_display_done_hide" = "The gift is now hidden from your profile page.";
|
||||
"lng_gift_display_done_hide_channel" = "The gift is now hidden from channel's Gifts.";
|
||||
"lng_gift_pinned_done_title" = "{gift} pinned";
|
||||
"lng_gift_pinned_done" = "The gift will always be shown on top.";
|
||||
"lng_gift_pinned_done_replaced" = "replacing {gift}";
|
||||
"lng_gift_got_stars#one" = "You got **{count} Star** for this gift.";
|
||||
"lng_gift_got_stars#other" = "You got **{count} Stars** for this gift.";
|
||||
"lng_gift_channel_got#one" = "Channel got **{count} Star** for this gift.";
|
||||
|
@ -3502,6 +3504,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_gift_wear_subscribe" = "Subscribe to {link} to wear collectibles.";
|
||||
"lng_gift_wear_start_toast" = "You put on {name}";
|
||||
"lng_gift_wear_end_toast" = "You took off {name}";
|
||||
"lng_gift_many_pinned_title" = "Too Many Pinned Gifts";
|
||||
"lng_gift_many_pinned_choose" = "Select a gift to unpin below";
|
||||
|
||||
"lng_accounts_limit_title" = "Limit Reached";
|
||||
"lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected account.";
|
||||
|
|
|
@ -883,6 +883,7 @@ std::optional<Data::SavedStarGift> FromTL(
|
|||
unique->exportAt = data.vcan_export_at().value_or_empty();
|
||||
}
|
||||
using Id = Data::SavedStarGiftId;
|
||||
const auto hasUnique = parsed->unique != nullptr;
|
||||
return Data::SavedStarGift{
|
||||
.info = std::move(*parsed),
|
||||
.manageId = (to->isUser()
|
||||
|
@ -905,7 +906,7 @@ std::optional<Data::SavedStarGift> FromTL(
|
|||
.date = data.vdate().v,
|
||||
.upgradable = data.is_can_upgrade(),
|
||||
.anonymous = data.is_name_hidden(),
|
||||
.pinned = data.is_pinned_to_top(),
|
||||
.pinned = data.is_pinned_to_top() && hasUnique,
|
||||
.hidden = data.is_unsaved(),
|
||||
.mine = to->isSelf(),
|
||||
};
|
||||
|
|
|
@ -1725,7 +1725,7 @@ void SendGiftBox(
|
|||
bool sending = false;
|
||||
};
|
||||
const auto state = raw->lifetime().make_state<State>(State{
|
||||
.delegate = Delegate(window, GiftButtonMode::Full),
|
||||
.delegate = Delegate(&window->session(), GiftButtonMode::Full),
|
||||
});
|
||||
const auto single = state->delegate.buttonSize();
|
||||
const auto shadow = st::defaultDropdownMenu.wrap.shadow;
|
||||
|
|
|
@ -479,7 +479,8 @@ ClickHandlerPtr OpenStarGiftLink(not_null<HistoryItem*> item) {
|
|||
Settings::SavedStarGiftBox,
|
||||
window,
|
||||
owner,
|
||||
*parsed));
|
||||
*parsed,
|
||||
nullptr));
|
||||
}
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
|
|
|
@ -7,20 +7,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "info/peer_gifts/info_peer_gifts_common.h"
|
||||
|
||||
#include "boxes/send_credits_box.h" // SetButtonMarkedLabel
|
||||
#include "boxes/star_gift_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "chat_helpers/stickers_gift_box_pack.h"
|
||||
#include "chat_helpers/stickers_lottie.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_credits.h" // CreditsHistoryEntry
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/view/media/history_view_sticker_player.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_credits_graphics.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/dynamic_image.h"
|
||||
#include "ui/dynamic_thumbnails.h"
|
||||
#include "ui/effects/premium_graphics.h"
|
||||
|
@ -240,6 +245,76 @@ void GiftButton::setGeometry(QRect inner, QMargins extend) {
|
|||
AbstractButton::setGeometry(inner.marginsAdded(extend));
|
||||
}
|
||||
|
||||
QMargins GiftButton::currentExtend() const {
|
||||
const auto progress = _selectedAnimation.value(_selected ? 1. : 0.);
|
||||
const auto added = anim::interpolate(0, st::giftBoxSelectSkip, progress);
|
||||
return _extend + QMargins(added, added, added, added);
|
||||
}
|
||||
|
||||
void GiftButton::toggleSelected(bool selected) {
|
||||
if (_selected == selected) {
|
||||
return;
|
||||
}
|
||||
const auto duration = st::defaultRoundCheckbox.duration;
|
||||
_selected = selected;
|
||||
_selectedAnimation.start([=] {
|
||||
update();
|
||||
}, selected ? 0. : 1., selected ? 1. : 0., duration, anim::easeOutCirc);
|
||||
}
|
||||
|
||||
void GiftButton::paintBackground(QPainter &p, const QImage &background) {
|
||||
const auto removed = currentExtend() - _extend;
|
||||
const auto x = removed.left();
|
||||
const auto y = removed.top();
|
||||
const auto width = this->width() - x - removed.right();
|
||||
const auto height = this->height() - y - removed.bottom();
|
||||
const auto dpr = int(background.devicePixelRatio());
|
||||
const auto bwidth = background.width() / dpr;
|
||||
const auto bheight = background.height() / dpr;
|
||||
const auto fillRow = [&](int yfrom, int ytill, int bfrom) {
|
||||
const auto fill = [&](int xto, int wto, int xfrom, int wfrom = 0) {
|
||||
const auto fheight = ytill - yfrom;
|
||||
p.drawImage(
|
||||
QRect(x + xto, y + yfrom, wto, fheight),
|
||||
background,
|
||||
QRect(
|
||||
QPoint(xfrom, bfrom) * dpr,
|
||||
QSize((wfrom ? wfrom : wto), fheight) * dpr));
|
||||
};
|
||||
if (width < bwidth) {
|
||||
const auto xhalf = width / 2;
|
||||
fill(0, xhalf, 0);
|
||||
fill(xhalf, width - xhalf, bwidth - (width - xhalf));
|
||||
} else if (width == bwidth) {
|
||||
fill(0, width, 0);
|
||||
} else {
|
||||
const auto half = bwidth / (2 * dpr);
|
||||
fill(0, half, 0);
|
||||
fill(width - half, half, bwidth - half);
|
||||
fill(half, width - 2 * half, half, 1);
|
||||
}
|
||||
};
|
||||
if (height < bheight) {
|
||||
fillRow(0, height / 2, 0);
|
||||
fillRow(height / 2, height, bheight - (height - (height / 2)));
|
||||
} else {
|
||||
fillRow(0, height, 0);
|
||||
}
|
||||
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
const auto progress = _selectedAnimation.value(_selected ? 1. : 0.);
|
||||
const auto pwidth = progress * st::defaultRoundCheckbox.width;
|
||||
p.setPen(QPen(st::defaultRoundCheckbox.bgActive->c, pwidth));
|
||||
p.setBrush(Qt::NoBrush);
|
||||
const auto rounded = rect().marginsRemoved(_extend);
|
||||
const auto phalf = pwidth / 2.;
|
||||
const auto extended = QRectF(rounded).marginsRemoved(
|
||||
{ phalf, phalf, phalf, phalf });
|
||||
const auto xradius = removed.left() + st::giftBoxGiftRadius - phalf;
|
||||
const auto yradius = removed.top() + st::giftBoxGiftRadius - phalf;
|
||||
p.drawRoundedRect(extended, xradius, yradius);
|
||||
}
|
||||
|
||||
void GiftButton::resizeEvent(QResizeEvent *e) {
|
||||
if (!_button.isEmpty()) {
|
||||
_button.moveLeft((width() - _button.width()) / 2);
|
||||
|
@ -267,9 +342,10 @@ void GiftButton::cacheUniqueBackground(
|
|||
[[maybe_unused]] const auto preload = _uniquePatternEmoji->ready();
|
||||
}
|
||||
const auto outer = QRect(0, 0, width, height);
|
||||
const auto extend = currentExtend();
|
||||
const auto inner = outer.marginsRemoved(
|
||||
_extend
|
||||
).translated(-_extend.left(), -_extend.top());
|
||||
extend
|
||||
).translated(-extend.left(), -extend.top());
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
if (_uniqueBackgroundCache.size() != inner.size() * ratio) {
|
||||
_uniqueBackgroundCache = QImage(
|
||||
|
@ -313,32 +389,15 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
: nullptr;
|
||||
const auto hidden = v::is<GiftTypeStars>(_descriptor)
|
||||
&& v::get<GiftTypeStars>(_descriptor).hidden;;
|
||||
const auto position = QPoint(_extend.left(), _extend.top());
|
||||
const auto extend = currentExtend();
|
||||
const auto position = QPoint(extend.left(), extend.top());
|
||||
const auto background = _delegate->background();
|
||||
const auto dpr = int(background.devicePixelRatio());
|
||||
const auto width = this->width();
|
||||
if (width * dpr <= background.width()) {
|
||||
p.drawImage(0, 0, background);
|
||||
} else {
|
||||
const auto full = background.width();
|
||||
const auto half = ((full / 2) / dpr) * dpr;
|
||||
const auto height = background.height();
|
||||
p.drawImage(
|
||||
QRect(0, 0, half / dpr, height / dpr),
|
||||
background,
|
||||
QRect(0, 0, half, height));
|
||||
p.drawImage(
|
||||
QRect(width - (half / dpr), 0, half / dpr, height / dpr),
|
||||
background,
|
||||
QRect(full - half, 0, half, height));
|
||||
p.drawImage(
|
||||
QRect(half / dpr, 0, width - 2 * (half / dpr), height / dpr),
|
||||
background,
|
||||
QRect(half, 0, 1, height));
|
||||
}
|
||||
const auto dpr = int(background.devicePixelRatio());
|
||||
paintBackground(p, background);
|
||||
if (unique) {
|
||||
cacheUniqueBackground(unique, width, background.height() / dpr);
|
||||
p.drawImage(_extend.left(), _extend.top(), _uniqueBackgroundCache);
|
||||
p.drawImage(extend.left(), extend.top(), _uniqueBackgroundCache);
|
||||
}
|
||||
|
||||
if (_userpic) {
|
||||
|
@ -348,7 +407,7 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
const auto image = _userpic->image(st::giftBoxUserpicSize);
|
||||
const auto skip = st::giftBoxUserpicSkip;
|
||||
p.drawImage(_extend.left() + skip, _extend.top() + skip, image);
|
||||
p.drawImage(extend.left() + skip, extend.top() + skip, image);
|
||||
}
|
||||
|
||||
auto frame = QImage();
|
||||
|
@ -401,7 +460,7 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
const auto premium = v::is<GiftTypePremium>(_descriptor);
|
||||
const auto singlew = width - _extend.left() - _extend.right();
|
||||
const auto singlew = width - extend.left() - extend.right();
|
||||
const auto font = st::semiboldFont;
|
||||
p.setFont(font);
|
||||
|
||||
|
@ -420,11 +479,17 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
return GiftBadge();
|
||||
}, [&](const GiftTypeStars &data) {
|
||||
if (const auto count = data.info.limitedCount) {
|
||||
const auto soldOut = !data.userpic && !data.info.limitedLeft;
|
||||
const auto count = data.info.limitedCount;
|
||||
const auto pinned = data.pinned || data.pinnedSelection;
|
||||
if (count || pinned) {
|
||||
const auto soldOut = !pinned
|
||||
&& !data.userpic
|
||||
&& !data.info.limitedLeft;
|
||||
return GiftBadge{
|
||||
.text = (soldOut
|
||||
? tr::lng_gift_stars_sold_out(tr::now)
|
||||
: (unique && pinned)
|
||||
? ('#' + QString::number(unique->number))
|
||||
: (!data.userpic && !data.info.unique)
|
||||
? tr::lng_gift_stars_limited(tr::now)
|
||||
: (count == 1)
|
||||
|
@ -452,7 +517,7 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
|
||||
if (badge) {
|
||||
const auto rubberOut = st::lineWidth;
|
||||
const auto inner = rect().marginsRemoved(_extend);
|
||||
const auto inner = rect().marginsRemoved(extend);
|
||||
p.setClipRect(inner.marginsAdded(
|
||||
{ rubberOut, rubberOut, rubberOut, rubberOut }));
|
||||
|
||||
|
@ -474,7 +539,7 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(unique->backdrop.patternColor);
|
||||
const auto rect = QRect(
|
||||
QPoint(_extend.left() + skip, _extend.top() + skip),
|
||||
QPoint(extend.left() + skip, extend.top() + skip),
|
||||
QSize(icon.width() + 2 * add, icon.height() + 2 * add));
|
||||
p.drawEllipse(rect);
|
||||
icon.paintInCenter(p, rect);
|
||||
|
@ -547,12 +612,10 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
Delegate::Delegate(
|
||||
not_null<Window::SessionController*> window,
|
||||
GiftButtonMode mode)
|
||||
: _window(window)
|
||||
Delegate::Delegate(not_null<Main::Session*> session, GiftButtonMode mode)
|
||||
: _session(session)
|
||||
, _hiddenMark(std::make_unique<StickerPremiumMark>(
|
||||
&window->session(),
|
||||
_session,
|
||||
st::giftBoxHiddenMark,
|
||||
RectPart::Center))
|
||||
, _mode(mode) {
|
||||
|
@ -563,18 +626,17 @@ Delegate::Delegate(Delegate &&other) = default;
|
|||
Delegate::~Delegate() = default;
|
||||
|
||||
TextWithEntities Delegate::star() {
|
||||
const auto owner = &_window->session().data();
|
||||
return owner->customEmojiManager().creditsEmoji();
|
||||
return _session->data().customEmojiManager().creditsEmoji();
|
||||
}
|
||||
|
||||
TextWithEntities Delegate::ministar() {
|
||||
const auto owner = &_window->session().data();
|
||||
const auto owner = &_session->data();
|
||||
const auto top = st::giftBoxByStarsStarTop;
|
||||
return owner->customEmojiManager().ministarEmoji({ 0, top, 0, 0 });
|
||||
}
|
||||
|
||||
Ui::Text::MarkedContext Delegate::textContext() {
|
||||
return Core::TextContext({ .session = &_window->session() });
|
||||
return Core::TextContext({ .session = _session });
|
||||
}
|
||||
|
||||
QSize Delegate::buttonSize() {
|
||||
|
@ -601,7 +663,7 @@ auto Delegate::buttonPatternEmoji(
|
|||
not_null<Data::UniqueGift*> unique,
|
||||
Fn<void()> repaint)
|
||||
-> std::unique_ptr<Ui::Text::CustomEmoji> {
|
||||
return _window->session().data().customEmojiManager().create(
|
||||
return _session->data().customEmojiManager().create(
|
||||
unique->pattern.document,
|
||||
repaint,
|
||||
Data::CustomEmojiSizeTag::Large);
|
||||
|
@ -658,7 +720,7 @@ QImage Delegate::background() {
|
|||
|
||||
rpl::producer<not_null<DocumentData*>> Delegate::sticker(
|
||||
const GiftDescriptor &descriptor) {
|
||||
return GiftStickerValue(&_window->session(), descriptor);
|
||||
return GiftStickerValue(_session, descriptor);
|
||||
}
|
||||
|
||||
not_null<StickerPremiumMark*> Delegate::hiddenMark() {
|
||||
|
@ -784,4 +846,143 @@ QImage ValidateRotatedBadge(const GiftBadge &badge, int added) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void SelectGiftToUnpin(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
const std::vector<Data::CreditsHistoryEntry> &pinned,
|
||||
Fn<void(Data::SavedStarGiftId)> chosen) {
|
||||
show->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
struct State {
|
||||
explicit State(not_null<Main::Session*> session)
|
||||
: delegate(session, GiftButtonMode::Minimal) {
|
||||
}
|
||||
|
||||
Delegate delegate;
|
||||
rpl::variable<int> selected = -1;
|
||||
std::vector<not_null<GiftButton*>> buttons;
|
||||
};
|
||||
const auto session = &show->session();
|
||||
const auto state = box->lifetime().make_state<State>(session);
|
||||
|
||||
box->setStyle(st::giftTooManyPinnedBox);
|
||||
box->setWidth(st::boxWideWidth);
|
||||
|
||||
box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_gift_many_pinned_title(),
|
||||
st::giftBoxSubtitle),
|
||||
st::giftBoxSubtitleMargin);
|
||||
box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_gift_many_pinned_choose(),
|
||||
st::giftTooManyPinnedChoose),
|
||||
st::giftBoxAboutMargin);
|
||||
|
||||
const auto gifts = box->addRow(
|
||||
object_ptr<Ui::RpWidget>(box),
|
||||
QMargins(
|
||||
st::giftBoxPadding.left(),
|
||||
st::giftTooManyPinnedBox.buttonPadding.top(),
|
||||
st::giftBoxPadding.right(),
|
||||
0));
|
||||
for (const auto &entry : pinned) {
|
||||
const auto index = int(state->buttons.size());
|
||||
state->buttons.push_back(
|
||||
Ui::CreateChild<GiftButton>(gifts, &state->delegate));
|
||||
const auto button = state->buttons.back();
|
||||
button->setDescriptor(GiftTypeStars{
|
||||
.info = {
|
||||
.id = entry.stargiftId,
|
||||
.unique = entry.uniqueGift,
|
||||
.document = entry.uniqueGift->model.document,
|
||||
},
|
||||
.pinnedSelection = true,
|
||||
}, GiftButton::Mode::Minimal);
|
||||
button->setClickedCallback([=] {
|
||||
const auto now = state->selected.current();
|
||||
state->selected = (now == index) ? -1 : index;
|
||||
});
|
||||
}
|
||||
|
||||
state->selected.value(
|
||||
) | rpl::combine_previous(
|
||||
) | rpl::start_with_next([=](int old, int now) {
|
||||
if (old >= 0) state->buttons[old]->toggleSelected(false);
|
||||
if (now >= 0) state->buttons[now]->toggleSelected(true);
|
||||
}, gifts->lifetime());
|
||||
|
||||
gifts->widthValue() | rpl::start_with_next([=](int width) {
|
||||
const auto singleMin = state->delegate.buttonSize();
|
||||
if (width < singleMin.width()) {
|
||||
return;
|
||||
}
|
||||
const auto count = int(state->buttons.size());
|
||||
const auto skipw = st::giftBoxGiftSkip.x();
|
||||
const auto skiph = st::giftBoxGiftSkip.y();
|
||||
const auto perRow = std::min(
|
||||
(width + skipw) / (singleMin.width() + skipw),
|
||||
std::max(count, 1));
|
||||
if (perRow <= 0) {
|
||||
return;
|
||||
}
|
||||
const auto single = (width - (perRow - 1) * skipw) / perRow;
|
||||
const auto height = singleMin.height();
|
||||
const auto rows = (count + perRow - 1) / perRow;
|
||||
for (auto row = 0; row != rows; ++row) {
|
||||
const auto y = row * (height + skiph);
|
||||
for (auto column = 0; column != perRow; ++column) {
|
||||
const auto index = row * perRow + column;
|
||||
if (index >= count) {
|
||||
break;
|
||||
}
|
||||
const auto &button = state->buttons[index];
|
||||
const auto x = column * (single + skipw);
|
||||
button->setGeometry(
|
||||
QRect(x, y, single, height),
|
||||
state->delegate.buttonExtend());
|
||||
}
|
||||
}
|
||||
gifts->resize(width, rows * (height + skiph) - skiph);
|
||||
}, gifts->lifetime());
|
||||
|
||||
const auto button = box->addButton(rpl::single(QString()), [=] {
|
||||
const auto index = state->selected.current();
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
Assert(index < int(pinned.size()));
|
||||
const auto &entry = pinned[index];
|
||||
const auto weak = Ui::MakeWeak(box);
|
||||
chosen(::Settings::EntryToSavedStarGiftId(session, entry));
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
});
|
||||
const auto label = Ui::SetButtonMarkedLabel(
|
||||
button,
|
||||
tr::lng_context_unpin_from_top(Ui::Text::WithEntities),
|
||||
&show->session(),
|
||||
st::creditsBoxButtonLabel,
|
||||
&st::giftTooManyPinnedBox.button.textFg);
|
||||
|
||||
state->selected.value() | rpl::start_with_next([=](int value) {
|
||||
const auto has = (value >= 0);
|
||||
label->setOpacity(has ? 1. : 0.5);
|
||||
button->setAttribute(Qt::WA_TransparentForMouseEvents, !has);
|
||||
}, box->lifetime());
|
||||
|
||||
const auto buttonPadding = st::giftTooManyPinnedBox.buttonPadding;
|
||||
const auto buttonWidth = st::boxWideWidth
|
||||
- buttonPadding.left()
|
||||
- buttonPadding.right();
|
||||
button->resizeToWidth(buttonWidth);
|
||||
button->widthValue() | rpl::start_with_next([=](int width) {
|
||||
if (width != buttonWidth) {
|
||||
button->resizeToWidth(buttonWidth);
|
||||
}
|
||||
}, button->lifetime());
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace Info::PeerGifts
|
||||
|
|
|
@ -15,8 +15,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
class StickerPremiumMark;
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Data {
|
||||
struct UniqueGift;
|
||||
struct CreditsHistoryEntry;
|
||||
class SavedStarGiftId;
|
||||
} // namespace Data
|
||||
|
||||
namespace HistoryView {
|
||||
|
@ -57,10 +63,11 @@ struct GiftTypeStars {
|
|||
Data::StarGift info;
|
||||
PeerData *from = nullptr;
|
||||
TimeId date = 0;
|
||||
bool userpic = false;
|
||||
bool pinned = false;
|
||||
bool hidden = false;
|
||||
bool mine = false;
|
||||
bool pinnedSelection : 1 = false;
|
||||
bool userpic : 1 = false;
|
||||
bool pinned : 1 = false;
|
||||
bool hidden : 1 = false;
|
||||
bool mine : 1 = false;
|
||||
|
||||
[[nodiscard]] friend inline bool operator==(
|
||||
const GiftTypeStars&,
|
||||
|
@ -128,6 +135,8 @@ public:
|
|||
void setDescriptor(const GiftDescriptor &descriptor, Mode mode);
|
||||
void setGeometry(QRect inner, QMargins extend);
|
||||
|
||||
void toggleSelected(bool selected);
|
||||
|
||||
[[nodiscard]] rpl::producer<QPoint> contextMenuRequests() const {
|
||||
return _contextMenuRequests.events();
|
||||
}
|
||||
|
@ -137,6 +146,7 @@ private:
|
|||
void resizeEvent(QResizeEvent *e) override;
|
||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||
|
||||
void paintBackground(QPainter &p, const QImage &background);
|
||||
void cacheUniqueBackground(
|
||||
not_null<Data::UniqueGift*> unique,
|
||||
int width,
|
||||
|
@ -144,6 +154,7 @@ private:
|
|||
|
||||
void setDocument(not_null<DocumentData*> document);
|
||||
[[nodiscard]] bool documentResolved() const;
|
||||
[[nodiscard]] QMargins currentExtend() const;
|
||||
|
||||
void unsubscribe();
|
||||
|
||||
|
@ -159,8 +170,10 @@ private:
|
|||
std::unique_ptr<Ui::Text::CustomEmoji> _uniquePatternEmoji;
|
||||
base::flat_map<float64, QImage> _uniquePatternCache;
|
||||
std::optional<Ui::Premium::ColoredMiniStars> _stars;
|
||||
Ui::Animations::Simple _selectedAnimation;
|
||||
bool _subscribed = false;
|
||||
bool _patterned = false;
|
||||
bool _selected = false;
|
||||
bool _small = false;
|
||||
|
||||
QRect _button;
|
||||
|
@ -173,9 +186,7 @@ private:
|
|||
|
||||
class Delegate final : public GiftButtonDelegate {
|
||||
public:
|
||||
Delegate(
|
||||
not_null<Window::SessionController*> window,
|
||||
GiftButtonMode mode);
|
||||
Delegate(not_null<Main::Session*> session, GiftButtonMode mode);
|
||||
Delegate(Delegate &&other);
|
||||
~Delegate();
|
||||
|
||||
|
@ -195,7 +206,7 @@ public:
|
|||
QImage cachedBadge(const GiftBadge &badge) override;
|
||||
|
||||
private:
|
||||
const not_null<Window::SessionController*> _window;
|
||||
const not_null<Main::Session*> _session;
|
||||
std::unique_ptr<StickerPremiumMark> _hiddenMark;
|
||||
base::flat_map<GiftBadge, QImage> _badges;
|
||||
QSize _single;
|
||||
|
@ -214,4 +225,9 @@ private:
|
|||
|
||||
[[nodiscard]] QImage ValidateRotatedBadge(const GiftBadge &badge, int added);
|
||||
|
||||
void SelectGiftToUnpin(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
const std::vector<Data::CreditsHistoryEntry> &pinned,
|
||||
Fn<void(Data::SavedStarGiftId)> chosen);
|
||||
|
||||
} // namespace Info::PeerGifts
|
||||
|
|
|
@ -112,6 +112,9 @@ private:
|
|||
|
||||
int resizeGetHeight(int width) override;
|
||||
|
||||
[[nodiscard]] auto pinnedSavedGifts()
|
||||
-> Fn<std::vector<Data::CreditsHistoryEntry>()>;
|
||||
|
||||
const not_null<Window::SessionController*> _window;
|
||||
rpl::variable<Filter> _filter;
|
||||
Delegate _delegate;
|
||||
|
@ -152,7 +155,7 @@ InnerWidget::InnerWidget(
|
|||
: BoxContentDivider(parent)
|
||||
, _window(controller->parentController())
|
||||
, _filter(std::move(filter))
|
||||
, _delegate(_window, GiftButtonMode::Minimal)
|
||||
, _delegate(&_window->session(), GiftButtonMode::Minimal)
|
||||
, _controller(controller)
|
||||
, _peer(peer)
|
||||
, _totalCount(_peer->peerGiftsCount())
|
||||
|
@ -225,6 +228,9 @@ void InnerWidget::subscribeToUpdates() {
|
|||
return;
|
||||
}
|
||||
refreshButtons();
|
||||
if (update.action == Action::Pin) {
|
||||
_scrollToTop.fire({});
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
|
@ -476,6 +482,41 @@ void InnerWidget::validateButtons() {
|
|||
std::swap(_views, views);
|
||||
}
|
||||
|
||||
auto InnerWidget::pinnedSavedGifts()
|
||||
-> Fn<std::vector<Data::CreditsHistoryEntry>()> {
|
||||
struct Entry {
|
||||
Data::SavedStarGiftId id;
|
||||
std::shared_ptr<Data::UniqueGift> unique;
|
||||
};
|
||||
auto entries = std::vector<Entry>();
|
||||
for (const auto &entry : _entries) {
|
||||
if (entry.gift.pinned) {
|
||||
Assert(entry.gift.info.unique != nullptr);
|
||||
entries.push_back({
|
||||
entry.gift.manageId,
|
||||
entry.gift.info.unique,
|
||||
});
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [entries] {
|
||||
auto result = std::vector<Data::CreditsHistoryEntry>();
|
||||
result.reserve(entries.size());
|
||||
for (const auto &entry : entries) {
|
||||
const auto &id = entry.id;
|
||||
result.push_back({
|
||||
.bareMsgId = uint64(id.userMessageId().bare),
|
||||
.bareEntryOwnerId = id.chat() ? id.chat()->id.value : 0,
|
||||
.giftChannelSavedId = id.chatSavedId(),
|
||||
.uniqueGift = entry.unique,
|
||||
.stargift = true,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
void InnerWidget::showMenuFor(not_null<GiftButton*> button, QPoint point) {
|
||||
if (_menu) {
|
||||
return;
|
||||
|
@ -495,27 +536,7 @@ void InnerWidget::showMenuFor(not_null<GiftButton*> button, QPoint point) {
|
|||
auto entry = ::Settings::SavedStarGiftEntry(
|
||||
_peer,
|
||||
_entries[index].gift);
|
||||
auto pinnedIds = std::vector<Data::SavedStarGiftId>();
|
||||
for (const auto &entry : _entries) {
|
||||
if (entry.gift.pinned) {
|
||||
pinnedIds.push_back(entry.gift.manageId);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
entry.pinnedSavedGifts = [pinnedIds] {
|
||||
auto result = std::vector<Data::CreditsHistoryEntry>();
|
||||
result.reserve(pinnedIds.size());
|
||||
for (const auto &id : pinnedIds) {
|
||||
result.push_back({
|
||||
.bareMsgId = uint64(id.userMessageId().bare),
|
||||
.bareEntryOwnerId = id.chat() ? id.chat()->id.value : 0,
|
||||
.giftChannelSavedId = id.chatSavedId(),
|
||||
.stargift = true,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
entry.pinnedSavedGifts = pinnedSavedGifts();
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(this, st::popupMenuWithIcons);
|
||||
::Settings::FillSavedStarGiftMenu(
|
||||
_controller->uiShow(),
|
||||
|
@ -535,7 +556,8 @@ void InnerWidget::showGift(int index) {
|
|||
::Settings::SavedStarGiftBox,
|
||||
_window,
|
||||
_peer,
|
||||
_entries[index].gift));
|
||||
_entries[index].gift,
|
||||
pinnedSavedGifts()));
|
||||
}
|
||||
|
||||
void InnerWidget::refreshAbout() {
|
||||
|
|
|
@ -43,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "info/bot/starref/info_bot_starref_common.h"
|
||||
#include "info/channel_statistics/boosts/giveaway/boost_badge.h" // InfiniteRadialAnimationWidget.
|
||||
#include "info/channel_statistics/earn/info_channel_earn_widget.h" // Info::ChannelEarn::Make.
|
||||
#include "info/peer_gifts/info_peer_gifts_common.h"
|
||||
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
|
||||
#include "info/statistics/info_statistics_list_controllers.h"
|
||||
#include "info/info_controller.h"
|
||||
|
@ -173,18 +174,6 @@ private:
|
|||
|
||||
};
|
||||
|
||||
[[nodiscard]] Data::SavedStarGiftId EntryToSavedStarGiftId(
|
||||
not_null<Main::Session*> session,
|
||||
const Data::CreditsHistoryEntry &entry) {
|
||||
return !entry.stargift
|
||||
? Data::SavedStarGiftId()
|
||||
: (entry.bareEntryOwnerId && entry.giftChannelSavedId)
|
||||
? Data::SavedStarGiftId::Chat(
|
||||
session->data().peer(PeerId(entry.bareEntryOwnerId)),
|
||||
entry.giftChannelSavedId)
|
||||
: Data::SavedStarGiftId::User(MsgId(entry.bareMsgId));
|
||||
}
|
||||
|
||||
void ToggleStarGiftSaved(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
Data::SavedStarGiftId savedId,
|
||||
|
@ -226,7 +215,8 @@ void ToggleStarGiftPinned(
|
|||
Data::SavedStarGiftId savedId,
|
||||
std::vector<Data::SavedStarGiftId> already,
|
||||
bool pinned,
|
||||
Fn<void(bool)> done = nullptr) {
|
||||
std::shared_ptr<Data::UniqueGift> uniqueData = nullptr,
|
||||
std::shared_ptr<Data::UniqueGift> replacingData = nullptr) {
|
||||
already.erase(ranges::remove(already, savedId), end(already));
|
||||
if (pinned) {
|
||||
already.insert(begin(already), savedId);
|
||||
|
@ -256,16 +246,29 @@ void ToggleStarGiftPinned(
|
|||
.action = (pinned ? GiftAction::Pin : GiftAction::Unpin),
|
||||
});
|
||||
|
||||
if (const auto onstack = done) {
|
||||
onstack(true);
|
||||
}
|
||||
if (pinned) {
|
||||
show->showToast(tr::lng_gift_pinned_done(tr::now));
|
||||
show->showToast({
|
||||
.title = (uniqueData
|
||||
? tr::lng_gift_pinned_done_title(
|
||||
tr::now,
|
||||
lt_gift,
|
||||
Data::UniqueGiftName(*uniqueData))
|
||||
: QString()),
|
||||
.text = (replacingData
|
||||
? tr::lng_gift_pinned_done_replaced(
|
||||
tr::now,
|
||||
lt_gift,
|
||||
TextWithEntities{
|
||||
Data::UniqueGiftName(*replacingData),
|
||||
},
|
||||
Ui::Text::WithEntities)
|
||||
: tr::lng_gift_pinned_done(
|
||||
tr::now,
|
||||
Ui::Text::WithEntities)),
|
||||
.duration = Ui::Toast::kDefaultDuration * 2,
|
||||
});
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (const auto onstack = done) {
|
||||
onstack(false);
|
||||
}
|
||||
show->showToast(error.type());
|
||||
}).send();
|
||||
}
|
||||
|
@ -920,25 +923,61 @@ void FillUniqueGiftMenu(
|
|||
if (unique
|
||||
&& canToggle
|
||||
&& e.savedToProfile
|
||||
&& type == SavedStarGiftMenuType::List) {
|
||||
const auto already = [session, entries = e.pinnedSavedGifts] {
|
||||
Expects(entries != nullptr);
|
||||
|
||||
auto list = entries();
|
||||
&& e.pinnedSavedGifts) {
|
||||
const auto pinned = e.pinnedSavedGifts;
|
||||
const auto ids = [session](
|
||||
const std::vector<Data::CreditsHistoryEntry> &pinned) {
|
||||
auto result = std::vector<Data::SavedStarGiftId>();
|
||||
result.reserve(list.size());
|
||||
for (const auto &entry : list) {
|
||||
result.reserve(pinned.size());
|
||||
for (const auto &entry : pinned) {
|
||||
result.push_back(EntryToSavedStarGiftId(session, entry));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
if (e.giftPinned) {
|
||||
menu->addAction(tr::lng_context_unpin_from_top(tr::now), [=] {
|
||||
ToggleStarGiftPinned(show, savedId, already(), false);
|
||||
ToggleStarGiftPinned(show, savedId, ids(pinned()), false);
|
||||
}, st.unpin ? st.unpin : &st::menuIconUnpin);
|
||||
} else {
|
||||
menu->addAction(tr::lng_context_pin_to_top(tr::now), [=] {
|
||||
ToggleStarGiftPinned(show, savedId, already(), true);
|
||||
const auto list = pinned();
|
||||
const auto &appConfig = show->session().appConfig();
|
||||
const auto limit = appConfig.pinnedGiftsLimit();
|
||||
auto already = ids(list);
|
||||
if (list.size() >= limit) {
|
||||
Info::PeerGifts::SelectGiftToUnpin(show, list, [=](
|
||||
Data::SavedStarGiftId id) {
|
||||
auto copy = already;
|
||||
const auto i = ranges::find(copy, id);
|
||||
const auto replaced = (i != end(copy))
|
||||
? list[i - begin(copy)].uniqueGift
|
||||
: nullptr;
|
||||
if (i != end(copy)) {
|
||||
copy.erase(i);
|
||||
}
|
||||
|
||||
using GiftAction = Data::GiftUpdate::Action;
|
||||
show->session().data().notifyGiftUpdate({
|
||||
.id = id,
|
||||
.action = GiftAction::Unpin,
|
||||
});
|
||||
|
||||
ToggleStarGiftPinned(
|
||||
show,
|
||||
savedId,
|
||||
already,
|
||||
true,
|
||||
unique,
|
||||
replaced);
|
||||
});
|
||||
} else {
|
||||
ToggleStarGiftPinned(
|
||||
show,
|
||||
savedId,
|
||||
already,
|
||||
true,
|
||||
unique);
|
||||
}
|
||||
}, st.pin ? st.pin : &st::menuIconPin);
|
||||
}
|
||||
}
|
||||
|
@ -2031,15 +2070,30 @@ Data::CreditsHistoryEntry SavedStarGiftEntry(
|
|||
};
|
||||
}
|
||||
|
||||
Data::SavedStarGiftId EntryToSavedStarGiftId(
|
||||
not_null<Main::Session*> session,
|
||||
const Data::CreditsHistoryEntry &entry) {
|
||||
return !entry.stargift
|
||||
? Data::SavedStarGiftId()
|
||||
: (entry.bareEntryOwnerId && entry.giftChannelSavedId)
|
||||
? Data::SavedStarGiftId::Chat(
|
||||
session->data().peer(PeerId(entry.bareEntryOwnerId)),
|
||||
entry.giftChannelSavedId)
|
||||
: Data::SavedStarGiftId::User(MsgId(entry.bareMsgId));
|
||||
}
|
||||
|
||||
void SavedStarGiftBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> owner,
|
||||
const Data::SavedStarGift &data) {
|
||||
const Data::SavedStarGift &data,
|
||||
Fn<std::vector<Data::CreditsHistoryEntry>()> pinned) {
|
||||
auto entry = SavedStarGiftEntry(owner, data);
|
||||
entry.pinnedSavedGifts = std::move(pinned);
|
||||
Settings::ReceiptCreditsBox(
|
||||
box,
|
||||
controller,
|
||||
SavedStarGiftEntry(owner, data),
|
||||
std::move(entry),
|
||||
Data::SubscriptionEntry());
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ struct SubscriptionEntry;
|
|||
struct GiftCode;
|
||||
struct CreditTopupOption;
|
||||
struct SavedStarGift;
|
||||
class SavedStarGiftId;
|
||||
struct StarGift;
|
||||
} // namespace Data
|
||||
|
||||
|
@ -158,11 +159,15 @@ void GlobalStarGiftBox(
|
|||
[[nodiscard]] Data::CreditsHistoryEntry SavedStarGiftEntry(
|
||||
not_null<PeerData*> owner,
|
||||
const Data::SavedStarGift &data);
|
||||
[[nodiscard]] Data::SavedStarGiftId EntryToSavedStarGiftId(
|
||||
not_null<Main::Session*> session,
|
||||
const Data::CreditsHistoryEntry &entry);
|
||||
void SavedStarGiftBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> owner,
|
||||
const Data::SavedStarGift &data);
|
||||
const Data::SavedStarGift &data,
|
||||
Fn<std::vector<Data::CreditsHistoryEntry>()> pinned = nullptr);
|
||||
enum class SavedStarGiftMenuType {
|
||||
List,
|
||||
View,
|
||||
|
|
|
@ -149,6 +149,7 @@ giftBoxStickerStarTop: 24px;
|
|||
giftBoxSmallStickerTop: 16px;
|
||||
giftBoxStickerTopByStars: -4px;
|
||||
giftBoxStickerSize: size(80px, 80px);
|
||||
giftBoxSelectSkip: 5px;
|
||||
giftBoxUserpicSize: 24px;
|
||||
giftBoxUserpicSkip: 2px;
|
||||
giftBoxTextField: InputField(defaultInputField) {
|
||||
|
@ -256,3 +257,10 @@ darkUpgradeGiftInfoTitle: FlatLabel(defaultFlatLabel) {
|
|||
darkUpgradeGiftInfoAbout: FlatLabel(upgradeGiftSubtext) {
|
||||
textFg: groupCallMemberNotJoinedStatus;
|
||||
}
|
||||
|
||||
giftTooManyPinnedBox: Box(giftBox) {
|
||||
buttonPadding: margins(11px, 11px, 11px, 11px);
|
||||
}
|
||||
giftTooManyPinnedChoose: FlatLabel(giftBoxAbout) {
|
||||
textFg: windowSubTextFg;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue