From fa818407e6b55aaef03bd02c1d067ab1e53ca549 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 5 Aug 2017 22:01:20 +0200 Subject: [PATCH] Improve group sticker set setup box. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/boxes/abstract_box.cpp | 23 +- Telegram/SourceFiles/boxes/abstract_box.h | 22 +- Telegram/SourceFiles/boxes/boxes.style | 13 + .../boxes/edit_participant_box.cpp | 31 +- .../SourceFiles/boxes/edit_participant_box.h | 2 - Telegram/SourceFiles/boxes/stickers_box.cpp | 354 ++++++++++++++---- Telegram/SourceFiles/boxes/stickers_box.h | 102 +++-- .../chat_helpers/stickers_list_widget.cpp | 74 +++- .../chat_helpers/stickers_list_widget.h | 4 +- .../SourceFiles/ui/widgets/input_fields.cpp | 17 +- .../SourceFiles/ui/widgets/input_fields.h | 2 + 12 files changed, 478 insertions(+), 167 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 8f2ddd0faa..d207ae021f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -922,6 +922,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org "lng_stickers_masks_pack" = "This is a pack of mask stickers. You can use them in the photo editor on our mobile apps."; "lng_stickers_group_set" = "Group sticker set"; "lng_stickers_remove_group_set" = "Remove group sticker set?"; +"lng_stickers_group_from_your" = "Choose from your stickers"; "lng_in_dlg_photo" = "Photo"; "lng_in_dlg_video" = "Video"; diff --git a/Telegram/SourceFiles/boxes/abstract_box.cpp b/Telegram/SourceFiles/boxes/abstract_box.cpp index 293c505edd..fc56e37c7f 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.cpp +++ b/Telegram/SourceFiles/boxes/abstract_box.cpp @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "boxes/abstract_box.h" #include "styles/style_boxes.h" +#include "styles/style_profile.h" #include "storage/localstorage.h" #include "lang/lang_keys.h" #include "ui/effects/widget_fade_wrap.h" @@ -30,9 +31,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "mainwindow.h" -BoxLayerTitleShadow::BoxLayerTitleShadow(QWidget *parent) : Ui::PlainShadow(parent, st::boxLayerTitleShadow) { -} - QPointer BoxContent::addButton(base::lambda textFactory, base::lambda clickCallback) { return addButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton); } @@ -421,3 +419,22 @@ void AbstractBox::keyPressEvent(QKeyEvent *e) { LayerWidget::keyPressEvent(e); } } + +BoxLayerTitleShadow::BoxLayerTitleShadow(QWidget *parent) : Ui::PlainShadow(parent, st::boxLayerTitleShadow) { +} + +BoxContentDivider::BoxContentDivider(QWidget *parent) : TWidget(parent) { +} + +int BoxContentDivider::resizeGetHeight(int newWidth) { + return st::rightsDividerHeight; +} + +void BoxContentDivider::paintEvent(QPaintEvent *e) { + Painter p(this); + p.fillRect(e->rect(), st::contactsAboutBg); + auto dividerFillTop = myrtlrect(0, 0, width(), st::profileDividerTop.height()); + st::profileDividerTop.fill(p, dividerFillTop); + auto dividerFillBottom = myrtlrect(0, height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height()); + st::profileDividerBottom.fill(p, dividerFillBottom); +} diff --git a/Telegram/SourceFiles/boxes/abstract_box.h b/Telegram/SourceFiles/boxes/abstract_box.h index e70f89f14b..5f1fa56320 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.h +++ b/Telegram/SourceFiles/boxes/abstract_box.h @@ -36,11 +36,7 @@ namespace Window { class Controller; } // namespace Window -class BoxLayerTitleShadow : public Ui::PlainShadow { -public: - BoxLayerTitleShadow(QWidget *parent); - -}; +class BoxLayerTitleShadow; class BoxContentDelegate { public: @@ -287,6 +283,22 @@ private: }; +class BoxLayerTitleShadow : public Ui::PlainShadow { +public: + BoxLayerTitleShadow(QWidget *parent); + +}; + +class BoxContentDivider : public TWidget { +public: + BoxContentDivider(QWidget *parent); + +protected: + int resizeGetHeight(int newWidth) override; + void paintEvent(QPaintEvent *e) override; + +}; + enum CreatingGroupType { CreatingGroupNone, CreatingGroupGroup, diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index cec4378947..81f5fabae8 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -679,3 +679,16 @@ muteChatTitle: FlatLabel(boxLabel) { font: font(boxFontSize semibold); } } + +groupStickersRemove: contactsSearchCancel; +groupStickersRemovePosition: point(6px, 6px); +groupStickersFieldPadding: margins(8px, 6px, 8px, 6px); +groupStickersField: InputField(contactsSearchField) { + placeholderFont: boxTextFont; + font: boxTextFont; + placeholderMargins: margins(0px, 0px, 0px, 0px); + textMargins: margins(0px, 7px, 0px, 0px); + textBg: boxBg; + heightMin: 32px; +} +groupStickersSubTitleHeight: 36px; diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/edit_participant_box.cpp index d479e55116..334d7ac165 100644 --- a/Telegram/SourceFiles/boxes/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_participant_box.cpp @@ -25,7 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "styles/style_boxes.h" -#include "styles/style_profile.h" #include "ui/special_buttons.h" #include "boxes/calendar_box.h" @@ -74,30 +73,6 @@ void ApplyDependencies(CheckboxesMap &checkboxes, DependenciesMap &dependencies, } // namespace -class EditParticipantBox::Divider : public TWidget { -public: - Divider(QWidget *parent) : TWidget(parent) { - } - -protected: - int resizeGetHeight(int newWidth) override; - void paintEvent(QPaintEvent *e) override; - -}; - -int EditParticipantBox::Divider::resizeGetHeight(int newWidth) { - return st::rightsDividerHeight; -} - -void EditParticipantBox::Divider::paintEvent(QPaintEvent *e) { - Painter p(this); - p.fillRect(e->rect(), st::contactsAboutBg); - auto dividerFillTop = myrtlrect(0, 0, width(), st::profileDividerTop.height()); - st::profileDividerTop.fill(p, dividerFillTop); - auto dividerFillBottom = myrtlrect(0, height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height()); - st::profileDividerBottom.fill(p, dividerFillBottom); -} - class EditParticipantBox::Inner : public TWidget { public: Inner(QWidget *parent, gsl::not_null channel, gsl::not_null user, bool hasAdminRights); @@ -236,7 +211,7 @@ void EditAdminBox::prepare() { auto hadRights = _oldRights.c_channelAdminRights().vflags.v; setTitle(langFactory(hadRights ? lng_rights_edit_admin : lng_channel_add_admin)); - addControl(object_ptr(this), QMargins()); + addControl(object_ptr(this), QMargins()); addControl(object_ptr(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin); auto prepareRights = (hadRights ? _oldRights : DefaultRights(channel())); @@ -355,7 +330,7 @@ void EditRestrictedBox::prepare() { setTitle(langFactory(lng_rights_user_restrictions)); - addControl(object_ptr(this), QMargins()); + addControl(object_ptr(this), QMargins()); addControl(object_ptr(this, lang(lng_rights_user_restrictions_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin); auto prepareRights = (_oldRights.c_channelBannedRights().vflags.v ? _oldRights : DefaultRights(channel())); @@ -378,7 +353,7 @@ void EditRestrictedBox::prepare() { addCheckbox(Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline, lang(lng_rights_chat_send_stickers)); addCheckbox(Flag::f_embed_links, lang(lng_rights_chat_send_links)); - addControl(object_ptr(this), st::rightsUntilMargin); + addControl(object_ptr(this), st::rightsUntilMargin); addControl(object_ptr(this, lang(lng_rights_chat_banned_until_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin); setRestrictUntil(_until); diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.h b/Telegram/SourceFiles/boxes/edit_participant_box.h index 6b6519fba2..ca5edd0206 100644 --- a/Telegram/SourceFiles/boxes/edit_participant_box.h +++ b/Telegram/SourceFiles/boxes/edit_participant_box.h @@ -57,8 +57,6 @@ protected: return _hasAdminRights; } - class Divider; - private: gsl::not_null _channel; gsl::not_null _user; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index d95f54d63f..03d276a8ce 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -31,16 +31,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/labels.h" #include "ui/widgets/scroll_area.h" #include "ui/effects/ripple_animation.h" #include "ui/effects/slide_animation.h" #include "ui/widgets/discrete_sliders.h" +#include "ui/widgets/input_fields.h" #include "auth_session.h" +#include "messenger.h" namespace { -constexpr int kArchivedLimitFirstRequest = 10; -constexpr int kArchivedLimitPerPage = 30; +constexpr auto kArchivedLimitFirstRequest = 10; +constexpr auto kArchivedLimitPerPage = 30; +constexpr auto kHandleMegagroupSetAddressChangeTimeout = TimeMs(1000); } // namespace @@ -156,6 +160,7 @@ StickersBox::StickersBox(QWidget*, gsl::not_null megagroup) : _section(Section::Installed) , _installed(0, this, megagroup) , _megagroupSet(megagroup) { + subscribe(_installed.widget()->scrollToY, [this](int y) { onScrollToY(y); }); } void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result) { @@ -264,7 +269,12 @@ void StickersBox::prepare() { _archived.widget()->setLoadMoreCallback([this] { loadMoreArchived(); }); } - addButton(langFactory(lng_about_done), [this] { closeBox(); }); + if (_megagroupSet) { + addButton(langFactory(lng_settings_save), [this] { _installed.widget()->saveGroupSet(); closeBox(); }); + addButton(langFactory(lng_cancel), [this] { closeBox(); }); + } else { + addButton(langFactory(lng_about_done), [this] { closeBox(); }); + } if (_section == Section::Installed) { _tab = &_installed; @@ -554,7 +564,7 @@ void StickersBox::rebuildList(Tab *tab) { } void StickersBox::closeHook() { - if (!_installed.widget()) { + if (!_installed.widget() || _megagroupSet) { return; } @@ -569,8 +579,30 @@ void StickersBox::closeHook() { } } +void StickersBox::setInnerFocus() { + if (_megagroupSet) { + _installed.widget()->setInnerFocus(); + } +} + StickersBox::~StickersBox() = default; +StickersBox::Inner::Row::Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh) : id(id) +, sticker(sticker) +, count(count) +, title(title) +, titleWidth(titleWidth) +, installed(installed) +, official(official) +, unread(unread) +, archived(archived) +, removed(removed) +, pixw(pixw) +, pixh(pixh) { +} + +StickersBox::Inner::Row::~Row() = default; + StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : TWidget(parent) , _section(section) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) @@ -599,7 +631,17 @@ StickersBox::Inner::Inner(QWidget *parent, gsl::not_null megagroup , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _a_shifting(animation(this, &Inner::step_shifting)) , _itemsTop(st::membersMarginTop) -, _megagroupSet(megagroup) { +, _megagroupSet(megagroup) +, _megagroupSetInput(_megagroupSet->mgInfo->stickerSet) +, _megagroupSetField(this, st::groupStickersField, [] { return qsl("stickerset"); }, QString(), true) +, _megagroupDivider(this) +, _megagroupSubTitle(this, lang(lng_stickers_group_from_your), Ui::FlatLabel::InitType::Simple, st::boxTitle) { + _megagroupSetField->setLinkPlaceholder(Messenger::Instance().createInternalLink(qsl("addstickers/"))); + _megagroupSetField->setPlaceholderHidden(false); + _megagroupSetAddressChangedTimer.setCallback([this] { handleMegagroupSetAddressChange(); }); + connect(_megagroupSetField, &Ui::MaskedInputField::changed, this, [this] { _megagroupSetAddressChangedTimer.callOnce(kHandleMegagroupSetAddressChangeTimeout); }); + connect(_megagroupSetField, &Ui::MaskedInputField::submitted, this, [this] { _megagroupSetAddressChangedTimer.cancel(); handleMegagroupSetAddressChange(); }); + setup(); } @@ -611,41 +653,76 @@ void StickersBox::Inner::setup() { setMouseTracking(true); } +void StickersBox::Inner::setInnerFocus() { + if (_megagroupSetField) { + _megagroupSetField->setFocusFast(); + } +} + void StickersBox::Inner::paintEvent(QPaintEvent *e) { - QRect r(e->rect()); Painter p(this); _a_shifting.step(); + auto clip = e->rect(); auto ms = getms(); - p.fillRect(r, st::boxBg); - p.setClipRect(r); + p.fillRect(clip, st::boxBg); + p.setClipRect(clip); + + if (_megagroupSelectedSet) { + auto setTop = _megagroupDivider->y() - _rowHeight; + p.translate(0, setTop); + paintRow(p, _megagroupSelectedSet.get(), -1, ms); + p.translate(0, -setTop); + } auto y = _itemsTop; - if (_rows.isEmpty()) { + if (_rows.empty()) { p.setFont(st::noContactsFont); p.setPen(st::noContactsColor); p.drawText(QRect(0, y, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); } else { p.translate(0, _itemsTop); - int32 yFrom = r.y() - _itemsTop, yTo = r.y() + r.height() - _itemsTop; + int32 yFrom = clip.y() - _itemsTop, yTo = clip.y() + clip.height() - _itemsTop; int32 from = floorclamp(yFrom - _rowHeight, _rowHeight, 0, _rows.size()); int32 to = ceilclamp(yTo + _rowHeight, _rowHeight, 0, _rows.size()); p.translate(0, from * _rowHeight); for (int32 i = from; i < to; ++i) { if (i != _above) { - paintRow(p, i, ms); + paintRow(p, _rows[i].get(), i, ms); } p.translate(0, _rowHeight); } if (from <= _above && _above < to) { p.translate(0, (_above - to) * _rowHeight); - paintRow(p, _above, ms); + paintRow(p, _rows[_above].get(), _above, ms); } } } +void StickersBox::Inner::resizeEvent(QResizeEvent *e) { + updateControlsGeometry(); +} + +void StickersBox::Inner::updateControlsGeometry() { + if (_megagroupSet) { + auto top = st::groupStickersFieldPadding.top(); + auto fieldLeft = st::boxLayerTitlePosition.x(); + _megagroupSetField->setGeometryToLeft(fieldLeft, top, width() - fieldLeft - st::groupStickersFieldPadding.right(), _megagroupSetField->height()); + top += _megagroupSetField->height() + st::groupStickersFieldPadding.bottom(); + if (_megagroupSelectedRemove) { + _megagroupSelectedShadow->setGeometryToLeft(0, top, width(), st::lineWidth); + top += st::lineWidth; + _megagroupSelectedRemove->moveToRight(st::groupStickersRemovePosition.x(), top + st::groupStickersRemovePosition.y()); + top += _rowHeight; + } + _megagroupDivider->setGeometryToLeft(0, top, width(), _megagroupDivider->height()); + top += _megagroupDivider->height(); + _megagroupSubTitle->moveToLeft(st::boxLayerTitlePosition.x(), top + st::boxLayerTitlePosition.y()); + } +} + QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const { auto buttonw = st::stickersRemove.width; auto buttonh = st::stickersRemove.height; @@ -662,14 +739,21 @@ QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const { return QRect(buttonx, buttony, buttonw, buttonh); } -void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) { - auto s = _rows.at(index); - - auto xadd = 0, yadd = qRound(s->yadd.current()); +void StickersBox::Inner::paintRow(Painter &p, Row *set, int index, TimeMs ms) { + auto xadd = 0, yadd = qRound(set->yadd.current()); if (xadd || yadd) p.translate(xadd, yadd); + if (_megagroupSet) { + if (index >= 0 && index == _selected) { + p.fillRect(0, 0, width(), _rowHeight, st::contactsBgOver); + if (set->ripple) { + set->ripple->paint(p, 0, 0, width(), ms); + } + } + } + if (_section == Section::Installed) { - if (index == _above) { + if (index >= 0 && index == _above) { auto current = _aboveShadowFadeOpacity.current(); if (_started >= 0) { auto reachedOpacity = aboveShadowOpacity(); @@ -686,16 +770,16 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) { App::roundRect(p, row, st::boxBg, BoxCorners); p.setOpacity(1. - current); - paintFakeButton(p, index, ms); + paintFakeButton(p, set, index, ms); p.setOpacity(1.); } else if (!_megagroupSet) { - paintFakeButton(p, index, ms); + paintFakeButton(p, set, index, ms); } } else if (!_megagroupSet) { - paintFakeButton(p, index, ms); + paintFakeButton(p, set, index, ms); } - if (s->removed && _section == Section::Installed) { + if (set->removed && _section == Section::Installed) { p.setOpacity(st::stickersRowDisabledOpacity); } @@ -703,15 +787,15 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) { if (!_megagroupSet && _section == Section::Installed) { stickerx += st::stickersReorderIcon.width() + st::stickersReorderSkip; - if (!s->isRecentSet()) { + if (!set->isRecentSet()) { st::stickersReorderIcon.paint(p, st::contactsPadding.left(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width()); } } - if (s->sticker) { - s->sticker->thumb->load(); - QPixmap pix(s->sticker->thumb->pix(s->pixw, s->pixh)); - p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - s->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - s->pixh) / 2, width(), pix); + if (set->sticker) { + set->sticker->thumb->load(); + auto pix = set->sticker->thumb->pix(set->pixw, set->pixh); + p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix); } int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left(); @@ -722,19 +806,19 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) { p.setFont(st::contactsNameStyle.font); p.setPen(st::contactsNameFg); - p.drawTextLeft(namex, namey, width(), s->title, s->titleWidth); + p.drawTextLeft(namex, namey, width(), set->title, set->titleWidth); - if (s->unread) { + if (set->unread) { p.setPen(Qt::NoPen); p.setBrush(st::stickersFeaturedUnreadBg); { PainterHighQualityEnabler hq(p); - p.drawEllipse(rtlrect(namex + s->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width())); + p.drawEllipse(rtlrect(namex + set->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width())); } } - auto statusText = (s->count > 0) ? lng_stickers_count(lt_count, s->count) : lang(lng_contacts_loading); + auto statusText = (set->count > 0) ? lng_stickers_count(lt_count, set->count) : lang(lng_contacts_loading); p.setFont(st::contactsStatusFont); p.setPen(st::contactsStatusFg); @@ -744,8 +828,7 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) { if (xadd || yadd) p.translate(-xadd, -yadd); } -void StickersBox::Inner::paintFakeButton(Painter &p, int index, TimeMs ms) { - auto set = _rows[index]; +void StickersBox::Inner::paintFakeButton(Painter &p, Row *set, int index, TimeMs ms) { auto removeButton = (_section == Section::Installed && !set->removed); auto rect = relativeButtonRect(removeButton); if (_section != Section::Installed && set->installed && !set->archived && !set->removed) { @@ -794,7 +877,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) { _mouse = e->globalPos(); onUpdateSelected(); - _pressed = _selected; + setPressed(_selected); if (_actionSel >= 0) { setActionDown(_actionSel); update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); @@ -810,7 +893,7 @@ void StickersBox::Inner::setActionDown(int newActionDown) { } if (_actionDown >= 0 && _actionDown < _rows.size()) { update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight); - auto set = _rows[_actionDown]; + auto &set = _rows[_actionDown]; if (set->ripple) { set->ripple->lastStop(); } @@ -818,7 +901,7 @@ void StickersBox::Inner::setActionDown(int newActionDown) { _actionDown = newActionDown; if (_actionDown >= 0 && _actionDown < _rows.size()) { update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight); - auto set = _rows[_actionDown]; + auto &set = _rows[_actionDown]; auto removeButton = (_section == Section::Installed && !set->removed); if (!set->ripple) { if (_section == Section::Installed) { @@ -844,8 +927,46 @@ void StickersBox::Inner::setActionDown(int newActionDown) { } } +void StickersBox::Inner::setSelected(int selected) { + if (_selected == selected) { + return; + } + if (_megagroupSet && _selected >= 0 && _selected < _rows.size()) { + update(0, _itemsTop + _selected * _rowHeight, width(), _rowHeight); + } + _selected = selected; + if (_megagroupSet && _selected >= 0 && _selected < _rows.size()) { + update(0, _itemsTop + _selected * _rowHeight, width(), _rowHeight); + } +} + +void StickersBox::Inner::setPressed(int pressed) { + if (_pressed == pressed) { + return; + } + if (_megagroupSet && _pressed >= 0 && _pressed < _rows.size()) { + update(0, _itemsTop + _pressed * _rowHeight, width(), _rowHeight); + auto &set = _rows[_pressed]; + if (set->ripple) { + set->ripple->lastStop(); + } + } + _pressed = pressed; + if (_megagroupSet && _pressed >= 0 && _pressed < _rows.size()) { + update(0, _itemsTop + _pressed * _rowHeight, width(), _rowHeight); + auto &set = _rows[_pressed]; + auto rippleMask = Ui::RippleAnimation::rectMask(QSize(width(), _rowHeight)); + if (!_rows[_pressed]->ripple) { + _rows[_pressed]->ripple = std::make_unique(st::contactsRipple, std::move(rippleMask), [this, index = _pressed] { + update(0, _itemsTop + index * _rowHeight, width(), _rowHeight); + }); + } + _rows[_pressed]->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(0, _itemsTop + _pressed * _rowHeight)); + } +} + void StickersBox::Inner::ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton) { - _rows[_actionDown]->ripple = MakeShared(st, std::move(mask), [this, index = _actionDown, removeButton] { + _rows[_actionDown]->ripple = std::make_unique(st, std::move(mask), [this, index = _actionDown, removeButton] { update(myrtlrect(relativeButtonRect(removeButton).translated(0, _itemsTop + index * _rowHeight))); }); } @@ -906,10 +1027,10 @@ void StickersBox::Inner::onUpdateSelected() { auto selected = -1; auto actionSel = -1; auto inDragArea = false; - if (in && !_rows.isEmpty()) { + if (in && !_rows.empty()) { selected = floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1); local.setY(local.y() - _itemsTop - selected * _rowHeight); - auto set = _rows[selected]; + auto &set = _rows[selected]; if (!_megagroupSet && (_section == Section::Installed || !set->installed || set->archived || set->removed)) { auto removeButton = (_section == Section::Installed && !set->removed); auto rect = myrtlrect(relativeButtonRect(removeButton)); @@ -931,7 +1052,7 @@ void StickersBox::Inner::onUpdateSelected() { setCursor((selected >= 0 || _pressed >= 0) ? style::cur_pointer : style::cur_default); } } - _selected = selected; + setSelected(selected); } if (_inDragArea != inDragArea) { _inDragArea = inDragArea; @@ -978,16 +1099,14 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) { } else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) { if (_selected >= 0 && !_inDragArea) { auto &sets = Global::RefStickerSets(); - auto row = _rows[pressed]; + auto &row = _rows[pressed]; if (!row->isRecentSet()) { auto it = sets.find(row->id); if (it != sets.cend()) { - _selected = -1; if (_megagroupSet) { - Auth().api().setGroupStickerSet(_megagroupSet, Stickers::inputSetId(*it)); - Ui::hideLayer(); - App::main()->onStickersInstalled(Stickers::MegagroupSetId); + setMegagroupSelectedSet(MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access))); } else { + setSelected(-1); Ui::show(Box(Stickers::inputSetId(*it)), KeepOtherLayers); } } @@ -997,8 +1116,18 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) { setActionDown(-1); } +void StickersBox::Inner::saveGroupSet() { + Expects(_megagroupSet != nullptr); + auto oldId = (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) ? _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID().vid.v : 0; + auto newId = (_megagroupSetInput.type() == mtpc_inputStickerSetID) ? _megagroupSetInput.c_inputStickerSetID().vid.v : 0; + if (newId != oldId) { + Auth().api().setGroupStickerSet(_megagroupSet, _megagroupSetInput); + App::main()->onStickersInstalled(Stickers::MegagroupSetId); + } +} + void StickersBox::Inner::setRowRemoved(int index, bool removed) { - auto row = _rows[index]; + auto &row = _rows[index]; if (row->removed != removed) { row->removed = removed; row->ripple.reset(); @@ -1012,6 +1141,11 @@ void StickersBox::Inner::leaveEventHook(QEvent *e) { onUpdateSelected(); } +void StickersBox::Inner::leaveToChildEvent(QEvent *e, QWidget *child) { + _mouse = QPoint(-1, -1); + onUpdateSelected(); +} + void StickersBox::Inner::step_shifting(TimeMs ms, bool timer) { auto animating = false; auto updateMin = -1; @@ -1062,19 +1196,16 @@ void StickersBox::Inner::step_shifting(TimeMs ms, bool timer) { } void StickersBox::Inner::clear() { - for (int32 i = 0, l = _rows.size(); i < l; ++i) { - delete _rows.at(i); - } _rows.clear(); _animStartTimes.clear(); _aboveShadowFadeStart = 0; _aboveShadowFadeOpacity = anim::value(); _a_shifting.stop(); _above = _dragging = _started = -1; - _selected = -1; - _pressed = -1; - _actionDown = -1; + setSelected(-1); + setPressed(-1); setActionSel(-1); + setActionDown(-1); update(); } @@ -1089,10 +1220,86 @@ void StickersBox::Inner::setActionSel(int32 actionSel) { } } +void StickersBox::Inner::handleMegagroupSetAddressChange() { + auto text = _megagroupSetField->getLastText().trimmed(); + if (text.isEmpty()) { + if (_megagroupSelectedSet) { + auto it = Global::StickerSets().constFind(_megagroupSelectedSet->id); + if (it != Global::StickerSets().end() && !it->shortName.isEmpty()) { + setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); + } + } + } else if (!_megagroupSetRequestId) { + _megagroupSetRequestId = request(MTPmessages_GetStickerSet(MTP_inputStickerSetShortName(MTP_string(text)))).done([this](const MTPmessages_StickerSet &result) { + _megagroupSetRequestId = 0; + auto set = Stickers::FeedSetFull(result); + setMegagroupSelectedSet(MTP_inputStickerSetID(MTP_long(set->id), MTP_long(set->access))); + }).fail([this](const RPCError &error) { + _megagroupSetRequestId = 0; + setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); + }).send(); + } else { + _megagroupSetAddressChangedTimer.callOnce(kHandleMegagroupSetAddressChangeTimeout); + } +} + +void StickersBox::Inner::rebuildMegagroupSet() { + Expects(_megagroupSet != nullptr); + if (_megagroupSetInput.type() != mtpc_inputStickerSetID) { + if (_megagroupSelectedSet) { + _megagroupSetField->setText(QString()); + _megagroupSetField->finishAnimations(); + } + _megagroupSelectedSet.reset(); + _megagroupSelectedRemove.destroy(); + _megagroupSelectedShadow.destroy(); + return; + } + auto &set = _megagroupSetInput.c_inputStickerSetID(); + auto setId = set.vid.v; + auto &sets = Global::StickerSets(); + auto it = sets.find(setId); + if (it == sets.cend() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + Auth().api().scheduleStickerSetRequest(set.vid.v, set.vaccess_hash.v); + return; + } + + auto maxNameWidth = countMaxNameWidth(); + auto titleWidth = 0; + auto title = fillSetTitle(*it, maxNameWidth, &titleWidth); + auto count = fillSetCount(*it); + auto sticker = (DocumentData*)nullptr; + auto pixw = 0, pixh = 0; + fillSetCover(*it, &sticker, &pixw, &pixh); + auto installed = true, official = false, unread = false, archived = false, removed = false; + if (!_megagroupSelectedSet || _megagroupSelectedSet->id != it->id) { + _megagroupSetField->setText(it->shortName); + _megagroupSetField->finishAnimations(); + } + _megagroupSelectedSet = std::make_unique(it->id, sticker, count, title, titleWidth, installed, official, unread, archived, removed, pixw, pixh); + _itemsTop += st::lineWidth + _rowHeight; + + if (!_megagroupSelectedRemove) { + _megagroupSelectedRemove.create(this, st::groupStickersRemove); + _megagroupSelectedRemove->showFast(); + _megagroupSelectedRemove->setClickedCallback([this] { + setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); + }); + _megagroupSelectedShadow.create(this); + updateControlsGeometry(); + } +} + void StickersBox::Inner::rebuild() { _itemsTop = st::membersMarginTop; - int maxNameWidth = countMaxNameWidth(); + if (_megagroupSet) { + _itemsTop += st::groupStickersFieldPadding.top() + _megagroupSetField->height() + st::groupStickersFieldPadding.bottom(); + _itemsTop += _megagroupDivider->height() + st::groupStickersSubTitleHeight; + rebuildMegagroupSet(); + } + + auto maxNameWidth = countMaxNameWidth(); clear(); auto &order = ([this]() -> const Stickers::Order & { @@ -1131,21 +1338,34 @@ void StickersBox::Inner::rebuild() { updateSize(); } -void StickersBox::Inner::updateSize() { - resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersMarginBottom); +void StickersBox::Inner::setMegagroupSelectedSet(const MTPInputStickerSet &set) { + _megagroupSetInput = set; + rebuild(); + scrollToY.notify(0, true); + onUpdateSelected(); +} + +void StickersBox::Inner::setMinHeight(int newWidth, int minHeight) { + _minHeight = minHeight; + updateSize(newWidth); +} + +void StickersBox::Inner::updateSize(int newWidth) { + auto naturalHeight = _itemsTop + int(_rows.size()) * _rowHeight + st::membersMarginBottom; + resize(newWidth ? newWidth : width(), qMax(_minHeight, naturalHeight)); checkLoadMore(); } void StickersBox::Inner::updateRows() { int maxNameWidth = countMaxNameWidth(); auto &sets = Global::StickerSets(); - for_const (auto row, _rows) { + for_const (auto &row, _rows) { auto it = sets.constFind(row->id); if (it != sets.cend()) { auto &set = it.value(); if (!row->sticker) { - DocumentData *sticker = nullptr; - int pixw = 0, pixh = 0; + auto sticker = (DocumentData*)nullptr; + auto pixw = 0, pixh = 0; fillSetCover(set, &sticker, &pixw, &pixh); if (sticker) { row->sticker = sticker; @@ -1172,7 +1392,7 @@ void StickersBox::Inner::updateRows() { } bool StickersBox::Inner::appendSet(const Stickers::Set &set) { - for_const (auto row, _rows) { + for_const (auto &row, _rows) { if (row->id == set.id) { return false; } @@ -1212,7 +1432,7 @@ void StickersBox::Inner::rebuildAppendSet(const Stickers::Set &set, int maxNameW QString title = fillSetTitle(set, maxNameWidth, &titleWidth); int count = fillSetCount(set); - _rows.push_back(new Row(set.id, sticker, count, title, titleWidth, installed, official, unread, archived, removed, pixw, pixh)); + _rows.push_back(std::make_unique(set.id, sticker, count, title, titleWidth, installed, official, unread, archived, removed, pixw, pixh)); _animStartTimes.push_back(0); } @@ -1288,8 +1508,8 @@ template Stickers::Order StickersBox::Inner::collectSets(Check check) const { Stickers::Order result; result.reserve(_rows.size()); - for_const (auto row, _rows) { - if (check(row)) { + for_const (auto &row, _rows) { + if (check(row.get())) { result.push_back(row->id); } } @@ -1315,8 +1535,8 @@ Stickers::Order StickersBox::Inner::getRemovedSets() const { } int StickersBox::Inner::getRowIndex(uint64 setId) const { - for (auto i = 0, count = _rows.size(); i != count; ++i) { - auto row = _rows[i]; + for (auto i = 0, count = int(_rows.size()); i != count; ++i) { + auto &row = _rows[i]; if (row->id == setId) { return i; } @@ -1328,18 +1548,18 @@ void StickersBox::Inner::setFullOrder(const Stickers::Order &order) { for_const (auto setId, order) { auto index = getRowIndex(setId); if (index >= 0) { - auto row = _rows[index]; + auto row = std::move(_rows[index]); auto count = _rows.size(); for (auto i = index + 1; i != count; ++i) { - _rows[i - 1] = _rows[i]; + _rows[i - 1] = std::move(_rows[i]); } - _rows[count - 1] = row; + _rows[count - 1] = std::move(row); } } } void StickersBox::Inner::setRemovedSets(const Stickers::Order &removed) { - for (auto i = 0, count = _rows.size(); i != count; ++i) { + for (auto i = 0, count = int(_rows.size()); i != count; ++i) { setRowRemoved(i, removed.contains(_rows[i]->id)); } } diff --git a/Telegram/SourceFiles/boxes/stickers_box.h b/Telegram/SourceFiles/boxes/stickers_box.h index 3b0cc4ec94..7b8f9e8cc7 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.h +++ b/Telegram/SourceFiles/boxes/stickers_box.h @@ -21,6 +21,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "boxes/abstract_box.h" +#include "base/timer.h" +#include "mtproto/sender.h" class ConfirmBox; @@ -33,6 +35,8 @@ class PlainShadow; class RippleAnimation; class SettingsSlider; class SlideAnimation; +class UsernameInput; +class CrossButton; } // namespace Ui class StickersBox : public BoxContent, public RPCSender { @@ -48,6 +52,7 @@ public: StickersBox(QWidget*, gsl::not_null megagroup); void closeHook() override; + void setInnerFocus() override; ~StickersBox(); @@ -142,7 +147,7 @@ private: int stickerPacksCount(bool includeArchivedOfficial = false); // This class is hold in header because it requires Qt preprocessing. -class StickersBox::Inner : public TWidget, private base::Subscriber { +class StickersBox::Inner : public TWidget, private base::Subscriber, private MTP::Sender { Q_OBJECT public: @@ -151,8 +156,13 @@ public: Inner(QWidget *parent, const Stickers::Order &archivedIds); Inner(QWidget *parent, gsl::not_null megagroup); + base::Observable scrollToY; + void setInnerFocus(); + + void saveGroupSet(); + void rebuild(); - void updateSize(); + void updateSize(int newWidth = 0); void updateRows(); // refresh only pack cover stickers bool appendSet(const Stickers::Set &set); @@ -171,6 +181,7 @@ public: } void setVisibleTopBottom(int visibleTop, int visibleBottom) override; + void setMinHeight(int newWidth, int minHeight); int getVisibleTop() const { return _visibleTop; @@ -180,10 +191,12 @@ public: protected: void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void leaveEventHook(QEvent *e) override; + void leaveToChildEvent(QEvent *e, QWidget *child) override; signals: void draggingScrollDelta(int delta); @@ -192,6 +205,29 @@ public slots: void onUpdateSelected(); private: + struct Row { + Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh); + bool isRecentSet() const { + return (id == Stickers::CloudRecentSetId); + } + ~Row(); + + uint64 id = 0; + DocumentData *sticker = nullptr; + int32 count = 0; + QString title; + int titleWidth = 0; + bool installed = false; + bool official = false; + bool unread = false; + bool archived = false; + bool removed = false; + int32 pixw = 0; + int32 pixh = 0; + anim::value yadd; + std::unique_ptr ripple; + }; + template Stickers::Order collectSets(Check check) const; @@ -200,63 +236,40 @@ private: int getRowIndex(uint64 setId) const; void setRowRemoved(int index, bool removed); + void setSelected(int selected); void setActionDown(int newActionDown); + void setPressed(int pressed); void setup(); QRect relativeButtonRect(bool removeButton) const; void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton); void step_shifting(TimeMs ms, bool timer); - void paintRow(Painter &p, int index, TimeMs ms); - void paintFakeButton(Painter &p, int index, TimeMs ms); + void paintRow(Painter &p, Row *set, int index, TimeMs ms); + void paintFakeButton(Painter &p, Row *set, int index, TimeMs ms); void clear(); void setActionSel(int32 actionSel); float64 aboveShadowOpacity() const; void readVisibleSets(); - Section _section; - Stickers::Order _archivedIds; - - int32 _rowHeight; - struct Row { - Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh) : id(id) - , sticker(sticker) - , count(count) - , title(title) - , titleWidth(titleWidth) - , installed(installed) - , official(official) - , unread(unread) - , archived(archived) - , removed(removed) - , pixw(pixw) - , pixh(pixh) - , yadd(0, 0) { - } - bool isRecentSet() const { - return (id == Stickers::CloudRecentSetId); - } - uint64 id; - DocumentData *sticker; - int32 count; - QString title; - int titleWidth; - bool installed, official, unread, archived, removed; - int32 pixw, pixh; - anim::value yadd; - QSharedPointer ripple; - }; - using Rows = QList; - + void updateControlsGeometry(); void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth); void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const; int fillSetCount(const Stickers::Set &set) const; QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const; void fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived); + void rebuildMegagroupSet(); + void handleMegagroupSetAddressChange(); + void setMegagroupSelectedSet(const MTPInputStickerSet &set); int countMaxNameWidth() const; - Rows _rows; + Section _section; + Stickers::Order _archivedIds; + + int32 _rowHeight; + + std::vector> _rows; QList _animStartTimes; TimeMs _aboveShadowFadeStart = 0; anim::value _aboveShadowFadeOpacity; @@ -288,7 +301,18 @@ private: int _dragging = -1; int _above = -1; + int _minHeight = 0; + int _scrollbar = 0; ChannelData *_megagroupSet = nullptr; + MTPInputStickerSet _megagroupSetInput = MTP_inputStickerSetEmpty(); + std::unique_ptr _megagroupSelectedSet; + object_ptr _megagroupSetField = { nullptr }; + object_ptr _megagroupSelectedShadow = { nullptr }; + object_ptr _megagroupSelectedRemove = { nullptr }; + object_ptr _megagroupDivider = { nullptr }; + object_ptr _megagroupSubTitle = { nullptr }; + base::Timer _megagroupSetAddressChangedTimer; + mtpRequestId _megagroupSetRequestId = 0; }; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index e94baaf418..ad81a0c158 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -436,10 +436,10 @@ void StickersListWidget::Footer::step_icons(TimeMs ms, bool timer) { StickersListWidget::StickersListWidget(QWidget *parent, gsl::not_null controller) : Inner(parent, controller) , _section(Section::Stickers) +, _megagroupSetAbout(st::emojiPanWidth - st::emojiScroll.width - st::emojiPanHeaderLeft) , _addText(lang(lng_stickers_featured_add).toUpper()) , _addWidth(st::stickersTrendingAdd.font->width(_addText)) -, _settings(this, lang(lng_stickers_you_have)) -, _megagroupSetAbout(st::emojiPanWidth - st::emojiScroll.width - st::emojiPanHeaderLeft) { +, _settings(this, lang(lng_stickers_you_have)) { resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, countHeight()); setMouseTracking(true); @@ -877,7 +877,10 @@ bool StickersListWidget::hasRemoveButton(int index) const { } if (set.id == Stickers::MegagroupSetId) { t_assert(_megagroupSet != nullptr); - return set.pack.empty() ? (index + 1 != _mySets.size()) : _megagroupSet->canEditStickers(); + if (index + 1 != _mySets.size()) { + return true; + } + return !set.pack.empty() && _megagroupSet->canEditStickers(); } return false; } @@ -1015,7 +1018,9 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) { if (_section == Section::Featured) { installSet(sets[button->section].id); } else if (sets[button->section].id == Stickers::MegagroupSetId) { - removeMegagroupSet(sets[button->section].pack.empty()); + auto removeLocally = sets[button->section].pack.empty() + || !_megagroupSet->canEditStickers(); + removeMegagroupSet(removeLocally); } else { removeSet(sets[button->section].id); } @@ -1293,36 +1298,53 @@ void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) { if (!_megagroupSet) { return; } + auto canEdit = _megagroupSet->canEditStickers(); + auto isShownHere = [place](bool hidden) { + return (hidden == (place == GroupStickersPlace::Hidden)); + }; if (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetEmpty) { - if (_megagroupSet->canEditStickers()) { + if (canEdit) { auto hidden = Auth().data().isGroupStickersSectionHidden(_megagroupSet->id); - if (hidden == (place == GroupStickersPlace::Hidden)) { + if (isShownHere(hidden)) { _mySets.push_back(Set(Stickers::MegagroupSetId, qFlags(MTPDstickerSet_ClientFlag::f_special), lang(lng_group_stickers), 0)); } } return; } - if (place != GroupStickersPlace::Visible) { - return; - } - if (Auth().data().isGroupStickersSectionHidden(_megagroupSet->id)) { - Auth().data().removeGroupStickersSectionHidden(_megagroupSet->id); - Local::writeUserSettings(); + auto hidden = Auth().data().isGroupStickersSectionHidden(_megagroupSet->id); + auto removeHiddenForGroup = [this, &hidden] { + if (hidden) { + Auth().data().removeGroupStickersSectionHidden(_megagroupSet->id); + Local::writeUserSettings(); + hidden = false; + } + }; + if (canEdit && hidden) { + removeHiddenForGroup(); } if (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) { auto &set = _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID(); auto &sets = Global::StickerSets(); auto it = sets.constFind(set.vid.v); if (it != sets.cend()) { - _mySets.push_back(Set(Stickers::MegagroupSetId, qFlags(MTPDstickerSet_ClientFlag::f_special), lang(lng_group_stickers), it->stickers.size() + 1, it->stickers)); + auto isInstalled = (it->flags & MTPDstickerSet::Flag::f_installed) + && !(it->flags & MTPDstickerSet::Flag::f_archived); + if (isInstalled && !canEdit) { + removeHiddenForGroup(); + } else if (isShownHere(hidden)) { + _mySets.push_back(Set(Stickers::MegagroupSetId, qFlags(MTPDstickerSet_ClientFlag::f_special), lang(lng_group_stickers), it->stickers.size() + 1, it->stickers)); + } return; } } + if (!isShownHere(hidden)) { + return; + } request(MTPmessages_GetStickerSet(_megagroupSet->mgInfo->stickerSet)).done([this](const MTPmessages_StickerSet &result) { if (auto set = Stickers::FeedSetFull(result)) { refreshStickers(); } - }); + }).send(); } void StickersListWidget::fillIcons(QList &icons) { @@ -1417,6 +1439,9 @@ void StickersListWidget::updateSelected() { newSelected = OverButton { section }; } else if (!(sets[section].flags & MTPDstickerSet_ClientFlag::f_special)) { newSelected = OverSet { section }; + } else if (sets[section].id == Stickers::MegagroupSetId + && (_megagroupSet->canEditStickers() || !sets[section].pack.empty())) { + newSelected = OverSet { section }; } } else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom && sx >= 0) { auto yOffset = p.y() - info.rowsTop; @@ -1578,6 +1603,21 @@ void StickersListWidget::showMegagroupSet(ChannelData *megagroup) { } void StickersListWidget::displaySet(uint64 setId) { + if (setId == Stickers::MegagroupSetId) { + if (_megagroupSet->canEditStickers()) { + _displayingSetId = setId; + auto box = Ui::show(Box(_megagroupSet)); + connect(box, &QObject::destroyed, this, [this] { + _displayingSetId = 0; + emit checkForHide(); + }); + return; + } else if (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) { + setId = _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID().vid.v; + } else { + return; + } + } auto &sets = Global::StickerSets(); auto it = sets.constFind(setId); if (it != sets.cend()) { @@ -1608,8 +1648,8 @@ void StickersListWidget::installSet(uint64 setId) { } } -void StickersListWidget::removeMegagroupSet(bool empty) { - if (empty) { +void StickersListWidget::removeMegagroupSet(bool locally) { + if (locally) { Auth().data().setGroupStickersSectionHidden(_megagroupSet->id); Local::writeUserSettings(); refreshStickers(); @@ -1675,4 +1715,6 @@ void StickersListWidget::removeSet(uint64 setId) { } } +StickersListWidget::~StickersListWidget() = default; + } // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index e81740e445..b25a1829c5 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -62,6 +62,8 @@ public: void notInstalledLocally(uint64 setId); void clearInstalledLocally(); + ~StickersListWidget(); + protected: void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; @@ -148,7 +150,7 @@ private: void displaySet(uint64 setId); void installSet(uint64 setId); - void removeMegagroupSet(bool empty); + void removeMegagroupSet(bool locally); void removeSet(uint64 setId); bool setHasTitle(const Set &set) const; diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.cpp b/Telegram/SourceFiles/ui/widgets/input_fields.cpp index 13ad489d5e..a1cd85ce23 100644 --- a/Telegram/SourceFiles/ui/widgets/input_fields.cpp +++ b/Telegram/SourceFiles/ui/widgets/input_fields.cpp @@ -3435,7 +3435,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) { auto placeholderTop = anim::interpolate(0, _st.placeholderShift, placeholderShiftDegree); - QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins)); + QRect r(rect().marginsRemoved(_textMargins + _st.placeholderMargins)); r.moveTop(r.top() + placeholderTop); if (rtl()) r.moveLeft(width() - r.left() - r.width()); @@ -3460,7 +3460,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) { auto placeholderLeft = anim::interpolate(0, -_st.placeholderShift, placeholderHiddenDegree); - QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins)); + QRect r(rect().marginsRemoved(_textMargins + _st.placeholderMargins)); r.moveLeft(r.left() + placeholderLeft); if (rtl()) r.moveLeft(width() - r.left() - r.width()); @@ -3469,6 +3469,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) { p.drawText(r, _placeholder, _st.placeholderAlign); p.restore(); + p.setOpacity(1.); } } @@ -3525,7 +3526,7 @@ void MaskedInputField::resizeEvent(QResizeEvent *e) { void MaskedInputField::refreshPlaceholder() { auto placeholderText = _placeholderFactory ? _placeholderFactory() : QString(); - auto availableWidth = width() - _st.textMargins.left() - _st.textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1; + auto availableWidth = width() - _textMargins.left() - _textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1; if (_st.placeholderScale > 0.) { auto placeholderFont = _st.placeholderFont->f; placeholderFont.setStyleStrategy(QFont::PreferMatch); @@ -3609,7 +3610,7 @@ void MaskedInputField::startPlaceholderAnimation() { } QRect MaskedInputField::placeholderRect() const { - return rect().marginsRemoved(_st.textMargins + _st.placeholderMargins); + return rect().marginsRemoved(_textMargins + _st.placeholderMargins); } void MaskedInputField::placeholderAdditionalPrepare(Painter &p, TimeMs ms) { @@ -3893,8 +3894,12 @@ void PortInput::correctValue(const QString &was, int32 wasCursor, QString &now, setCorrectedText(now, nowCursor, newText, newPos); } -UsernameInput::UsernameInput(QWidget *parent, const style::InputField &st, base::lambda placeholderFactory, const QString &val, bool isLink) : MaskedInputField(parent, st, std::move(placeholderFactory), val) -, _linkPlaceholder(isLink ? Messenger::Instance().createInternalLink(QString()) : QString()) { +UsernameInput::UsernameInput(QWidget *parent, const style::InputField &st, base::lambda placeholderFactory, const QString &val, bool isLink) : MaskedInputField(parent, st, std::move(placeholderFactory), val) { + setLinkPlaceholder(isLink ? Messenger::Instance().createInternalLink(QString()) : QString()); +} + +void UsernameInput::setLinkPlaceholder(const QString &placeholder) { + _linkPlaceholder = placeholder; if (!_linkPlaceholder.isEmpty()) { setTextMargins(style::margins(_st.textMargins.left() + _st.font->width(_linkPlaceholder), _st.textMargins.top(), _st.textMargins.right(), _st.textMargins.bottom())); setPlaceholderHidden(true); diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.h b/Telegram/SourceFiles/ui/widgets/input_fields.h index 49f0d40f05..b9eeb885de 100644 --- a/Telegram/SourceFiles/ui/widgets/input_fields.h +++ b/Telegram/SourceFiles/ui/widgets/input_fields.h @@ -878,6 +878,8 @@ class UsernameInput : public MaskedInputField { public: UsernameInput(QWidget *parent, const style::InputField &st, base::lambda placeholderFactory, const QString &val, bool isLink); + void setLinkPlaceholder(const QString &placeholder); + protected: void correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) override; void paintAdditionalPlaceholder(Painter &p, TimeMs ms) override;