| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- /*
- 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
- */
- #include "info/peer_gifts/info_peer_gifts_widget.h"
- #include "api/api_premium.h"
- #include "apiwrap.h"
- #include "data/data_channel.h"
- #include "data/data_credits.h"
- #include "data/data_session.h"
- #include "data/data_user.h"
- #include "info/peer_gifts/info_peer_gifts_common.h"
- #include "info/info_controller.h"
- #include "ui/layers/generic_box.h"
- #include "ui/text/text_utilities.h"
- #include "ui/widgets/menu/menu_add_action_callback.h"
- #include "ui/widgets/box_content_divider.h"
- #include "ui/widgets/checkbox.h"
- #include "ui/widgets/labels.h"
- #include "ui/widgets/popup_menu.h"
- #include "ui/widgets/scroll_area.h"
- #include "ui/wrap/slide_wrap.h"
- #include "ui/ui_utility.h"
- #include "lang/lang_keys.h"
- #include "main/main_app_config.h"
- #include "main/main_session.h"
- #include "mtproto/sender.h"
- #include "window/window_session_controller.h"
- #include "settings/settings_credits_graphics.h"
- #include "styles/style_info.h"
- #include "styles/style_layers.h" // boxRadius
- #include "styles/style_media_player.h" // mediaPlayerMenuCheck
- #include "styles/style_menu_icons.h"
- #include "styles/style_credits.h" // giftBoxPadding
- namespace Info::PeerGifts {
- namespace {
- constexpr auto kPreloadPages = 2;
- constexpr auto kPerPage = 50;
- [[nodiscard]] GiftDescriptor DescriptorForGift(
- not_null<PeerData*> to,
- const Data::SavedStarGift &gift) {
- return GiftTypeStars{
- .info = gift.info,
- .from = ((gift.anonymous || !gift.fromId)
- ? nullptr
- : to->owner().peer(gift.fromId).get()),
- .date = gift.date,
- .userpic = !gift.info.unique,
- .pinned = gift.pinned,
- .hidden = gift.hidden,
- .mine = to->isSelf(),
- };
- }
- } // namespace
- class InnerWidget final : public Ui::BoxContentDivider {
- public:
- InnerWidget(
- QWidget *parent,
- not_null<Controller*> controller,
- not_null<PeerData*> peer,
- rpl::producer<Filter> filter);
- [[nodiscard]] not_null<PeerData*> peer() const {
- return _peer;
- }
- [[nodiscard]] rpl::producer<bool> notifyEnabled() const {
- return _notifyEnabled.events();
- }
- [[nodiscard]] rpl::producer<> scrollToTop() const {
- return _scrollToTop.events();
- }
- void saveState(not_null<Memento*> memento);
- void restoreState(not_null<Memento*> memento);
- private:
- struct Entry {
- Data::SavedStarGift gift;
- GiftDescriptor descriptor;
- };
- struct View {
- std::unique_ptr<GiftButton> button;
- Data::SavedStarGiftId manageId;
- uint64 giftId = 0;
- int index = 0;
- };
- void visibleTopBottomUpdated(
- int visibleTop,
- int visibleBottom) override;
- void paintEvent(QPaintEvent *e) override;
- void subscribeToUpdates();
- void loadMore();
- void refreshButtons();
- void validateButtons();
- void showGift(int index);
- void showMenuFor(not_null<GiftButton*> button, QPoint point);
- void refreshAbout();
- void markPinned(std::vector<Entry>::iterator i);
- void markUnpinned(std::vector<Entry>::iterator i);
- 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;
- not_null<Controller*> _controller;
- std::unique_ptr<Ui::FlatLabel> _about;
- const not_null<PeerData*> _peer;
- std::vector<Entry> _entries;
- int _totalCount = 0;
- rpl::event_stream<> _scrollToTop;
- MTP::Sender _api;
- mtpRequestId _loadMoreRequestId = 0;
- QString _offset;
- bool _allLoaded = false;
- bool _reloading = false;
- rpl::event_stream<bool> _notifyEnabled;
- std::vector<View> _views;
- int _viewsForWidth = 0;
- int _viewsFromRow = 0;
- int _viewsTillRow = 0;
- QSize _singleMin;
- QSize _single;
- int _perRow = 0;
- int _visibleFrom = 0;
- int _visibleTill = 0;
- base::unique_qptr<Ui::PopupMenu> _menu;
- };
- InnerWidget::InnerWidget(
- QWidget *parent,
- not_null<Controller*> controller,
- not_null<PeerData*> peer,
- rpl::producer<Filter> filter)
- : BoxContentDivider(parent)
- , _window(controller->parentController())
- , _filter(std::move(filter))
- , _delegate(&_window->session(), GiftButtonMode::Minimal)
- , _controller(controller)
- , _peer(peer)
- , _totalCount(_peer->peerGiftsCount())
- , _api(&_peer->session().mtp()) {
- _singleMin = _delegate.buttonSize();
- if (peer->canManageGifts()) {
- subscribeToUpdates();
- }
- _filter.value() | rpl::start_with_next([=] {
- _reloading = true;
- _api.request(base::take(_loadMoreRequestId)).cancel();
- _allLoaded = false;
- refreshAbout();
- loadMore();
- }, lifetime());
- }
- void InnerWidget::subscribeToUpdates() {
- _peer->owner().giftUpdates(
- ) | rpl::start_with_next([=](const Data::GiftUpdate &update) {
- const auto savedId = [](const Entry &entry) {
- return entry.gift.manageId;
- };
- const auto i = ranges::find(_entries, update.id, savedId);
- if (i == end(_entries)) {
- return;
- }
- const auto index = int(i - begin(_entries));
- using Action = Data::GiftUpdate::Action;
- if (update.action == Action::Convert
- || update.action == Action::Transfer
- || update.action == Action::Delete) {
- _entries.erase(i);
- if (_totalCount > 0) {
- --_totalCount;
- }
- for (auto &view : _views) {
- if (view.index >= index) {
- --view.index;
- }
- }
- } else if (update.action == Action::Save
- || update.action == Action::Unsave) {
- i->gift.hidden = (update.action == Action::Unsave);
- const auto unpin = i->gift.hidden && i->gift.pinned;
- v::match(i->descriptor, [](GiftTypePremium &) {
- }, [&](GiftTypeStars &data) {
- data.hidden = i->gift.hidden;
- });
- for (auto &view : _views) {
- if (view.index == index) {
- view.index = -1;
- view.manageId = {};
- }
- }
- if (unpin) {
- markUnpinned(i);
- }
- } else if (update.action == Action::Pin
- || update.action == Action::Unpin) {
- if (update.action == Action::Pin) {
- markPinned(i);
- } else {
- markUnpinned(i);
- }
- } else {
- return;
- }
- refreshButtons();
- if (update.action == Action::Pin) {
- _scrollToTop.fire({});
- }
- }, lifetime());
- }
- void InnerWidget::markPinned(std::vector<Entry>::iterator i) {
- const auto index = int(i - begin(_entries));
- i->gift.pinned = true;
- v::match(i->descriptor, [](const GiftTypePremium &) {
- }, [&](GiftTypeStars &data) {
- data.pinned = true;
- });
- if (index) {
- std::rotate(begin(_entries), i, i + 1);
- }
- auto unpin = end(_entries);
- const auto session = &_window->session();
- const auto limit = session->appConfig().pinnedGiftsLimit();
- if (limit < _entries.size()) {
- const auto j = begin(_entries) + limit;
- if (j->gift.pinned) {
- unpin = j;
- }
- }
- for (auto &view : _views) {
- if (view.index <= index) {
- view.index = -1;
- view.manageId = {};
- }
- }
- if (unpin != end(_entries)) {
- markUnpinned(unpin);
- }
- }
- void InnerWidget::markUnpinned(std::vector<Entry>::iterator i) {
- const auto index = int(i - begin(_entries));
- i->gift.pinned = false;
- v::match(i->descriptor, [](const GiftTypePremium &) {
- }, [&](GiftTypeStars &data) {
- data.pinned = false;
- });
- auto after = index + 1;
- for (auto j = i + 1; j != end(_entries); ++j) {
- if (!j->gift.pinned && j->gift.date <= i->gift.date) {
- break;
- }
- ++after;
- }
- if (after == _entries.size() && !_allLoaded) {
- // We don't know if the correct position is exactly in the end
- // of the loaded part or later, so we hide it for now, let it
- // be loaded later while scrolling.
- _entries.erase(i);
- } else if (after > index + 1) {
- std::rotate(i, i + 1, begin(_entries) + after);
- }
- for (auto &view : _views) {
- if (view.index >= index) {
- view.index = -1;
- view.manageId = {};
- }
- }
- }
- void InnerWidget::visibleTopBottomUpdated(
- int visibleTop,
- int visibleBottom) {
- const auto page = (visibleBottom - visibleTop);
- if (visibleBottom + page * kPreloadPages >= height()) {
- loadMore();
- }
- _visibleFrom = visibleTop;
- _visibleTill = visibleBottom;
- validateButtons();
- }
- void InnerWidget::paintEvent(QPaintEvent *e) {
- auto p = QPainter(this);
- const auto aboutSize = _about
- ? _about->size().grownBy(st::giftListAboutMargin)
- : QSize();
- const auto skips = QMargins(0, 0, 0, aboutSize.height());
- p.fillRect(rect().marginsRemoved(skips), st::boxDividerBg->c);
- paintTop(p);
- if (const auto bottom = skips.bottom()) {
- paintBottom(p, bottom);
- }
- }
- void InnerWidget::loadMore() {
- if (_allLoaded || _loadMoreRequestId) {
- return;
- }
- using Flag = MTPpayments_GetSavedStarGifts::Flag;
- const auto filter = _filter.current();
- _loadMoreRequestId = _api.request(MTPpayments_GetSavedStarGifts(
- MTP_flags((filter.sortByValue ? Flag::f_sort_by_value : Flag())
- | (filter.skipLimited ? Flag::f_exclude_limited : Flag())
- | (filter.skipUnlimited ? Flag::f_exclude_unlimited : Flag())
- | (filter.skipUnique ? Flag::f_exclude_unique : Flag())
- | (filter.skipSaved ? Flag::f_exclude_saved : Flag())
- | (filter.skipUnsaved ? Flag::f_exclude_unsaved : Flag())),
- _peer->input,
- MTP_string(_reloading ? QString() : _offset),
- MTP_int(kPerPage)
- )).done([=](const MTPpayments_SavedStarGifts &result) {
- _loadMoreRequestId = 0;
- const auto &data = result.data();
- if (const auto enabled = data.vchat_notifications_enabled()) {
- _notifyEnabled.fire(mtpIsTrue(*enabled));
- }
- if (const auto next = data.vnext_offset()) {
- _offset = qs(*next);
- } else {
- _allLoaded = true;
- }
- _totalCount = data.vcount().v;
- const auto owner = &_peer->owner();
- owner->processUsers(data.vusers());
- owner->processChats(data.vchats());
- if (base::take(_reloading)) {
- _entries.clear();
- }
- _entries.reserve(_entries.size() + data.vgifts().v.size());
- for (const auto &gift : data.vgifts().v) {
- if (auto parsed = Api::FromTL(_peer, gift)) {
- auto descriptor = DescriptorForGift(_peer, *parsed);
- _entries.push_back({
- .gift = std::move(*parsed),
- .descriptor = std::move(descriptor),
- });
- }
- }
- refreshButtons();
- refreshAbout();
- }).fail([=] {
- _loadMoreRequestId = 0;
- _allLoaded = true;
- }).send();
- }
- void InnerWidget::refreshButtons() {
- _viewsForWidth = 0;
- _viewsFromRow = 0;
- _viewsTillRow = 0;
- resizeToWidth(width());
- validateButtons();
- }
- void InnerWidget::validateButtons() {
- if (!_perRow) {
- return;
- }
- const auto padding = st::giftBoxPadding;
- const auto vskip = padding.bottom();
- const auto row = _single.height() + st::giftBoxGiftSkip.y();
- const auto fromRow = std::max(_visibleFrom - vskip, 0) / row;
- const auto tillRow = (_visibleTill - vskip + row - 1) / row;
- Assert(tillRow >= fromRow);
- if (_viewsFromRow == fromRow
- && _viewsTillRow == tillRow
- && _viewsForWidth == width()) {
- return;
- }
- _viewsFromRow = fromRow;
- _viewsTillRow = tillRow;
- _viewsForWidth = width();
- const auto available = _viewsForWidth - padding.left() - padding.right();
- const auto skipw = st::giftBoxGiftSkip.x();
- const auto fullw = _perRow * (_single.width() + skipw) - skipw;
- const auto left = padding.left() + (available - fullw) / 2;
- const auto oneh = _single.height() + st::giftBoxGiftSkip.y();
- const auto mode = GiftButton::Mode::Minimal;
- auto x = left;
- auto y = vskip + fromRow * oneh;
- auto views = std::vector<View>();
- views.reserve((tillRow - fromRow) * _perRow);
- const auto idUsed = [&](uint64 giftId, int column, int row) {
- for (auto j = row; j != tillRow; ++j) {
- for (auto i = column; i != _perRow; ++i) {
- const auto index = j * _perRow + i;
- if (index >= _entries.size()) {
- return false;
- } else if (_entries[index].gift.info.id == giftId) {
- return true;
- }
- }
- column = 0;
- }
- return false;
- };
- const auto add = [&](int column, int row) {
- const auto index = row * _perRow + column;
- if (index >= _entries.size()) {
- return false;
- }
- const auto giftId = _entries[index].gift.info.id;
- const auto manageId = _entries[index].gift.manageId;
- const auto &descriptor = _entries[index].descriptor;
- const auto already = ranges::find(_views, giftId, &View::giftId);
- if (already != end(_views)) {
- views.push_back(base::take(*already));
- } else {
- const auto unused = ranges::find_if(_views, [&](const View &v) {
- return v.button && !idUsed(v.giftId, column, row);
- });
- if (unused != end(_views)) {
- views.push_back(base::take(*unused));
- } else {
- auto button = std::make_unique<GiftButton>(this, &_delegate);
- const auto raw = button.get();
- raw->contextMenuRequests(
- ) | rpl::start_with_next([=](QPoint point) {
- showMenuFor(raw, point);
- }, raw->lifetime());
- raw->show();
- views.push_back({ .button = std::move(button) });
- }
- }
- auto &view = views.back();
- const auto callback = [=] {
- showGift(index);
- };
- view.index = index;
- view.manageId = manageId;
- view.giftId = giftId;
- view.button->setDescriptor(descriptor, mode);
- view.button->setClickedCallback(callback);
- return true;
- };
- for (auto j = fromRow; j != tillRow; ++j) {
- for (auto i = 0; i != _perRow; ++i) {
- if (!add(i, j)) {
- break;
- }
- views.back().button->setGeometry(
- QRect(QPoint(x, y), _single),
- _delegate.buttonExtend());
- x += _single.width() + skipw;
- }
- x = left;
- y += oneh;
- }
- 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;
- }
- const auto index = [&] {
- for (const auto &view : _views) {
- if (view.button.get() == button) {
- return view.index;
- }
- }
- return -1;
- }();
- if (index < 0) {
- return;
- }
- auto entry = ::Settings::SavedStarGiftEntry(
- _peer,
- _entries[index].gift);
- entry.pinnedSavedGifts = pinnedSavedGifts();
- _menu = base::make_unique_q<Ui::PopupMenu>(this, st::popupMenuWithIcons);
- ::Settings::FillSavedStarGiftMenu(
- _controller->uiShow(),
- _menu.get(),
- entry,
- ::Settings::SavedStarGiftMenuType::List);
- if (_menu->empty()) {
- return;
- }
- _menu->popup(point);
- }
- void InnerWidget::showGift(int index) {
- Expects(index >= 0 && index < _entries.size());
- _window->show(Box(
- ::Settings::SavedStarGiftBox,
- _window,
- _peer,
- _entries[index].gift,
- pinnedSavedGifts()));
- }
- void InnerWidget::refreshAbout() {
- if (!_peer->isSelf() && _peer->canManageGifts() && !_entries.empty()) {
- if (_about) {
- _about = nullptr;
- resizeToWidth(width());
- }
- } else if (!_about) {
- _about = std::make_unique<Ui::FlatLabel>(
- this,
- (_peer->isSelf()
- ? tr::lng_peer_gifts_about_mine(Ui::Text::RichLangValue)
- : tr::lng_peer_gifts_about(
- lt_user,
- rpl::single(Ui::Text::Bold(_peer->shortName())),
- Ui::Text::RichLangValue)),
- st::giftListAbout);
- _about->show();
- resizeToWidth(width());
- }
- }
- int InnerWidget::resizeGetHeight(int width) {
- const auto count = int(_entries.size());
- const auto padding = st::giftBoxPadding;
- const auto available = width - padding.left() - padding.right();
- const auto skipw = st::giftBoxGiftSkip.x();
- _perRow = std::min(
- (available + skipw) / (_singleMin.width() + skipw),
- std::max(count, 1));
- if (!_perRow) {
- return 0;
- }
- const auto singlew = std::min(
- ((available + skipw) / _perRow) - skipw,
- 2 * _singleMin.width());
- Assert(singlew >= _singleMin.width());
- const auto singleh = _singleMin.height();
- _single = QSize(singlew, singleh);
- const auto rows = (count + _perRow - 1) / _perRow;
- const auto skiph = st::giftBoxGiftSkip.y();
- auto result = rows
- ? (padding.bottom() * 2 + rows * (singleh + skiph) - skiph)
- : 0;
- if (const auto about = _about.get()) {
- const auto margin = st::giftListAboutMargin;
- about->resizeToWidth(width - margin.left() - margin.right());
- about->moveToLeft(margin.left(), result + margin.top());
- result += margin.top() + about->height() + margin.bottom();
- }
- return result;
- }
- void InnerWidget::saveState(not_null<Memento*> memento) {
- auto state = std::make_unique<ListState>();
- memento->setListState(std::move(state));
- }
- void InnerWidget::restoreState(not_null<Memento*> memento) {
- if (const auto state = memento->listState()) {
- }
- }
- Memento::Memento(not_null<PeerData*> peer)
- : ContentMemento(peer, nullptr, PeerId()) {
- }
- Section Memento::section() const {
- return Section(Section::Type::PeerGifts);
- }
- object_ptr<ContentWidget> Memento::createWidget(
- QWidget *parent,
- not_null<Controller*> controller,
- const QRect &geometry) {
- auto result = object_ptr<Widget>(parent, controller, peer());
- result->setInternalState(geometry, this);
- return result;
- }
- void Memento::setListState(std::unique_ptr<ListState> state) {
- _listState = std::move(state);
- }
- std::unique_ptr<ListState> Memento::listState() {
- return std::move(_listState);
- }
- Memento::~Memento() = default;
- Widget::Widget(
- QWidget *parent,
- not_null<Controller*> controller,
- not_null<PeerData*> peer)
- : ContentWidget(parent, controller) {
- _inner = setInnerWidget(
- object_ptr<InnerWidget>(this, controller, peer, _filter.value()));
- _inner->notifyEnabled(
- ) | rpl::take(1) | rpl::start_with_next([=](bool enabled) {
- setupNotifyCheckbox(enabled);
- }, _inner->lifetime());
- _inner->scrollToTop() | rpl::start_with_next([=] {
- scrollTo({ 0, 0 });
- }, _inner->lifetime());
- }
- void Widget::showFinished() {
- _shown = true;
- if (const auto bottom = _pinnedToBottom.data()) {
- bottom->toggle(true, anim::type::normal);
- }
- }
- void Widget::setupNotifyCheckbox(bool enabled) {
- _pinnedToBottom = Ui::CreateChild<Ui::SlideWrap<Ui::RpWidget>>(
- this,
- object_ptr<Ui::RpWidget>(this));
- const auto wrap = _pinnedToBottom.data();
- wrap->toggle(false, anim::type::instant);
- const auto bottom = wrap->entity();
- bottom->show();
- const auto notify = Ui::CreateChild<Ui::Checkbox>(
- bottom,
- tr::lng_peer_gifts_notify(),
- enabled);
- notify->show();
- notify->checkedChanges() | rpl::start_with_next([=](bool checked) {
- const auto api = &controller()->session().api();
- const auto show = controller()->uiShow();
- using Flag = MTPpayments_ToggleChatStarGiftNotifications::Flag;
- api->request(MTPpayments_ToggleChatStarGiftNotifications(
- MTP_flags(checked ? Flag::f_enabled : Flag()),
- _inner->peer()->input
- )).send();
- if (checked) {
- show->showToast(tr::lng_peer_gifts_notify_enabled(tr::now));
- }
- }, notify->lifetime());
- const auto &checkSt = st::defaultCheckbox;
- const auto checkTop = st::boxRadius + checkSt.margin.top();
- bottom->widthValue() | rpl::start_with_next([=](int width) {
- const auto normal = notify->naturalWidth()
- - checkSt.margin.left()
- - checkSt.margin.right();
- notify->resizeToWidth(normal);
- const auto checkLeft = (width - normal) / 2;
- notify->moveToLeft(checkLeft, checkTop);
- }, notify->lifetime());
- notify->heightValue() | rpl::start_with_next([=](int height) {
- bottom->resize(bottom->width(), st::boxRadius + height);
- }, notify->lifetime());
- const auto processHeight = [=] {
- setScrollBottomSkip(wrap->height());
- wrap->moveToLeft(wrap->x(), height() - wrap->height());
- };
- _inner->sizeValue(
- ) | rpl::start_with_next([=](const QSize &s) {
- wrap->resizeToWidth(s.width());
- crl::on_main(wrap, processHeight);
- }, wrap->lifetime());
- rpl::combine(
- wrap->heightValue(),
- heightValue()
- ) | rpl::start_with_next(processHeight, wrap->lifetime());
- if (_shown) {
- wrap->toggle(true, anim::type::normal);
- }
- _hasPinnedToBottom = true;
- }
- void Widget::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
- const auto filter = _filter.current();
- const auto change = [=](Fn<void(Filter&)> update) {
- auto now = _filter.current();
- update(now);
- _filter = now;
- };
- if (filter.sortByValue) {
- addAction(tr::lng_peer_gifts_filter_by_date(tr::now), [=] {
- change([](Filter &filter) { filter.sortByValue = false; });
- }, &st::menuIconSchedule);
- } else {
- addAction(tr::lng_peer_gifts_filter_by_value(tr::now), [=] {
- change([](Filter &filter) { filter.sortByValue = true; });
- }, &st::menuIconEarn);
- }
- addAction({ .isSeparator = true });
- addAction(tr::lng_peer_gifts_filter_unlimited(tr::now), [=] {
- change([](Filter &filter) {
- filter.skipUnlimited = !filter.skipUnlimited;
- if (filter.skipUnlimited
- && filter.skipLimited
- && filter.skipUnique) {
- filter.skipLimited = false;
- }
- });
- }, filter.skipUnlimited ? nullptr : &st::mediaPlayerMenuCheck);
- addAction(tr::lng_peer_gifts_filter_limited(tr::now), [=] {
- change([](Filter &filter) {
- filter.skipLimited = !filter.skipLimited;
- if (filter.skipUnlimited
- && filter.skipLimited
- && filter.skipUnique) {
- filter.skipUnlimited = false;
- }
- });
- }, filter.skipLimited ? nullptr : &st::mediaPlayerMenuCheck);
- addAction(tr::lng_peer_gifts_filter_unique(tr::now), [=] {
- change([](Filter &filter) {
- filter.skipUnique = !filter.skipUnique;
- if (filter.skipUnlimited
- && filter.skipLimited
- && filter.skipUnique) {
- filter.skipUnlimited = false;
- }
- });
- }, filter.skipUnique ? nullptr : &st::mediaPlayerMenuCheck);
- if (_inner->peer()->canManageGifts()) {
- addAction({ .isSeparator = true });
- addAction(tr::lng_peer_gifts_filter_saved(tr::now), [=] {
- change([](Filter &filter) {
- filter.skipSaved = !filter.skipSaved;
- if (filter.skipSaved && filter.skipUnsaved) {
- filter.skipUnsaved = false;
- }
- });
- }, filter.skipSaved ? nullptr : &st::mediaPlayerMenuCheck);
- addAction(tr::lng_peer_gifts_filter_unsaved(tr::now), [=] {
- change([](Filter &filter) {
- filter.skipUnsaved = !filter.skipUnsaved;
- if (filter.skipSaved && filter.skipUnsaved) {
- filter.skipSaved = false;
- }
- });
- }, filter.skipUnsaved ? nullptr : &st::mediaPlayerMenuCheck);
- }
- }
- rpl::producer<QString> Widget::title() {
- return tr::lng_peer_gifts_title();
- }
- rpl::producer<bool> Widget::desiredBottomShadowVisibility() {
- return _hasPinnedToBottom.value();
- }
- not_null<PeerData*> Widget::peer() const {
- return _inner->peer();
- }
- bool Widget::showInternal(not_null<ContentMemento*> memento) {
- if (!controller()->validateMementoPeer(memento)) {
- return false;
- }
- if (auto similarMemento = dynamic_cast<Memento*>(memento.get())) {
- if (similarMemento->peer() == peer()) {
- restoreState(similarMemento);
- return true;
- }
- }
- return false;
- }
- void Widget::setInternalState(
- const QRect &geometry,
- not_null<Memento*> memento) {
- setGeometry(geometry);
- Ui::SendPendingMoveResizeEvents(this);
- restoreState(memento);
- }
- std::shared_ptr<ContentMemento> Widget::doCreateMemento() {
- auto result = std::make_shared<Memento>(peer());
- saveState(result.get());
- return result;
- }
- void Widget::saveState(not_null<Memento*> memento) {
- memento->setScrollTop(scrollTopSave());
- _inner->saveState(memento);
- }
- void Widget::restoreState(not_null<Memento*> memento) {
- _inner->restoreState(memento);
- scrollTopRestore(memento->scrollTop());
- }
- } // namespace Info::PeerGifts
|