From 70f92a7817c4cec6ebc8983cb8d4e5f3d58214e0 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 29 Mar 2021 20:37:03 +0300 Subject: [PATCH] Added initial masks tab to manage stickers box. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/boxes/stickers_box.cpp | 206 +++++++++++++------- Telegram/SourceFiles/boxes/stickers_box.h | 8 +- 3 files changed, 145 insertions(+), 70 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 84c31d5017..9304a878af 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1390,6 +1390,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_box_remove" = "Remove"; "lng_stickers_installed_tab" = "Stickers"; +"lng_stickers_masks_tab" = "Masks"; "lng_stickers_featured_tab" = "Trending"; "lng_stickers_archived_tab" = "Archived"; "lng_stickers_remove_pack" = "Remove «{sticker_pack}»?"; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index c4f311abcb..f2a50080cb 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -239,7 +239,8 @@ private: const not_null _controller; MTP::Sender _api; - Section _section; + const Section _section; + const bool _isInstalled; int32 _rowHeight; @@ -351,7 +352,7 @@ void StickersBox::Tab::returnWidget(object_ptr widget) { Assert(_widget == _weak); } -StickersBox::Inner *StickersBox::Tab::widget() { +StickersBox::Inner *StickersBox::Tab::widget() const { return _weak; } @@ -375,8 +376,9 @@ StickersBox::StickersBox( controller->session().data().stickers().featuredSetsUnreadCountValue()) , _section(section) , _installed(0, this, controller, Section::Installed) -, _featured(1, this, controller, Section::Featured) -, _archived(2, this, controller, Section::Archived) { +, _masks(1, this, controller, Section::Masks) +, _featured(2, this, controller, Section::Featured) +, _archived(3, this, controller, Section::Archived) { _tabs->setRippleTopRoundRadius(st::boxRadius); } @@ -534,21 +536,33 @@ void StickersBox::prepare() { lifetime()); refreshTabs(); } - if (_installed.widget() && _section != Section::Installed) _installed.widget()->hide(); - if (_featured.widget() && _section != Section::Featured) _featured.widget()->hide(); - if (_archived.widget() && _section != Section::Archived) _archived.widget()->hide(); - if (_attached.widget() && _section != Section::Attached) _attached.widget()->hide(); + if (_installed.widget() && _section != Section::Installed) { + _installed.widget()->hide(); + } + if (_masks.widget() && _section != Section::Masks) { + _masks.widget()->hide(); + } + if (_featured.widget() && _section != Section::Featured) { + _featured.widget()->hide(); + } + if (_archived.widget() && _section != Section::Archived) { + _archived.widget()->hide(); + } + if (_attached.widget() && _section != Section::Attached) { + _attached.widget()->hide(); + } + const auto installCallback = [=](uint64 setId) { installSet(setId); }; if (_featured.widget()) { - _featured.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); }); + _featured.widget()->setInstallSetCallback(installCallback); } if (_archived.widget()) { - _archived.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); }); - _archived.widget()->setLoadMoreCallback([this] { loadMoreArchived(); }); + _archived.widget()->setInstallSetCallback(installCallback); + _archived.widget()->setLoadMoreCallback([=] { loadMoreArchived(); }); } if (_attached.widget()) { - _attached.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); }); - _attached.widget()->setLoadMoreCallback([this] { showAttachedStickers(); }); + _attached.widget()->setInstallSetCallback(installCallback); + _attached.widget()->setLoadMoreCallback([=] { showAttachedStickers(); }); } if (_megagroupSet) { @@ -565,6 +579,8 @@ void StickersBox::prepare() { if (_section == Section::Installed) { _tab = &_installed; + } else if (_section == Section::Masks) { + _tab = &_masks; } else if (_section == Section::Archived) { _tab = &_archived; } else if (_section == Section::Attached) { @@ -580,18 +596,21 @@ void StickersBox::prepare() { [this] { handleStickersUpdated(); }, lifetime()); session().api().updateStickers(); + session().api().updateMasks(); - if (_installed.widget()) { - _installed.widget()->draggingScrollDelta( - ) | rpl::start_with_next([=](int delta) { - scrollByDraggingDelta(delta); - }, _installed.widget()->lifetime()); - if (!_megagroupSet) { - boxClosing() | rpl::start_with_next([=] { - saveChanges(); - }, lifetime()); + for (const auto &widget : { _installed.widget(), _masks.widget() }) { + if (widget) { + widget->draggingScrollDelta( + ) | rpl::start_with_next([=](int delta) { + scrollByDraggingDelta(delta); + }, widget->lifetime()); } } + if (!_megagroupSet) { + boxClosing() | rpl::start_with_next([=] { + saveChanges(); + }, lifetime()); + } if (_tabs) { _tabs->raise(); @@ -607,6 +626,10 @@ void StickersBox::refreshTabs() { auto sections = std::vector(); sections.push_back(tr::lng_stickers_installed_tab(tr::now).toUpper()); _tabIndices.push_back(Section::Installed); + if (!session().data().stickers().maskSetsOrder().isEmpty()) { + sections.push_back(tr::lng_stickers_masks_tab(tr::now).toUpper()); + _tabIndices.push_back(Section::Masks); + } if (!session().data().stickers().featuredSetsOrder().isEmpty()) { sections.push_back(tr::lng_stickers_featured_tab(tr::now).toUpper()); _tabIndices.push_back(Section::Featured); @@ -617,12 +640,15 @@ void StickersBox::refreshTabs() { } _tabs->setSections(sections); if ((_tab == &_archived && !_tabIndices.contains(Section::Archived)) - || (_tab == &_featured && !_tabIndices.contains(Section::Featured))) { + || (_tab == &_featured && !_tabIndices.contains(Section::Featured)) + || (_tab == &_masks && !_tabIndices.contains(Section::Masks))) { switchTab(); } else if (_tab == &_archived) { _tabs->setActiveSectionFast(_tabIndices.indexOf(Section::Archived)); } else if (_tab == &_featured) { _tabs->setActiveSectionFast(_tabIndices.indexOf(Section::Featured)); + } else if (_tab == &_masks) { + _tabs->setActiveSectionFast(_tabIndices.indexOf(Section::Masks)); } updateTabsGeometry(); } @@ -674,13 +700,15 @@ void StickersBox::paintEvent(QPaintEvent *e) { void StickersBox::updateTabsGeometry() { if (!_tabs) return; - _tabs->resizeToWidth(_tabIndices.size() * width() / 3); + const auto maxTabs = 4; + + _tabs->resizeToWidth(_tabIndices.size() * width() / maxTabs); _unreadBadge->setVisible(_tabIndices.contains(Section::Featured)); setInnerTopSkip(getTopSkip()); - auto featuredLeft = width() / 3; - auto featuredRight = 2 * width() / 3; + auto featuredLeft = width() / maxTabs; + auto featuredRight = 2 * width() / maxTabs; auto featuredTextWidth = st::stickersTabs.labelStyle.font->width(tr::lng_stickers_featured_tab(tr::now).toUpper()); auto featuredTextRight = featuredLeft + (featuredRight - featuredLeft - featuredTextWidth) / 2 + featuredTextWidth; auto unreadBadgeLeft = featuredTextRight - st::stickersFeaturedBadgeSkip; @@ -712,6 +740,9 @@ void StickersBox::switchTab() { } else if (newSection == Section::Archived) { newTab = &_archived; requestArchivedSets(); + } else if (newSection == Section::Masks) { + newTab = &_masks; + session().api().updateMasks(); } if (_tab == newTab) { onScrollToY(0); @@ -744,7 +775,7 @@ void StickersBox::switchTab() { _slideAnimation = std::make_unique(); _slideAnimation->setSnapshots(std::move(wasCache), std::move(nowCache)); auto slideLeft = wasIndex > nowIndex; - _slideAnimation->start(slideLeft, [this] { update(); }, st::slideDuration); + _slideAnimation->start(slideLeft, [=] { update(); }, st::slideDuration); setInnerVisible(false); setFocus(); @@ -758,6 +789,16 @@ QPixmap StickersBox::grabContentCache() { return result; } +std::array StickersBox::widgets() const { + return { + _installed.widget(), + _featured.widget(), + _archived.widget(), + _attached.widget(), + _masks.widget() + }; +} + void StickersBox::installSet(uint64 setId) { const auto &sets = session().data().stickers().sets(); const auto it = sets.find(setId); @@ -769,10 +810,11 @@ void StickersBox::installSet(uint64 setId) { const auto set = it->second.get(); if (_localRemoved.contains(setId)) { _localRemoved.removeOne(setId); - if (_installed.widget()) _installed.widget()->setRemovedSets(_localRemoved); - if (_featured.widget()) _featured.widget()->setRemovedSets(_localRemoved); - if (_archived.widget()) _archived.widget()->setRemovedSets(_localRemoved); - if (_attached.widget()) _attached.widget()->setRemovedSets(_localRemoved); + for (const auto &widget : widgets()) { + if (widget) { + widget->setRemovedSets(_localRemoved); + } + } } if (!(set->flags & MTPDstickerSet::Flag::f_installed_date) || (set->flags & MTPDstickerSet::Flag::f_archived)) { @@ -850,14 +892,17 @@ void StickersBox::resizeEvent(QResizeEvent *e) { if (_titleShadow) { _titleShadow->setGeometry(0, 0, width(), st::lineWidth); } - if (_installed.widget()) _installed.widget()->resize(width(), _installed.widget()->height()); - if (_featured.widget()) _featured.widget()->resize(width(), _featured.widget()->height()); - if (_archived.widget()) _archived.widget()->resize(width(), _archived.widget()->height()); - if (_attached.widget()) _attached.widget()->resize(width(), _attached.widget()->height()); + for (const auto &widget : widgets()) { + if (widget) { + widget->resize(width(), widget->height()); + } + } } void StickersBox::handleStickersUpdated() { - if (_section == Section::Installed || _section == Section::Featured) { + if (_section == Section::Installed + || _section == Section::Featured + || _section == Section::Masks) { rebuildList(); } else { _tab->widget()->updateRows(); @@ -870,15 +915,19 @@ void StickersBox::handleStickersUpdated() { } void StickersBox::rebuildList(Tab *tab) { - if (_section == Section::Attached) return; - if (!tab) tab = _tab; + if (_section == Section::Attached) { + return; + } + if (!tab) { + tab = _tab; + } - if (tab == &_installed) { + if ((tab == &_installed) || (tab == &_masks)) { _localOrder = tab->widget()->getFullOrder(); _localRemoved = tab->widget()->getRemovedSets(); } tab->widget()->rebuild(); - if (tab == &_installed) { + if ((tab == &_installed) || (tab == &_masks)) { tab->widget()->setFullOrder(_localOrder); } tab->widget()->setRemovedSets(_localRemoved); @@ -887,11 +936,21 @@ void StickersBox::rebuildList(Tab *tab) { void StickersBox::saveChanges() { // Make sure that our changes in other tabs are applied in the Installed tab. rebuildList(&_installed); + rebuildList(&_masks); if (_someArchivedLoaded) { session().local().writeArchivedStickers(); } - session().api().saveStickerSets(_installed.widget()->getOrder(), _installed.widget()->getRemovedSets()); + if (const auto widget = _installed.widget()) { + session().api().saveStickerSets( + widget->getOrder(), + widget->getRemovedSets()); + } + if (const auto widget = _masks.widget()) { + session().api().saveStickerSets( + widget->getOrder(), + widget->getRemovedSets()); + } } void StickersBox::setInnerFocus() { @@ -932,7 +991,8 @@ StickersBox::Inner::Row::Row( StickersBox::Inner::Row::~Row() = default; bool StickersBox::Inner::Row::isRecentSet() const { - return (set->id == Data::Stickers::CloudRecentSetId); + return (set->id == Data::Stickers::CloudRecentSetId) + || (set->id == Data::Stickers::CloudRecentAttachedSetId); } StickersBox::Inner::Inner( @@ -943,6 +1003,7 @@ StickersBox::Inner::Inner( , _controller(controller) , _api(&_controller->session().mtp()) , _section(section) +, _isInstalled(_section == Section::Installed || _section == Section::Masks) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _shiftingAnimation([=](crl::time now) { return shiftingAnimationCallback(now); @@ -963,6 +1024,7 @@ StickersBox::Inner::Inner( , _controller(controller) , _api(&_controller->session().mtp()) , _section(StickersBox::Section::Installed) +, _isInstalled(_section == Section::Installed || _section == Section::Masks) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _shiftingAnimation([=](crl::time now) { return shiftingAnimationCallback(now); @@ -1087,8 +1149,10 @@ QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const { auto buttonh = st::stickersRemove.height; auto buttonshift = st::stickersRemoveSkip; if (!removeButton) { - auto &st = (_section == Section::Installed) ? st::stickersUndoRemove : st::stickersTrendingAdd; - auto textWidth = (_section == Section::Installed) ? _undoWidth : _addWidth; + const auto &st = _isInstalled + ? st::stickersUndoRemove + : st::stickersTrendingAdd; + const auto textWidth = _isInstalled ? _undoWidth : _addWidth; buttonw = textWidth - st.width; buttonh = st.height; buttonshift = 0; @@ -1117,7 +1181,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null row, int index) { } } - if (_section == Section::Installed) { + if (_isInstalled) { if (index >= 0 && index == _above) { auto current = _aboveShadowFadeOpacity.current(); if (_started >= 0) { @@ -1144,13 +1208,13 @@ void StickersBox::Inner::paintRow(Painter &p, not_null row, int index) { paintFakeButton(p, row, index); } - if (row->removed && _section == Section::Installed) { + if (row->removed && _isInstalled) { p.setOpacity(st::stickersRowDisabledOpacity); } auto stickerx = st::contactsPadding.left(); - if (!_megagroupSet && _section == Section::Installed) { + if (!_megagroupSet && _isInstalled) { stickerx += st::stickersReorderIcon.width() + st::stickersReorderSkip; if (!row->isRecentSet()) { st::stickersReorderIcon.paint(p, st::contactsPadding.left(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width()); @@ -1281,7 +1345,7 @@ void StickersBox::Inner::updateRowThumbnail(not_null row) { Unexpected("StickersBox::Inner::updateRowThumbnail: row not found"); }(); const auto left = st::contactsPadding.left() - + ((!_megagroupSet && _section == Section::Installed) + + ((!_megagroupSet && _isInstalled) ? st::stickersReorderIcon.width() + st::stickersReorderSkip : 0); update( @@ -1292,9 +1356,9 @@ void StickersBox::Inner::updateRowThumbnail(not_null row) { } void StickersBox::Inner::paintFakeButton(Painter &p, not_null row, int index) { - auto removeButton = (_section == Section::Installed && !row->removed); + auto removeButton = (_isInstalled && !row->removed); auto rect = relativeButtonRect(removeButton); - if (_section != Section::Installed && row->installed && !row->archived && !row->removed) { + if (!_isInstalled && row->installed && !row->archived && !row->removed) { // Checkbox after installed from Trending or Archived. int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (rect.width() + st::stickersFeaturedInstalled.width()) / 2); int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2; @@ -1317,10 +1381,12 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null row, int ind } else { // Round button ADD when not installed from Trending or Archived. // Or round button UNDO after disabled from Installed. - auto &st = (_section == Section::Installed) ? st::stickersUndoRemove : st::stickersTrendingAdd; - auto textWidth = (_section == Section::Installed) ? _undoWidth : _addWidth; - auto &text = (_section == Section::Installed) ? _undoText : _addText; - auto &textBg = selected ? st.textBgOver : st.textBg; + const auto &st = _isInstalled + ? st::stickersUndoRemove + : st::stickersTrendingAdd; + const auto textWidth = _isInstalled ? _undoWidth : _addWidth; + const auto &text = _isInstalled ? _undoText : _addText; + const auto &textBg = selected ? st.textBgOver : st.textBg; Ui::FillRoundRect(p, myrtlrect(rect), textBg, ImageRoundRadius::Small); if (row->ripple) { row->ripple->paint(p, rect.x(), rect.y(), width()); @@ -1345,7 +1411,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) { setActionDown(_actionSel); update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight); } else if (auto selectedIndex = std::get_if(&_selected)) { - if (_section == Section::Installed && !_rows[*selectedIndex]->isRecentSet() && _inDragArea) { + if (_isInstalled && !_rows[*selectedIndex]->isRecentSet() && _inDragArea) { _above = _dragging = _started = *selectedIndex; _dragStart = mapFromGlobal(_mouse); } @@ -1367,9 +1433,9 @@ void StickersBox::Inner::setActionDown(int newActionDown) { if (_actionDown >= 0 && _actionDown < _rows.size()) { update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight); const auto row = _rows[_actionDown].get(); - auto removeButton = (_section == Section::Installed && !row->removed); + auto removeButton = (_isInstalled && !row->removed); if (!row->ripple) { - if (_section == Section::Installed) { + if (_isInstalled) { if (row->removed) { auto rippleSize = QSize(_undoWidth - st::stickersUndoRemove.width, st::stickersUndoRemove.height); auto rippleMask = Ui::RippleAnimation::roundRectMask(rippleSize, st::roundRadiusSmall); @@ -1512,14 +1578,14 @@ void StickersBox::Inner::updateSelected() { selected = selectedIndex; local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight); const auto row = _rows[selectedIndex].get(); - if (!_megagroupSet && (_section == Section::Installed || !row->installed || row->archived || row->removed)) { - auto removeButton = (_section == Section::Installed && !row->removed); + if (!_megagroupSet && (_isInstalled || !row->installed || row->archived || row->removed)) { + auto removeButton = (_isInstalled && !row->removed); auto rect = myrtlrect(relativeButtonRect(removeButton)); actionSel = rect.contains(local) ? selectedIndex : -1; } else { actionSel = -1; } - if (!_megagroupSet && _section == Section::Installed && !row->isRecentSet()) { + if (!_megagroupSet && _isInstalled && !row->isRecentSet()) { auto dragAreaWidth = st::contactsPadding.left() + st::stickersReorderIcon.width() + st::stickersReorderSkip; auto dragArea = myrtlrect(0, 0, dragAreaWidth, _rowHeight); inDragArea = dragArea.contains(local); @@ -1543,7 +1609,7 @@ void StickersBox::Inner::updateSelected() { void StickersBox::Inner::updateCursor() { setCursor(_inDragArea ? style::cur_sizeall - : (!_megagroupSet && _section == Section::Installed) + : (!_megagroupSet && _isInstalled) ? ((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel)) ? style::cur_pointer : style::cur_default) @@ -1568,7 +1634,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) { _mouse = e->globalPos(); updateSelected(); if (_actionDown == _actionSel && _actionSel >= 0) { - if (_section == Section::Installed) { + if (_isInstalled) { setRowRemoved(_actionDown, !_rows[_actionDown]->removed); } else if (_installSetCallback) { _installSetCallback(_rows[_actionDown]->set->id); @@ -1859,6 +1925,8 @@ void StickersBox::Inner::rebuild() { return session().data().stickers().featuredSetsOrder(); } return result; + } else if (_section == Section::Masks) { + return session().data().stickers().maskSetsOrder(); } else if (_section == Section::Featured) { return session().data().stickers().featuredSetsOrder(); } @@ -1874,8 +1942,10 @@ void StickersBox::Inner::rebuild() { ? tr::lng_stickers_group_from_featured(tr::now) : tr::lng_stickers_group_from_your(tr::now)); updateControlsGeometry(); - } else if (_section == Section::Installed) { - auto cloudIt = sets.find(Data::Stickers::CloudRecentSetId); + } else if (_isInstalled) { + const auto cloudIt = sets.find((_section == Section::Masks) + ? Data::Stickers::CloudRecentAttachedSetId + : Data::Stickers::CloudRecentSetId); // Section::Installed. if (cloudIt != sets.cend() && !cloudIt->second->stickers.isEmpty()) { rebuildAppendSet(cloudIt->second.get(), maxNameWidth); } @@ -1944,7 +2014,7 @@ void StickersBox::Inner::updateRows() { auto wasInstalled = row->installed; auto wasArchived = row->archived; fillSetFlags(set, &row->installed, &row->official, &row->unread, &row->archived); - if (_section == Section::Installed) { + if (_isInstalled) { row->archived = false; } if (row->installed != wasInstalled || row->archived != wasArchived) { @@ -1969,11 +2039,11 @@ bool StickersBox::Inner::appendSet(not_null set) { int StickersBox::Inner::countMaxNameWidth() const { int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); - if (!_megagroupSet && _section == Section::Installed) { + if (!_megagroupSet && _isInstalled) { namex += st::stickersReorderIcon.width() + st::stickersReorderSkip; } int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); - if (_section == Section::Installed) { + if (_isInstalled) { if (!_megagroupSet) { namew -= _undoWidth - st::stickersUndoRemove.width; } @@ -1993,7 +2063,7 @@ void StickersBox::Inner::rebuildAppendSet( if (set->id != Data::Stickers::CloudRecentSetId) { fillSetFlags(set, &installed, &official, &unread, &archived); } - if (_section == Section::Installed && archived) { + if (_isInstalled && archived) { return; } diff --git a/Telegram/SourceFiles/boxes/stickers_box.h b/Telegram/SourceFiles/boxes/stickers_box.h index ae9fc8b5bc..56cbc7d199 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.h +++ b/Telegram/SourceFiles/boxes/stickers_box.h @@ -56,6 +56,7 @@ public: Featured, Archived, Attached, + Masks, }; StickersBox( @@ -94,7 +95,7 @@ private: object_ptr takeWidget(); void returnWidget(object_ptr widget); - [[nodiscard]] Inner *widget(); + [[nodiscard]] Inner *widget() const; [[nodiscard]] int index() const; void saveScrollTop(); @@ -103,7 +104,7 @@ private: } private: - int _index = 0; + const int _index = 0; object_ptr _widget = { nullptr }; QPointer _weak; int _scrollTop = 0; @@ -132,6 +133,8 @@ private: uint64 offsetId); void showAttachedStickers(); + std::array widgets() const; + const not_null _controller; MTP::Sender _api; @@ -144,6 +147,7 @@ private: Section _section; Tab _installed; + Tab _masks; Tab _featured; Tab _archived; Tab _attached;