diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index bfbde65f1b..43c72f429c 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -683,7 +683,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_stickers_share_pack" = "Share Stickers"; "lng_stickers_not_found" = "Sticker pack not found."; "lng_stickers_packs_archived" = "Some of your unused stickers have been archived to make room for the sets you've activated."; -"lng_stickers_archived" = "Archived stickers"; +"lng_stickers_archived" = "Archived Stickers"; "lng_stickers_copied" = "Sticker pack link copied to clipboard."; "lng_stickers_default_set" = "Great Minds"; "lng_stickers_you_have" = "Manage and reorder sticker packs"; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index f3c85d3e23..f8320b6230 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2028,6 +2028,7 @@ namespace { Global::SetFeaturedStickerSetsOrder(Stickers::Order()); Global::SetFeaturedStickerSetsUnreadCount(0); Global::SetLastFeaturedStickersUpdate(0); + Global::SetArchivedStickerSetsOrder(Stickers::Order()); cSetSavedGifs(SavedGifs()); cSetLastSavedGifsUpdate(0); cSetReportSpamStatuses(ReportSpamStatuses()); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index a1df6f9573..2d8d02d194 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -31,6 +31,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "dialogs/dialogs_layout.h" #include "styles/style_boxes.h" +namespace { + +constexpr int kArchivedLimitFirstRequest = 10; +constexpr int kArchivedLimitPerPage = 30; + +} // namespace + namespace Stickers { void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { @@ -58,6 +65,7 @@ void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { } App::api()->requestStickerSets(); } + Local::writeArchivedStickers(); Ui::showLayer(new StickersBox(archived), KeepOtherLayers); } @@ -153,6 +161,13 @@ bool StickerSetInner::failedSet(const RPCError &error) { void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &result) { auto &sets = Global::RefStickerSets(); + bool wasArchived = (_setFlags & MTPDstickerSet::Flag::f_archived); + if (wasArchived) { + auto index = Global::RefArchivedStickerSetsOrder().indexOf(_setId); + if (index >= 0) { + Global::RefArchivedStickerSetsOrder().removeAt(index); + } + } _setFlags &= ~MTPDstickerSet::Flag::f_archived; _setFlags |= MTPDstickerSet::Flag::f_installed; auto it = sets.find(_setId); @@ -186,6 +201,8 @@ void StickerSetInner::installDone(const MTPmessages_StickerSetInstallResult &res if (result.type() == mtpc_messages_stickerSetInstallResultArchive) { Stickers::applyArchivedResult(result.c_messages_stickerSetInstallResultArchive()); + } else if (wasArchived) { + Local::writeArchivedStickers(); } Local::writeInstalledStickers(); @@ -483,24 +500,22 @@ void StickersInner::setup() { setMouseTracking(true); } -void StickersInner::paintFeaturedButton(Painter &p) const { - if (!_featuredHeight) return; - - if (_selected == -1) { - p.fillRect(0, st::membersPadding.top(), width(), _featuredHeight, st::contactsBgOver); +void StickersInner::paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const { + if (selected) { + p.fillRect(0, y, width(), _buttonHeight, st::contactsBgOver); } p.setFont(st::stickersFeaturedFont); p.setPen(st::stickersFeaturedPen); - p.drawTextLeft(st::stickersFeaturedPosition.x(), st::membersPadding.top() + st::stickersFeaturedPosition.y(), width(), lang(lng_stickers_featured)); + p.drawTextLeft(st::stickersFeaturedPosition.x(), y + st::stickersFeaturedPosition.y(), width(), text); - if (auto unread = Global::FeaturedStickerSetsUnreadCount()) { + if (badgeCounter) { Dialogs::Layout::UnreadBadgeStyle unreadSt; unreadSt.sizeId = Dialogs::Layout::UnreadBadgeInStickersBox; unreadSt.size = st::stickersFeaturedBadgeSize; int unreadRight = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x()); if (rtl()) unreadRight = width() - unreadRight; - int unreadTop = st::membersPadding.top() + (_featuredHeight - st::stickersFeaturedBadgeSize) / 2; - Dialogs::Layout::paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, unreadSt); + int unreadTop = y + (_buttonHeight - st::stickersFeaturedBadgeSize) / 2; + Dialogs::Layout::paintUnreadCount(p, QString::number(badgeCounter), unreadRight, unreadTop, unreadSt); } } @@ -513,12 +528,22 @@ void StickersInner::paintEvent(QPaintEvent *e) { p.fillRect(r, st::white); p.setClipRect(r); - paintFeaturedButton(p); + int y = st::membersPadding.top(); + if (_hasFeaturedButton) { + auto selected = (_selected == -2); + paintButton(p, y, selected, lang(lng_stickers_featured), Global::FeaturedStickerSetsUnreadCount()); + y += _buttonHeight; + } + if (_hasArchivedButton) { + auto selected = (_selected == -1); + paintButton(p, y, selected, lang(lng_stickers_archived), 0); + y += _buttonHeight; + } if (_rows.isEmpty()) { p.setFont(st::noContactsFont); p.setPen(st::noContactsColor); - p.drawText(QRect(0, _featuredHeight, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); + p.drawText(QRect(0, y, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); } else { p.translate(0, _itemsTop); @@ -708,13 +733,15 @@ void StickersInner::onUpdateSelected() { QRect add(myrtlrect(addx, addy, addw, st::stickersAddSize.height())); actionSel = add.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1; } - } else if (_featuredHeight && QRect(0, st::membersPadding.top(), width(), _featuredHeight).contains(local)) { + } else if (_hasFeaturedButton && QRect(0, st::membersPadding.top(), width(), _buttonHeight).contains(local)) { + selected = -2; + } else if (_hasArchivedButton && QRect(0, st::membersPadding.top() + (_hasFeaturedButton ? _buttonHeight : 0), width(), _buttonHeight).contains(local)) { selected = -1; } else { - selected = -2; + selected = -3; } if (_selected != selected) { - if ((_selected == -1) != (selected == -1)) { + if (((_selected == -1) != (selected == -1)) || ((_selected == -2) != (selected == -2))) { update(); } if (_section != Section::Installed && ((_selected >= 0 || _pressed >= 0) != (selected >= 0 || _pressed >= 0))) { @@ -800,14 +827,17 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) { _dragging = _started = -1; } else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) { - if (_selected == -1) { - _selected = -2; + if (_selected == -2) { + _selected = -3; Ui::showLayer(new StickersBox(Section::Featured), KeepOtherLayers); + } else if (_selected == -1) { + _selected = -3; + Ui::showLayer(new StickersBox(Section::Archived), KeepOtherLayers); } else if (_selected >= 0 && _section != Section::Installed) { auto &sets = Global::RefStickerSets(); auto it = sets.find(_rows.at(pressed)->id); if (it != sets.cend()) { - _selected = -2; + _selected = -3; Ui::showLayer(new StickerSetBox(Stickers::inputSetId(*it)), KeepOtherLayers); } } @@ -859,6 +889,13 @@ void StickersInner::installSet(uint64 setId) { } Local::writeInstalledStickers(); if (changedFlags & MTPDstickerSet_ClientFlag::f_unread) Local::writeFeaturedStickers(); + if (changedFlags & MTPDstickerSet::Flag::f_archived) { + auto index = Global::RefArchivedStickerSetsOrder().indexOf(setId); + if (index >= 0) { + Global::RefArchivedStickerSetsOrder().removeAt(index); + Local::writeArchivedStickers(); + } + } emit App::main()->stickersUpdated(); } @@ -960,8 +997,8 @@ void StickersInner::clear() { _aboveShadowFadeOpacity = anim::fvalue(0, 0); _a_shifting.stop(); _above = _dragging = _started = -1; - _selected = -2; - _pressed = -2; + _selected = -3; + _pressed = -3; _actionDown = -1; setActionSel(-1); update(); @@ -979,22 +1016,24 @@ void StickersInner::setActionSel(int32 actionSel) { } void StickersInner::rebuild() { - QList rows, rowsDisabled; - + _hasFeaturedButton = _hasArchivedButton = false; _itemsTop = st::membersPadding.top(); - _featuredHeight = 0; - if (_section == Section::Installed && !Global::FeaturedStickerSetsOrder().isEmpty()) { - _featuredHeight = st::stickersFeaturedHeight; - _itemsTop += _featuredHeight + st::membersPadding.top(); + _buttonHeight = st::stickersFeaturedHeight; + if (_section == Section::Installed) { + if (!Global::FeaturedStickerSetsOrder().isEmpty()) { + _itemsTop += _buttonHeight; + _hasFeaturedButton = true; + } + if (!Global::ArchivedStickerSetsOrder().isEmpty()) { + _itemsTop += _buttonHeight; + _hasArchivedButton = true; + } + if (_itemsTop > st::membersPadding.top()) { + _itemsTop += st::membersPadding.top(); + } } - int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); - int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); - if (_section == Section::Installed) { - namew -= qMax(qMax(qMax(_returnWidth, _removeWidth), _restoreWidth), _clearWidth); - } else { - namew -= _addWidth - st::defaultActiveButton.width; - } + int maxNameWidth = countMaxNameWidth(); clear(); auto &order = ([this]() { @@ -1002,6 +1041,8 @@ void StickersInner::rebuild() { return Global::StickerSetsOrder(); } else if (_section == Section::Featured) { return Global::FeaturedStickerSetsOrder(); + } else if (_section == Section::Archived) { + return Global::ArchivedStickerSetsOrder(); } return _archivedIds; })(); @@ -1012,7 +1053,7 @@ void StickersInner::rebuild() { if (_section == Section::Installed) { auto cloudIt = sets.constFind(Stickers::CloudRecentSetId); if (cloudIt != sets.cend() && !cloudIt->stickers.isEmpty()) { - rebuildAppendSet(cloudIt.value(), namew); + rebuildAppendSet(cloudIt.value(), maxNameWidth); } } for_const (auto setId, order) { @@ -1021,14 +1062,14 @@ void StickersInner::rebuild() { continue; } - rebuildAppendSet(it.value(), namew); + rebuildAppendSet(it.value(), maxNameWidth); if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { App::api()->scheduleStickerSetRequest(it->id, it->access); } } App::api()->requestStickerSets(); - resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom()); + updateSize(); if (_section == Section::Featured && Global::FeaturedStickerSetsUnreadCount()) { Global::SetFeaturedStickerSetsUnreadCount(0); @@ -1039,52 +1080,106 @@ void StickersInner::rebuild() { } } -void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) { - bool recent = (set.id == Stickers::CloudRecentSetId); - bool installed = true; - bool official = true; - bool unread = false; - bool disabled = false; - if (!recent) { - installed = (set.flags & MTPDstickerSet::Flag::f_installed); - official = (set.flags & MTPDstickerSet::Flag::f_official); - disabled = (set.flags & MTPDstickerSet::Flag::f_archived); - if (_section == Section::Featured) { - unread = _unreadSets.contains(set.id); - if (!unread && (set.flags & MTPDstickerSet_ClientFlag::f_unread)) { - unread = true; - _unreadSets.insert(set.id); +void StickersInner::updateSize() { + resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom()); +} + +void StickersInner::updateRows() { + int maxNameWidth = countMaxNameWidth(); + auto &sets = Global::StickerSets(); + 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; + fillSetCover(set, &sticker, &pixw, &pixh); + if (sticker) { + row->sticker = sticker; + row->pixw = pixw; + row->pixh = pixh; + } } - } else if (_section == Section::Installed && disabled) { - return; + fillSetFlags(set, &row->recent, &row->installed, &row->official, &row->unread, &row->disabled); + if (_section == Section::Installed) { + row->disabled = false; + } + row->title = fillSetTitle(set, maxNameWidth); + row->count = fillSetCount(set); } } + update(); +} - auto sticker = set.stickers.at(0); - int32 pixw = 0, pixh = 0; - if (sticker) { - pixw = sticker->thumb->width(); - pixh = sticker->thumb->height(); - if (pixw > st::contactsPhotoSize) { - if (pixw > pixh) { - pixh = (pixh * st::contactsPhotoSize) / pixw; - pixw = st::contactsPhotoSize; - } else { - pixw = (pixw * st::contactsPhotoSize) / pixh; - pixh = st::contactsPhotoSize; - } - } else if (pixh > st::contactsPhotoSize) { +bool StickersInner::appendSet(const Stickers::Set &set) { + for_const (auto row, _rows) { + if (row->id == set.id) { + return false; + } + } + rebuildAppendSet(set, countMaxNameWidth()); + return true; +} + +int StickersInner::countMaxNameWidth() const { + int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); + int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); + if (_section == Section::Installed) { + namew -= qMax(qMax(qMax(_returnWidth, _removeWidth), _restoreWidth), _clearWidth); + } else { + namew -= _addWidth - st::defaultActiveButton.width; + } + return namew; +} + +void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) { + bool recent = false, installed = false, official = false, unread = false, disabled = false; + fillSetFlags(set, &recent, &installed, &official, &unread, &disabled); + if (_section == Section::Installed && disabled) { + return; + } + + DocumentData *sticker = nullptr; + int pixw = 0, pixh = 0; + fillSetCover(set, &sticker, &pixw, &pixh); + + QString title = fillSetTitle(set, maxNameWidth); + int count = fillSetCount(set); + + _rows.push_back(new StickerSetRow(set.id, sticker, count, title, installed, official, unread, disabled, recent, pixw, pixh)); + _animStartTimes.push_back(0); +} + +void StickersInner::fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const { + if (set.stickers.isEmpty()) { + *outSticker = nullptr; + *outWidth = *outHeight = 0; + return; + } + auto sticker = *outSticker = set.stickers.front(); + + auto pixw = sticker->thumb->width(); + auto pixh = sticker->thumb->height(); + if (pixw > st::contactsPhotoSize) { + if (pixw > pixh) { + pixh = (pixh * st::contactsPhotoSize) / pixw; + pixw = st::contactsPhotoSize; + } else { pixw = (pixw * st::contactsPhotoSize) / pixh; pixh = st::contactsPhotoSize; } + } else if (pixh > st::contactsPhotoSize) { + pixw = (pixw * st::contactsPhotoSize) / pixh; + pixh = st::contactsPhotoSize; } - QString title = set.title; - int32 titleWidth = st::contactsNameFont->width(title); - if (titleWidth > maxNameWidth) { - title = st::contactsNameFont->elided(title, maxNameWidth); - } - int count = set.stickers.size(), added = 0; - if (recent) { + *outWidth = pixw; + *outHeight = pixh; +} + +int StickersInner::fillSetCount(const Stickers::Set &set) const { + int result = set.stickers.isEmpty() ? set.count : set.stickers.size(), added = 0; + if (set.id == Stickers::CloudRecentSetId) { auto customIt = Global::StickerSets().constFind(Stickers::CustomSetId); if (customIt != Global::StickerSets().cend()) { added = customIt->stickers.size(); @@ -1097,8 +1192,36 @@ void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) added = cGetRecentStickers().size(); } } - _rows.push_back(new StickerSetRow(set.id, sticker, count + added, title, installed, official, unread, disabled, recent, pixw, pixh)); - _animStartTimes.push_back(0); + return result + added; +} + +QString StickersInner::fillSetTitle(const Stickers::Set &set, int maxNameWidth) const { + auto result = set.title; + int32 titleWidth = st::contactsNameFont->width(result); + if (titleWidth > maxNameWidth) { + result = st::contactsNameFont->elided(result, maxNameWidth); + } + return result; +} + +void StickersInner::fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled) { + *outRecent = (set.id == Stickers::CloudRecentSetId); + *outInstalled = true; + *outOfficial = true; + *outUnread = false; + *outDisabled = false; + if (!*outRecent) { + *outInstalled = (set.flags & MTPDstickerSet::Flag::f_installed); + *outOfficial = (set.flags & MTPDstickerSet::Flag::f_official); + *outDisabled = (set.flags & MTPDstickerSet::Flag::f_archived); + if (_section == Section::Featured) { + *outUnread = _unreadSets.contains(set.id); + if (!*outUnread && (set.flags & MTPDstickerSet_ClientFlag::f_unread)) { + *outUnread = true; + _unreadSets.insert(set.id); + } + } + } } void StickersInner::readFeaturedDone(const MTPBool &result) { @@ -1158,10 +1281,7 @@ StickersBox::StickersBox(Section section) : ItemListBox(st::boxScroll) , _section(section) , _inner(section) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) -, _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) { - if (section == Section::Archived) { - Local::readArchivedStickers(); - } +, _about(st::boxTextFont, lang((section == Section::Archived) ? lng_stickers_packs_archived : lng_stickers_reorder), _defaultOptions, _aboutWidth) { setup(); } @@ -1170,11 +1290,87 @@ StickersBox::StickersBox(const Stickers::Order &archivedIds) : ItemListBox(st::b , _inner(archivedIds) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) , _about(st::boxTextFont, lang(lng_stickers_packs_archived), _defaultOptions, _aboutWidth) { - Local::readArchivedStickers(); setup(); } +void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result) { + _archivedRequestId = 0; + if (result.type() != mtpc_messages_archivedStickers) { + return; + } + + auto &stickers = result.c_messages_archivedStickers(); + auto &archived = Global::RefArchivedStickerSetsOrder(); + if (offsetId) { + auto index = archived.indexOf(offsetId); + if (index >= 0) { + archived = archived.mid(0, index + 1); + } + } else { + archived.clear(); + } + + bool addedSet = false; + auto &v = stickers.vsets.c_vector().v; + for_const (auto &stickerSet, v) { + if (stickerSet.type() != mtpc_stickerSet) continue; + + if (auto set = Stickers::feedSet(stickerSet.c_stickerSet())) { + auto index = archived.indexOf(set->id); + if (index != archived.size() - 1) { + if (index < archived.size() - 1) { + archived.removeAt(index); + } + archived.push_back(set->id); + } + if (_section == Section::Archived) { + if (_inner->appendSet(*set)) { + addedSet = true; + if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + App::api()->scheduleStickerSetRequest(set->id, set->access); + } + } + } + } + } + if (_section == Section::Installed && !archived.isEmpty()) { + Local::writeArchivedStickers(); + rebuildList(); + } else if (_section == Section::Archived) { + if (addedSet) { + _inner->updateSize(); + setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); + _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); + App::api()->requestStickerSets(); + } else { + _allArchivedLoaded = v.isEmpty() || (offsetId != 0); + } + } + checkLoadMoreArchived(); +} + void StickersBox::setup() { + if (_section == Section::Installed) { + Local::readArchivedStickers(); + if (Global::ArchivedStickerSetsOrder().isEmpty()) { + _archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_long(0), MTP_int(kArchivedLimitFirstRequest)), rpcDone(&StickersBox::getArchivedDone, 0ULL)); + } + } else if (_section == Section::Archived) { + // Reload the archived list. + _archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_long(0), MTP_int(kArchivedLimitFirstRequest)), rpcDone(&StickersBox::getArchivedDone, 0ULL)); + + auto &sets = Global::StickerSets(); + for_const (auto setId, Global::ArchivedStickerSetsOrder()) { + auto it = sets.constFind(setId); + if (it != sets.cend()) { + if (it->stickers.isEmpty() && (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + App::api()->scheduleStickerSetRequest(setId, it->access); + } + } + } + App::api()->requestStickerSets(); + } + int bottomSkip = st::boxPadding.bottom(); if (_section == Section::Installed) { _aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom(); @@ -1194,6 +1390,9 @@ void StickersBox::setup() { _save = new BoxButton(this, lang(lng_box_ok), st::defaultBoxButton); connect(_save, SIGNAL(clicked()), this, SLOT(onClose())); + } else if (_section == Section::Archived) { + _aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom(); + _topShadow = new PlainShadow(this, st::contactsAboutShadow); } ItemListBox::init(_inner, bottomSkip, st::boxTitleHeight + _aboutHeight); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); @@ -1204,13 +1403,40 @@ void StickersBox::setup() { connect(_inner, SIGNAL(checkDraggingScroll(int)), this, SLOT(onCheckDraggingScroll(int))); connect(_inner, SIGNAL(noDraggingScroll()), this, SLOT(onNoDraggingScroll())); connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer())); + connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); _scrollTimer.setSingleShot(false); - onStickersUpdated(); + rebuildList(); prepare(); } +void StickersBox::onScroll() { + checkLoadMoreArchived(); +} + +void StickersBox::checkLoadMoreArchived() { + if (_section != Section::Archived) return; + + int scrollTop = _scroll.scrollTop(), scrollTopMax = _scroll.scrollTopMax(); + if (scrollTop + PreloadHeightsCount * _scroll.height() >= scrollTopMax) { + if (!_archivedRequestId && !_allArchivedLoaded) { + uint64 lastId = 0; + for (auto setId = Global::ArchivedStickerSetsOrder().cend(), e = Global::ArchivedStickerSetsOrder().cbegin(); setId != e;) { + --setId; + auto it = Global::StickerSets().constFind(*setId); + if (it != Global::StickerSets().cend()) { + if (it->flags & MTPDstickerSet::Flag::f_archived) { + lastId = it->id; + break; + } + } + } + _archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_long(lastId), MTP_int(kArchivedLimitPerPage)), rpcDone(&StickersBox::getArchivedDone, lastId)); + } + } +} + int32 StickersBox::countHeight() const { int bottomSkip = st::boxPadding.bottom(); if (_section == Section::Installed) { @@ -1302,9 +1528,7 @@ void StickersBox::closePressed() { } StickersBox::~StickersBox() { - if (_section == Section::Featured) { - Local::writeFeaturedStickers(); - } else if (_section == Section::Archived) { + if (_section == Section::Archived) { Local::writeArchivedStickers(); } } @@ -1326,6 +1550,14 @@ void StickersBox::resizeEvent(QResizeEvent *e) { } void StickersBox::onStickersUpdated() { + if (_section == Section::Installed || _section == Section::Featured) { + rebuildList(); + } else { + _inner->updateRows(); + } +} + +void StickersBox::rebuildList() { _inner->rebuild(); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); @@ -1360,7 +1592,7 @@ void StickersBox::onSave() { return; } - bool writeRecent = false; + bool writeRecent = false, writeArchived = false; auto &recent = cGetRecentStickers(); auto &sets = Global::RefStickerSets(); @@ -1381,6 +1613,11 @@ void StickersBox::onSave() { if (it->flags & MTPDstickerSet::Flag::f_official) { _disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolTrue()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); it->flags |= MTPDstickerSet::Flag::f_archived; + auto index = Global::RefArchivedStickerSetsOrder().indexOf(it->id); + if (index < 0) { + Global::RefArchivedStickerSetsOrder().push_front(it->id); + writeArchived = true; + } } else { _disenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); int removeIndex = Global::StickerSetsOrder().indexOf(it->id); @@ -1388,6 +1625,9 @@ void StickersBox::onSave() { if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) { sets.erase(it); } else { + if (it->flags & MTPDstickerSet::Flag::f_archived) { + writeArchived = true; + } it->flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet::Flag::f_archived); } } @@ -1411,6 +1651,7 @@ void StickersBox::onSave() { MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName)); _disenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(setId, MTP_boolFalse()), rpcDone(&StickersBox::disenableDone), rpcFail(&StickersBox::disenableFail), 0, 5), NullType()); it->flags &= ~MTPDstickerSet::Flag::f_archived; + writeArchived = true; } order.push_back(reorder.at(i)); it->flags |= MTPDstickerSet::Flag::f_installed; @@ -1429,6 +1670,7 @@ void StickersBox::onSave() { Local::writeInstalledStickers(); if (writeRecent) Local::writeUserSettings(); + if (writeArchived) Local::writeArchivedStickers(); emit App::main()->stickersUpdated(); if (_disenableRequests.isEmpty()) { diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 4dfc9fcb1a..42d9e23cf1 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -155,6 +155,9 @@ public slots: void onSave(); +private slots: + void onScroll(); + protected: void hideAll(); void showAll(); @@ -162,6 +165,7 @@ protected: private: void setup(); int32 countHeight() const; + void rebuildList(); void disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req); bool disenableFail(const RPCError &error, mtpRequestId req); @@ -169,6 +173,9 @@ private: bool reorderFail(const RPCError &result); void saveOrder(); + void checkLoadMoreArchived(); + void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result); + Section _section; ChildWidget _inner; @@ -186,6 +193,9 @@ private: Text _about; int _aboutHeight = 0; + mtpRequestId _archivedRequestId = 0; + bool _allArchivedLoaded = false; + }; int32 stickerPacksCount(bool includeDisabledOfficial = false); @@ -201,6 +211,9 @@ public: StickersInner(const Stickers::Order &archivedIds); void rebuild(); + void updateSize(); + void updateRows(); // refresh only pack cover stickers + bool appendSet(const Stickers::Set &set); bool savingStart() { if (_saving) return false; _saving = true; @@ -232,7 +245,7 @@ public slots: private: void setup(); - void paintFeaturedButton(Painter &p) const; + void paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const; void step_shifting(uint64 ms, bool timer); void paintRow(Painter &p, int32 index); @@ -275,6 +288,12 @@ private: using StickerSetRows = QList; 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) const; + void fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled); + + int countMaxNameWidth() const; StickerSetRows _rows; QList _animStartTimes; @@ -296,12 +315,15 @@ private: QString _addText; int _addWidth; - int _featuredHeight = 0; + int _buttonHeight = 0; + bool _hasFeaturedButton = false; + bool _hasArchivedButton = false; + // Remember all the unread set ids to display unread dots. OrderedSet _unreadSets; QPoint _mouse; - int _selected = -2; // -1 - featured stickers button + int _selected = -3; // -2 - featured stickers button, -1 - archived stickers button int _pressed = -2; QPoint _dragStart; int _started = -1; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 80c4335273..783ef5afb7 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -523,6 +523,8 @@ DefineVar(Sandbox, ConnectionProxy, PreLaunchProxy); namespace Stickers { Set *feedSet(const MTPDstickerSet &set) { + MTPDstickerSet::Flags flags = 0; + auto &sets = Global::RefStickerSets(); auto it = sets.find(set.vid.v); auto title = stickerSetTitle(set); @@ -532,6 +534,7 @@ Set *feedSet(const MTPDstickerSet &set) { it->access = set.vaccess_hash.v; it->title = title; it->shortName = qs(set.vshort_name); + flags = it->flags; auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_special); it->flags = set.vflags.v | clientFlags; if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) { @@ -540,6 +543,17 @@ Set *feedSet(const MTPDstickerSet &set) { it->flags |= MTPDstickerSet_ClientFlag::f_not_loaded; // need to request this set } } + auto changedFlags = (flags ^ it->flags); + if (changedFlags & MTPDstickerSet::Flag::f_archived) { + auto index = Global::ArchivedStickerSetsOrder().indexOf(it->id); + if (it->flags & MTPDstickerSet::Flag::f_archived) { + if (index < 0) { + Global::RefArchivedStickerSetsOrder().push_front(it->id); + } + } else if (index >= 0) { + Global::RefArchivedStickerSetsOrder().removeAt(index); + } + } return &it.value(); } @@ -594,6 +608,7 @@ struct Data { Stickers::Order FeaturedStickerSetsOrder; int FeaturedStickerSetsUnreadCount = 0; uint64 LastFeaturedStickersUpdate = 0; + Stickers::Order ArchivedStickerSetsOrder; MTP::DcOptions DcOptions; @@ -667,6 +682,7 @@ DefineVar(Global, uint64, LastRecentStickersUpdate); DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder); DefineVar(Global, int, FeaturedStickerSetsUnreadCount); DefineVar(Global, uint64, LastFeaturedStickersUpdate); +DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder); DefineVar(Global, MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index d99b54bb80..bd07881b2c 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -271,6 +271,7 @@ DeclareVar(uint64, LastRecentStickersUpdate); DeclareVar(Stickers::Order, FeaturedStickerSetsOrder); DeclareVar(int, FeaturedStickerSetsUnreadCount); DeclareVar(uint64, LastFeaturedStickersUpdate); +DeclareVar(Stickers::Order, ArchivedStickerSetsOrder); DeclareVar(MTP::DcOptions, DcOptions); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 59630d7fc1..48f0cc5ceb 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3844,7 +3844,7 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic QString title = stickerSetTitle(set); if (it == sets.cend()) { auto setClientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded; - if (unread.contains(set.vid.v) || !(set.vflags.v & MTPDstickerSet::Flag::f_installed)) { + if (unread.contains(set.vid.v)) { setClientFlags |= MTPDstickerSet_ClientFlag::f_unread; } it = sets.insert(set.vid.v, Stickers::Set(set.vid.v, set.vaccess_hash.v, title, qs(set.vshort_name), set.vcount.v, set.vhash.v, set.vflags.v | setClientFlags)); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index c365e66067..b4395b4ebb 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3325,7 +3325,7 @@ namespace Local { return StickerSetCheckResult::Skip; } return StickerSetCheckResult::Write; - }, Stickers::Order()); + }, Global::ArchivedStickerSetsOrder()); } void importOldRecentStickers() { @@ -3434,30 +3434,28 @@ namespace Local { void readArchivedStickers() { static bool archivedStickersRead = false; if (!archivedStickersRead) { - _readStickerSets(_archivedStickersKey); + _readStickerSets(_archivedStickersKey, &Global::RefArchivedStickerSetsOrder()); archivedStickersRead = true; } } - int32 countStickersHash(bool checkOfficial) { + int32 countStickersHash(bool checkOutdatedInfo) { uint32 acc = 0; - bool foundOfficial = false, foundBad = false;; + bool foundOutdated = false; auto &sets = Global::StickerSets(); auto &order = Global::StickerSetsOrder(); for (auto i = order.cbegin(), e = order.cend(); i != e; ++i) { auto j = sets.constFind(*i); if (j != sets.cend()) { - if (j->id == 0) { - foundBad = true; - } else if (j->flags & MTPDstickerSet::Flag::f_official) { - foundOfficial = true; - } - if (!(j->flags & MTPDstickerSet::Flag::f_archived)) { + if (j->id == Stickers::DefaultSetId) { + foundOutdated = true; + } else if (!(j->flags & MTPDstickerSet_ClientFlag::f_special) + && !(j->flags & MTPDstickerSet::Flag::f_archived)) { acc = (acc * 20261) + j->hash; } } } - return (!checkOfficial || (!foundBad && foundOfficial)) ? int32(acc & 0x7FFFFFFF) : 0; + return (!checkOutdatedInfo || !foundOutdated) ? int32(acc & 0x7FFFFFFF) : 0; } int32 countRecentStickersHash() { diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index 786a108508..ca59fe65b7 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -161,7 +161,7 @@ namespace Local { void readFeaturedStickers(); void readRecentStickers(); void readArchivedStickers(); - int32 countStickersHash(bool checkOfficial = false); + int32 countStickersHash(bool checkOutdatedInfo = false); int32 countRecentStickersHash(); int32 countFeaturedStickersHash(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 44d597b819..bfd5d191b0 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4667,19 +4667,23 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { ////// Cloud sticker sets case mtpc_updateNewStickerSet: { - const auto &d(update.c_updateNewStickerSet()); + auto &d = update.c_updateNewStickerSet(); + bool writeArchived = false; if (d.vstickerset.type() == mtpc_messages_stickerSet) { - const auto &set(d.vstickerset.c_messages_stickerSet()); + auto &set = d.vstickerset.c_messages_stickerSet(); if (set.vset.type() == mtpc_stickerSet) { - const auto &s(set.vset.c_stickerSet()); + auto &s = set.vset.c_stickerSet(); - Stickers::Sets &sets(Global::RefStickerSets()); + auto &sets = Global::RefStickerSets(); auto it = sets.find(s.vid.v); if (it == sets.cend()) { it = sets.insert(s.vid.v, Stickers::Set(s.vid.v, s.vaccess_hash.v, stickerSetTitle(s), qs(s.vshort_name), s.vcount.v, s.vhash.v, s.vflags.v | MTPDstickerSet::Flag::f_installed)); } else { it->flags |= MTPDstickerSet::Flag::f_installed; - it->flags &= ~MTPDstickerSet::Flag::f_archived; + if (it->flags & MTPDstickerSet::Flag::f_archived) { + it->flags &= ~MTPDstickerSet::Flag::f_archived; + writeArchived = true; + } } const auto &v(set.vdocuments.c_vector().v); @@ -4692,12 +4696,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { it->stickers.push_back(doc); } it->emoji.clear(); - const auto &packs(set.vpacks.c_vector().v); + auto &packs = set.vpacks.c_vector().v; for (int32 i = 0, l = packs.size(); i < l; ++i) { if (packs.at(i).type() != mtpc_stickerPack) continue; - const auto &pack(packs.at(i).c_stickerPack()); + auto &pack = packs.at(i).c_stickerPack(); if (EmojiPtr e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) { - const auto &stickers(pack.vdocuments.c_vector().v); + auto &stickers = pack.vdocuments.c_vector().v; StickerPack p; p.reserve(stickers.size()); for (int32 j = 0, c = stickers.size(); j < c; ++j) { @@ -4730,6 +4734,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } Local::writeInstalledStickers(); + if (writeArchived) Local::writeArchivedStickers(); emit stickersUpdated(); } }