diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 820e9a1e8..119c3414e 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -49,25 +49,6 @@ confirmInviteUserName: flatLabel(labelDefFlat) { } confirmInviteUserNameTop: 227px; -stickersAddIcon: icon { - { "stickers_add", #ffffff }, -}; -stickersAddSize: size(30px, 24px); - -stickersFeaturedHeight: 32px; -stickersFeaturedFont: contactsNameFont; -stickersFeaturedPosition: point(16px, 6px); -stickersFeaturedBadgeFont: semiboldFont; -stickersFeaturedBadgeSize: 21px; -stickersFeaturedPen: contactsNewItemFg; -stickersFeaturedUnreadBg: msgFileInBg; -stickersFeaturedUnreadSize: 5px; -stickersFeaturedUnreadSkip: 5px; -stickersFeaturedUnreadTop: 7px; -stickersFeaturedInstalled: icon { - { "mediaview_save_check", #40ace3 } -}; - confirmPhoneAboutLabel: flatLabel(labelDefFlat) { width: 282px; } diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index f3d50db54..5f094e795 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" #include "dialogs/dialogs_layout.h" #include "styles/style_boxes.h" +#include "styles/style_stickers.h" namespace { @@ -423,7 +424,7 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) { namespace internal { -StickersInner::StickersInner(StickersBox::Section section) : TWidget() +StickersInner::StickersInner(StickersBox::Section section) : ScrolledWidget() , _section(section) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _a_shifting(animation(this, &StickersInner::step_shifting)) @@ -436,7 +437,7 @@ StickersInner::StickersInner(StickersBox::Section section) : TWidget() setup(); } -StickersInner::StickersInner(const Stickers::Order &archivedIds) : TWidget() +StickersInner::StickersInner(const Stickers::Order &archivedIds) : ScrolledWidget() , _section(StickersBox::Section::ArchivedPart) , _archivedIds(archivedIds) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) @@ -451,10 +452,15 @@ StickersInner::StickersInner(const Stickers::Order &archivedIds) : TWidget() } void StickersInner::setup() { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(onImageLoaded())); setMouseTracking(true); } +void StickersInner::onImageLoaded() { + update(); + readVisibleSets(); +} + 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); @@ -587,18 +593,18 @@ void StickersInner::paintRow(Painter &p, int32 index) { int statusx = namex; int statusy = st::contactsPadding.top() + st::contactsStatusTop; + p.setFont(st::contactsNameFont); + p.setPen(st::black); + p.drawTextLeft(namex, namey, width(), s->title, s->titleWidth); + if (s->unread) { p.setPen(Qt::NoPen); p.setBrush(st::stickersFeaturedUnreadBg); p.setRenderHint(QPainter::HighQualityAntialiasing, true); - p.drawEllipse(rtlrect(namex, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width())); + p.drawEllipse(rtlrect(namex + s->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width())); p.setRenderHint(QPainter::HighQualityAntialiasing, false); - namex += st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; } - p.setFont(st::contactsNameFont); - p.setPen(st::black); - p.drawTextLeft(namex, namey, width(), s->title); p.setFont(st::contactsStatusFont); p.setPen(st::contactsStatusFg); @@ -967,19 +973,6 @@ void StickersInner::rebuild() { } App::api()->requestStickerSets(); updateSize(); - - if (_section == Section::Featured && Global::FeaturedStickerSetsUnreadCount()) { - Global::SetFeaturedStickerSetsUnreadCount(0); - QVector<MTPlong> readIds; - readIds.reserve(Global::StickerSets().size()); - for (auto &set : Global::RefStickerSets()) { - if (set.flags & MTPDstickerSet_ClientFlag::f_unread) { - set.flags &= ~MTPDstickerSet_ClientFlag::f_unread; - readIds.push_back(MTP_long(set.id)); - } - } - MTP::send(MTPmessages_ReadFeaturedStickers(MTP_vector<MTPlong>(readIds)), rpcDone(&StickersInner::readFeaturedDone), rpcFail(&StickersInner::readFeaturedFail)); - } } void StickersInner::updateSize() { @@ -1007,7 +1000,7 @@ void StickersInner::updateRows() { if (_section == Section::Installed) { row->disabled = false; } - row->title = fillSetTitle(set, maxNameWidth); + row->title = fillSetTitle(set, maxNameWidth, &row->titleWidth); row->count = fillSetCount(set); } } @@ -1031,6 +1024,7 @@ int StickersInner::countMaxNameWidth() const { namew -= qMax(qMax(qMax(_returnWidth, _removeWidth), _restoreWidth), _clearWidth); } else { namew -= st::stickersAddIcon.width() - st::defaultActiveButton.width; + namew -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; } return namew; } @@ -1046,10 +1040,11 @@ void StickersInner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) int pixw = 0, pixh = 0; fillSetCover(set, &sticker, &pixw, &pixh); - QString title = fillSetTitle(set, maxNameWidth); + int titleWidth = 0; + QString title = fillSetTitle(set, maxNameWidth, &titleWidth); int count = fillSetCount(set); - _rows.push_back(new StickerSetRow(set.id, sticker, count, title, installed, official, unread, disabled, recent, pixw, pixh)); + _rows.push_back(new StickerSetRow(set.id, sticker, count, title, titleWidth, installed, official, unread, disabled, recent, pixw, pixh)); _animStartTimes.push_back(0); } @@ -1097,11 +1092,15 @@ int StickersInner::fillSetCount(const Stickers::Set &set) const { return result + added; } -QString StickersInner::fillSetTitle(const Stickers::Set &set, int maxNameWidth) const { +QString StickersInner::fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const { auto result = set.title; - int32 titleWidth = st::contactsNameFont->width(result); + int titleWidth = st::contactsNameFont->width(result); if (titleWidth > maxNameWidth) { result = st::contactsNameFont->elided(result, maxNameWidth); + titleWidth = st::contactsNameFont->width(result); + } + if (outTitleWidth) { + *outTitleWidth = titleWidth; } return result; } @@ -1117,35 +1116,11 @@ void StickersInner::fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *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); - } + *outUnread = (set.flags & MTPDstickerSet_ClientFlag::f_unread); } } } -void StickersInner::readFeaturedDone(const MTPBool &result) { - Local::writeFeaturedStickers(); - emit App::main()->stickersUpdated(); -} - -bool StickersInner::readFeaturedFail(const RPCError &error) { - if (MTP::isDefaultHandledError(error)) return false; - - int unreadCount = 0; - for_const (auto &set, Global::StickerSets()) { - if (!(set.flags & MTPDstickerSet::Flag::f_installed)) { - if (set.flags & MTPDstickerSet_ClientFlag::f_unread) { - ++unreadCount; - } - } - } - Global::SetFeaturedStickerSetsUnreadCount(unreadCount); - return true; -} - Stickers::Order StickersInner::getOrder() const { Stickers::Order result; result.reserve(_rows.size()); @@ -1169,6 +1144,32 @@ Stickers::Order StickersInner::getDisabledSets() const { return result; } +void StickersInner::setVisibleTopBottom(int visibleTop, int visibleBottom) { + if (_section == Section::Featured) { + _visibleTop = visibleTop; + _visibleBottom = visibleBottom; + readVisibleSets(); + } +} + +void StickersInner::readVisibleSets() { + auto itemsVisibleTop = _visibleTop - _itemsTop; + auto itemsVisibleBottom = _visibleBottom - _itemsTop; + int rowFrom = floorclamp(itemsVisibleTop, _rowHeight, 0, _rows.size()); + int rowTo = ceilclamp(itemsVisibleBottom, _rowHeight, 0, _rows.size()); + for (int i = rowFrom; i < rowTo; ++i) { + if (!_rows[i]->unread) { + continue; + } + if (i * _rowHeight < itemsVisibleTop || (i + 1) * _rowHeight > itemsVisibleBottom) { + continue; + } + if (!_rows[i]->sticker || _rows[i]->sticker->thumb->loaded() || _rows[i]->sticker->loaded()) { + Stickers::markFeaturedAsRead(_rows[i]->id); + } + } +} + void StickersInner::setVisibleScrollbar(int32 width) { _scrollbar = width; } @@ -1329,9 +1330,16 @@ void StickersBox::setup() { } void StickersBox::onScroll() { + updateVisibleTopBottom(); checkLoadMoreArchived(); } +void StickersBox::updateVisibleTopBottom() { + auto visibleTop = scrollArea()->scrollTop(); + auto visibleBottom = visibleTop + scrollArea()->height(); + _inner->setVisibleTopBottom(visibleTop, visibleBottom); +} + void StickersBox::checkLoadMoreArchived() { if (_section != Section::Archived) return; @@ -1456,6 +1464,7 @@ void StickersBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); _inner->resize(width(), _inner->height()); _inner->setVisibleScrollbar((scrollArea()->scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); + updateVisibleTopBottom(); if (_topShadow) { _topShadow->setGeometry(0, st::boxTitleHeight + _aboutHeight, width(), st::lineWidth); } diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index ef73191b2..99bc272b9 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -28,7 +28,6 @@ class StickerSetInner : public TWidget, public RPCSender { Q_OBJECT public: - StickerSetInner(const MTPInputStickerSet &set); void mousePressEvent(QMouseEvent *e); @@ -49,16 +48,13 @@ public: ~StickerSetInner(); public slots: - void onPreview(); signals: - void updateButtons(); void installed(uint64 id); private: - int32 stickerFromGlobalPos(const QPoint &p) const; void gotSet(const MTPmessages_StickerSet &set); @@ -169,6 +165,7 @@ private: bool reorderFail(const RPCError &result); void saveOrder(); + void updateVisibleTopBottom(); void checkLoadMoreArchived(); void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result); @@ -198,7 +195,7 @@ int32 stickerPacksCount(bool includeDisabledOfficial = false); namespace internal { -class StickersInner : public TWidget, public RPCSender { +class StickersInner : public ScrolledWidget, public RPCSender { Q_OBJECT public: @@ -220,6 +217,7 @@ public: Stickers::Order getDisabledSets() const; void setVisibleScrollbar(int32 width); + void setVisibleTopBottom(int visibleTop, int visibleBottom) override; ~StickersInner(); @@ -239,6 +237,9 @@ public slots: void onClearRecent(); void onClearBoxDestroyed(QObject *box); +private slots: + void onImageLoaded(); + private: void setup(); void paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const; @@ -249,21 +250,22 @@ private: void setActionSel(int32 actionSel); float64 aboveShadowOpacity() const; + void readVisibleSets(); + void installSet(uint64 setId); void installDone(const MTPmessages_StickerSetInstallResult &result); bool installFail(uint64 setId, const RPCError &error); - void readFeaturedDone(const MTPBool &result); - bool readFeaturedFail(const RPCError &error); Section _section; Stickers::Order _archivedIds; int32 _rowHeight; struct StickerSetRow { - StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, bool installed, bool official, bool unread, bool disabled, bool recent, int32 pixw, int32 pixh) : id(id) + StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool disabled, bool recent, int32 pixw, int32 pixh) : id(id) , sticker(sticker) , count(count) , title(title) + , titleWidth(titleWidth) , installed(installed) , official(official) , unread(unread) @@ -277,6 +279,7 @@ private: DocumentData *sticker; int32 count; QString title; + int titleWidth; bool installed, official, unread, disabled, recent; int32 pixw, pixh; anim::ivalue yadd; @@ -286,7 +289,7 @@ private: 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; + QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const; void fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled); int countMaxNameWidth() const; @@ -297,7 +300,9 @@ private: anim::fvalue _aboveShadowFadeOpacity = { 0., 0. }; Animation _a_shifting; - int32 _itemsTop; + int _visibleTop = 0; + int _visibleBottom = 0; + int _itemsTop = 0; bool _saving = false; @@ -312,9 +317,6 @@ private: bool _hasFeaturedButton = false; bool _hasArchivedButton = false; - // Remember all the unread set ids to display unread dots. - OrderedSet<uint64> _unreadSets; - QPoint _mouse; int _selected = -3; // -2 - featured stickers button, -1 - archived stickers button int _pressed = -2; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index f83fdb289..604c6c204 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3836,14 +3836,14 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic _featuredStickersUpdateRequest = 0; if (stickers.type() != mtpc_messages_featuredStickers) return; - auto &d(stickers.c_messages_featuredStickers()); + auto &d = stickers.c_messages_featuredStickers(); OrderedSet<uint64> unread; for_const (auto &unreadSetId, d.vunread.c_vector().v) { unread.insert(unreadSetId.v); } - auto &d_sets(d.vsets.c_vector().v); + auto &d_sets = d.vsets.c_vector().v; auto &setsOrder = Global::RefFeaturedStickerSetsOrder(); setsOrder.clear(); diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index 1d3b2082a..722a387bf 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -27,6 +27,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwindow.h" #include "mainwidget.h" #include "ui/filedialog.h" +#include "styles/style_stickers.h" + +namespace { + +constexpr int kStickerPreviewEmojiLimit = 10; + +} // namespace void LayerWidget::setInnerFocus() { auto focused = App::wnd()->focusWidget(); @@ -339,6 +346,7 @@ void LayerStackWidget::activateLayer(LayerWidget *l) { startShow(); } else { l->show(); + l->showDone(); if (App::wnd()) App::wnd()->setInnerFocus(); updateLayerBox(); } @@ -426,7 +434,8 @@ LayerStackWidget::~LayerStackWidget() { MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent) , a_shown(0, 0) -, _a_shown(animation(this, &MediaPreviewWidget::step_shown)) { +, _a_shown(animation(this, &MediaPreviewWidget::step_shown)) +, _emojiSize(EmojiSizes[EIndex + 1] / cIntRetinaFactor()) { setAttribute(Qt::WA_TransparentForMouseEvents); connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); } @@ -435,8 +444,8 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) { Painter p(this); QRect r(e->rect()); - const QPixmap &draw(currentImage()); - int w = draw.width() / cIntRetinaFactor(), h = draw.height() / cIntRetinaFactor(); + auto &image = currentImage(); + int w = image.width() / cIntRetinaFactor(), h = image.height() / cIntRetinaFactor(); if (_a_shown.animating()) { float64 shown = a_shown.current(); p.setOpacity(shown); @@ -444,7 +453,17 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) { // h = qMax(qRound(h * (st::stickerPreviewMin + ((1. - st::stickerPreviewMin) * shown)) / 2.) * 2 + int(h % 2), 1); } p.fillRect(r, st::stickerPreviewBg); - p.drawPixmap((width() - w) / 2, (height() - h) / 2, draw); + p.drawPixmap((width() - w) / 2, (height() - h) / 2, image); + if (!_emojiList.isEmpty()) { + int emojiCount = _emojiList.size(); + int emojiWidth = emojiCount * _emojiSize + (emojiCount - 1) * st::stickerEmojiSkip; + int emojiLeft = (width() - emojiWidth) / 2; + int esize = _emojiSize * cIntRetinaFactor(); + for_const (auto emoji, _emojiList) { + p.drawPixmapLeft(emojiLeft, (height() - h) / 2 - _emojiSize * 2, width(), App::emojiLarge(), QRect(emoji->x * esize, emoji->y * esize, esize, esize)); + emojiLeft += _emojiSize + st::stickerEmojiSkip; + } + } } void MediaPreviewWidget::resizeEvent(QResizeEvent *e) { @@ -472,6 +491,7 @@ void MediaPreviewWidget::showPreview(DocumentData *document) { startShow(); _photo = nullptr; _document = document; + fillEmojiString(); resetGifAndCache(); } @@ -510,6 +530,42 @@ void MediaPreviewWidget::hidePreview() { resetGifAndCache(); } +void MediaPreviewWidget::fillEmojiString() { + auto getStickerEmojiList = [this](uint64 setId) { + QList<EmojiPtr> result; + auto &sets = Global::StickerSets(); + auto it = sets.constFind(setId); + if (it == sets.cend()) { + return result; + } + for (auto i = it->emoji.cbegin(), e = it->emoji.cend(); i != e; ++i) { + for_const (auto document, *i) { + if (document == _document) { + result.append(i.key()); + if (result.size() >= kStickerPreviewEmojiLimit) { + return result; + } + } + } + } + return result; + }; + + if (auto sticker = _document->sticker()) { + auto &inputSet = sticker->set; + if (inputSet.type() == mtpc_inputStickerSetID) { + _emojiList = getStickerEmojiList(inputSet.c_inputStickerSetID().vid.v); + } else { + _emojiList.clear(); + if (auto emoji = emojiFromText(sticker->alt)) { + _emojiList.append(emoji); + } + } + } else { + _emojiList.clear(); + } +} + void MediaPreviewWidget::resetGifAndCache() { if (_gif) { if (gif()) { diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h index ffba58d3f..14d1fbc84 100644 --- a/Telegram/SourceFiles/layerwidget.h +++ b/Telegram/SourceFiles/layerwidget.h @@ -133,7 +133,6 @@ class MediaPreviewWidget : public TWidget { Q_OBJECT public: - MediaPreviewWidget(QWidget *parent); void paintEvent(QPaintEvent *e); @@ -148,10 +147,10 @@ public: ~MediaPreviewWidget(); private: - QSize currentDimensions() const; QPixmap currentImage() const; void startShow(); + void fillEmojiString(); void resetGifAndCache(); anim::fvalue a_shown; @@ -163,6 +162,9 @@ private: return (!_gif || _gif == Media::Clip::BadReader) ? false : true; } + int _emojiSize; + QList<EmojiPtr> _emojiList; + void clipCallback(Media::Clip::Notification notification); enum CacheStatus { diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index b662396c9..066004bc0 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3215,6 +3215,7 @@ namespace Local { it = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))); } auto &set = it.value(); + auto inputSet = MTP_inputStickerSetID(MTP_long(set.id), MTP_long(set.access)); if (scnt < 0) { // disabled not loaded set if (!set.count || set.stickers.isEmpty()) { @@ -3240,6 +3241,11 @@ namespace Local { if (fillStickers) { set.stickers.push_back(document); + if (!(set.flags & MTPDstickerSet_ClientFlag::f_special)) { + if (document->sticker()->set.type() != mtpc_inputStickerSetID) { + document->sticker()->set = inputSet; + } + } ++set.count; } } @@ -3287,6 +3293,8 @@ namespace Local { } void writeInstalledStickers() { + if (!Global::started()) return; + _writeStickerSets(_installedStickersKey, [](const Stickers::Set &set) { if (set.id == Stickers::CloudRecentSetId) { // separate file for recent return StickerSetCheckResult::Skip; @@ -3306,6 +3314,8 @@ namespace Local { } void writeFeaturedStickers() { + if (!Global::started()) return; + _writeStickerSets(_featuredStickersKey, [](const Stickers::Set &set) { if (set.id == Stickers::CloudRecentSetId) { // separate file for recent return StickerSetCheckResult::Skip; @@ -3323,6 +3333,8 @@ namespace Local { } void writeRecentStickers() { + if (!Global::started()) return; + _writeStickerSets(_recentStickersKey, [](const Stickers::Set &set) { if (set.id != Stickers::CloudRecentSetId || set.stickers.isEmpty()) { return StickerSetCheckResult::Skip; @@ -3332,6 +3344,8 @@ namespace Local { } void writeArchivedStickers() { + if (!Global::started()) return; + _writeStickerSets(_archivedStickersKey, [](const Stickers::Set &set) { if (!(set.flags & MTPDstickerSet::Flag::f_archived) || set.stickers.isEmpty()) { return StickerSetCheckResult::Skip; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 8feba33bc..cde8d0048 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4691,15 +4691,18 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { writeArchived = true; } } - - const auto &v(set.vdocuments.c_vector().v); + auto inputSet = MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)); + auto &v = set.vdocuments.c_vector().v; it->stickers.clear(); it->stickers.reserve(v.size()); for (int32 i = 0, l = v.size(); i < l; ++i) { - DocumentData *doc = App::feedDocument(v.at(i)); + auto doc = App::feedDocument(v.at(i)); if (!doc || !doc->sticker()) continue; it->stickers.push_back(doc); + if (doc->sticker()->set.type() != mtpc_inputStickerSetID) { + doc->sticker()->set = inputSet; + } } it->emoji.clear(); auto &packs = set.vpacks.c_vector().v; @@ -4780,16 +4783,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateReadFeaturedStickers: { - for (auto &set : Global::RefStickerSets()) { - if (set.flags & MTPDstickerSet_ClientFlag::f_unread) { - set.flags &= ~MTPDstickerSet_ClientFlag::f_unread; - } - } - if (Global::FeaturedStickerSetsUnreadCount()) { - Global::SetFeaturedStickerSetsUnreadCount(0); - Local::writeFeaturedStickers(); - emit stickersUpdated(); - } + // We read some of the featured stickers, perhaps not all of them. + // Here we don't know what featured sticker sets were read, so we + // request all of them once again. + Global::SetLastFeaturedStickersUpdate(0); + App::main()->updateStickers(); } break; ////// Cloud saved GIFs diff --git a/Telegram/SourceFiles/stickers/emoji_pan.cpp b/Telegram/SourceFiles/stickers/emoji_pan.cpp index f84cc454b..a39f1e194 100644 --- a/Telegram/SourceFiles/stickers/emoji_pan.cpp +++ b/Telegram/SourceFiles/stickers/emoji_pan.cpp @@ -287,7 +287,7 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) { p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojiLarge(), QRect(_variants[variant]->x * esize, _variants[variant]->y * esize, esize, esize)); } -EmojiPanInner::EmojiPanInner() : TWidget() +EmojiPanInner::EmojiPanInner() : ScrolledWidget() , _maxHeight(int(st::emojiPanMaxHeight) - st::rbEmoji.height) , _a_selected(animation(this, &EmojiPanInner::step_selected)) { resize(st::emojiPanWidth - st::emojiScroll.width, countHeight()); @@ -316,8 +316,9 @@ void EmojiPanInner::setMaxHeight(int32 h) { resize(st::emojiPanWidth - st::emojiScroll.width, countHeight()); } -void EmojiPanInner::setScrollTop(int top) { - _top = top; +void EmojiPanInner::setVisibleTopBottom(int visibleTop, int visibleBottom) { + _visibleTop = visibleTop; + _visibleBottom = visibleBottom; } int EmojiPanInner::countHeight() { @@ -519,7 +520,7 @@ void EmojiPanInner::onShowPicker() { int32 size = (c == tab) ? (sel - (sel % EmojiPanPerRow)) : _counts[c], rows = (size / EmojiPanPerRow) + ((size % EmojiPanPerRow) ? 1 : 0); y += st::emojiPanHeader + (rows * st::emojiPanSize.height()); } - y -= _picker.height() - st::buttonRadius + _top; + y -= _picker.height() - st::buttonRadius + _visibleTop; if (y < 0) { y += _picker.height() - st::buttonRadius + st::emojiPanSize.height() - st::buttonRadius; } @@ -788,7 +789,7 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) { update(); } -StickerPanInner::StickerPanInner() : TWidget() +StickerPanInner::StickerPanInner() : ScrolledWidget() , _a_selected(animation(this, &StickerPanInner::step_selected)) , _section(cShowingSavedGifs() ? Section::Gifs : Section::Stickers) , _addText(lang(lng_stickers_featured_add).toUpper()) @@ -800,7 +801,7 @@ StickerPanInner::StickerPanInner() : TWidget() setFocusPolicy(Qt::NoFocus); setAttribute(Qt::WA_OpaquePaintEvent); - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(onImageLoaded())); connect(&_settings, SIGNAL(clicked()), this, SLOT(onSettings())); _previewTimer.setSingleShot(true); @@ -816,11 +817,47 @@ void StickerPanInner::setMaxHeight(int32 h) { _settings.moveToLeft((st::emojiPanWidth - _settings.width()) / 2, height() / 3); } -void StickerPanInner::setScrollTop(int top) { - if (top == _top) return; +void StickerPanInner::setVisibleTopBottom(int visibleTop, int visibleBottom) { + _visibleBottom = visibleBottom; + if (_visibleTop != visibleTop) { + _visibleTop = visibleTop; + _lastScrolled = getms(); + } + if (_section == Section::Featured) { + readVisibleSets(); + } +} - _lastScrolled = getms(); - _top = top; +void StickerPanInner::readVisibleSets() { + auto itemsVisibleTop = _visibleTop - st::emojiPanHeader; + auto itemsVisibleBottom = _visibleBottom - st::emojiPanHeader; + auto rowHeight = featuredRowHeight(); + int rowFrom = floorclamp(itemsVisibleTop, rowHeight, 0, _featuredSets.size()); + int rowTo = ceilclamp(itemsVisibleBottom, rowHeight, 0, _featuredSets.size()); + for (int i = rowFrom; i < rowTo; ++i) { + auto &set = _featuredSets[i]; + if (!(set.flags & MTPDstickerSet_ClientFlag::f_unread)) { + continue; + } + if (i * rowHeight < itemsVisibleTop || (i + 1) * rowHeight > itemsVisibleBottom) { + continue; + } + int count = qMin(set.pack.size(), static_cast<int>(StickerPanPerRow)); + int loaded = 0; + for (int j = 0; j < count; ++j) { + if (set.pack[j]->thumb->loaded() || set.pack[j]->loaded()) { + ++loaded; + } + } + if (loaded == count) { + Stickers::markFeaturedAsRead(set.id); + } + } +} + +void StickerPanInner::onImageLoaded() { + update(); + readVisibleSets(); } int StickerPanInner::featuredRowHeight() const { @@ -973,6 +1010,9 @@ void StickerPanInner::paintStickers(Painter &p, const QRect &r) { widthForTitle -= add.width() - (st::featuredStickersAdd.width / 2); } + if (set.flags & MTPDstickerSet_ClientFlag::f_unread) { + widthForTitle -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; + } auto titleText = set.title; auto titleWidth = st::featuredStickersHeaderFont->width(titleText); @@ -984,6 +1024,15 @@ void StickerPanInner::paintStickers(Painter &p, const QRect &r) { p.setPen(st::featuredStickersHeaderFg); p.drawTextLeft(st::emojiPanHeaderLeft, y + st::featuredStickersHeaderTop, width(), titleText, titleWidth); + if (set.flags & MTPDstickerSet_ClientFlag::f_unread) { + p.setPen(Qt::NoPen); + p.setBrush(st::stickersFeaturedUnreadBg); + + p.setRenderHint(QPainter::HighQualityAntialiasing, true); + p.drawEllipse(rtlrect(st::emojiPanHeaderLeft + titleWidth + st::stickersFeaturedUnreadSkip, y + st::featuredStickersHeaderTop + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width())); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + } + p.setFont(st::featuredStickersSubheaderFont); p.setPen(st::featuredStickersSubheaderFg); p.drawTextLeft(st::emojiPanHeaderLeft, y + st::featuredStickersSubheaderTop, width(), lng_stickers_count(lt_count, size)); @@ -1246,7 +1295,6 @@ bool StickerPanInner::showSectionIcons() const { } void StickerPanInner::clearSelection(bool fast) { - _lastMousePos = mapToGlobal(QPoint(-10, -10)); if (fast) { if (showingInlineItems()) { if (_selected >= 0) { @@ -1287,7 +1335,10 @@ void StickerPanInner::clearSelection(bool fast) { _a_selected.stop(); update(); } else { + auto pos = _lastMousePos; + _lastMousePos = mapToGlobal(QPoint(-10, -10)); updateSelected(); + _lastMousePos = pos; } } @@ -1324,35 +1375,62 @@ void StickerPanInner::hideFinish(bool completely) { } void StickerPanInner::refreshStickers() { - clearSelection(true); + auto stickersShown = (_section == Section::Stickers || _section == Section::Featured); + if (stickersShown) { + clearSelection(true); + } _mySets.clear(); _mySets.reserve(Global::StickerSetsOrder().size() + 1); refreshRecentStickers(false); for_const (auto setId, Global::StickerSetsOrder()) { - appendSet(_mySets, setId); + appendSet(_mySets, setId, AppendSkip::Archived); } _featuredSets.clear(); _featuredSets.reserve(Global::FeaturedStickerSetsOrder().size()); for_const (auto setId, Global::FeaturedStickerSetsOrder()) { - appendSet(_featuredSets, setId); + appendSet(_featuredSets, setId, AppendSkip::Installed); } - if (_section == Section::Stickers) { + if (stickersShown) { int h = countHeight(); if (h != height()) resize(width(), h); - _settings.setVisible(_mySets.isEmpty()); + _settings.setVisible(_section == Section::Stickers && _mySets.isEmpty()); } else { _settings.hide(); } emit refreshIcons(); - updateSelected(); + // Hack: skip over animations to the very end, + // so that currently selected sticker won't get + // blinking background when refreshing stickers. + if (stickersShown) { + updateSelected(); + int sel = _selected, tab = sel / MatrixRowShift, xsel = -1; + if (sel >= 0) { + auto &sets = shownSets(); + if (tab < sets.size() && sets[tab].id == Stickers::RecentSetId && sel >= tab * MatrixRowShift + sets[tab].pack.size()) { + xsel = sel; + sel -= sets[tab].pack.size(); + } + auto i = _animations.find(sel + 1); + if (i != _animations.cend()) { + i.value() = (i.value() >= st::emojiPanDuration) ? (i.value() - st::emojiPanDuration) : 0; + } + if (xsel >= 0) { + auto j = _animations.find(xsel + 1); + if (j != _animations.cend()) { + j.value() = (j.value() >= st::emojiPanDuration) ? (j.value() - st::emojiPanDuration) : 0; + } + } + step_selected(getms(), true); + } + } } bool StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth) { @@ -1790,17 +1868,19 @@ bool StickerPanInner::ui_isInlineItemVisible(const InlineItem *layout) { top += _inlineRows.at(i).height; } - return (top < _top + _maxHeight) && (top + _inlineRows.at(row).items.at(col)->height() > _top); + return (top < _visibleTop + _maxHeight) && (top + _inlineRows[row].items[col]->height() > _visibleTop); } bool StickerPanInner::ui_isInlineItemBeingChosen() { return showingInlineItems(); } -void StickerPanInner::appendSet(Sets &to, uint64 setId) { +void StickerPanInner::appendSet(Sets &to, uint64 setId, AppendSkip skip) { auto &sets = Global::StickerSets(); auto it = sets.constFind(setId); - if (it == sets.cend() || (it->flags & MTPDstickerSet::Flag::f_archived) || it->stickers.isEmpty()) return; + if (it == sets.cend() || it->stickers.isEmpty()) return; + if ((skip == AppendSkip::Archived) && (it->flags & MTPDstickerSet::Flag::f_archived)) return; + if ((skip == AppendSkip::Installed) && (it->flags & MTPDstickerSet::Flag::f_installed) && !(it->flags & MTPDstickerSet::Flag::f_archived)) return; to.push_back(Set(it->id, it->flags, it->title, it->stickers.size() + 1, it->stickers)); } @@ -1879,7 +1959,7 @@ void StickerPanInner::fillIcons(QList<StickerIcon> &icons) { if (!cSavedGifs().isEmpty()) { icons.push_back(StickerIcon(Stickers::NoneSetId)); } - if (Global::FeaturedStickerSetsUnreadCount()) { + if (Global::FeaturedStickerSetsUnreadCount() && !_featuredSets.isEmpty()) { icons.push_back(StickerIcon(Stickers::FeaturedSetId)); } @@ -1906,7 +1986,7 @@ void StickerPanInner::fillIcons(QList<StickerIcon> &icons) { } } - if (!Global::FeaturedStickerSetsUnreadCount() && !Global::FeaturedStickerSetsOrder().empty()) { + if (!Global::FeaturedStickerSetsUnreadCount() && !_featuredSets.isEmpty()) { icons.push_back(StickerIcon(Stickers::FeaturedSetId)); } } @@ -2671,14 +2751,14 @@ void EmojiPan::paintEvent(QPaintEvent *e) { p.drawPixmapLeft(x + (st::rbEmoji.width - s.pixw) / 2, _iconsTop + (st::rbEmoji.height - s.pixh) / 2, width(), pix); x += st::rbEmoji.width; } else { - if (selxrel != x) { + if (true || selxrel != x) { p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), getSpecialSetIcon(s.setId, false)); } - if (selxrel < x + st::rbEmoji.width && selxrel > x - st::rbEmoji.width) { - p.setOpacity(1 - (qAbs(selxrel - x) / float64(st::rbEmoji.width))); - p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), getSpecialSetIcon(s.setId, true)); - p.setOpacity(1); - } + //if (selxrel < x + st::rbEmoji.width && selxrel > x - st::rbEmoji.width) { + // p.setOpacity(1 - (qAbs(selxrel - x) / float64(st::rbEmoji.width))); + // p.drawSpriteLeft(x + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), getSpecialSetIcon(s.setId, true)); + // p.setOpacity(1); + //} if (s.setId == Stickers::FeaturedSetId) { paintFeaturedStickerSetsBadge(p, x); } @@ -3330,7 +3410,7 @@ void EmojiPan::onScrollEmoji() { _noTabUpdate = false; } - e_inner.setScrollTop(st); + e_inner.setVisibleTopBottom(st, st + e_scroll.height()); } void EmojiPan::onScrollStickers() { @@ -3343,7 +3423,7 @@ void EmojiPan::onScrollStickers() { onInlineRequest(); } - s_inner.setScrollTop(st); + s_inner.setVisibleTopBottom(st, st + s_scroll.height()); } void EmojiPan::validateSelectedIcon(bool animated) { diff --git a/Telegram/SourceFiles/stickers/emoji_pan.h b/Telegram/SourceFiles/stickers/emoji_pan.h index ff6d609b5..16c8edc77 100644 --- a/Telegram/SourceFiles/stickers/emoji_pan.h +++ b/Telegram/SourceFiles/stickers/emoji_pan.h @@ -113,7 +113,7 @@ private: }; class EmojiPanel; -class EmojiPanInner : public TWidget { +class EmojiPanInner : public ScrolledWidget { Q_OBJECT public: @@ -122,13 +122,6 @@ public: void setMaxHeight(int32 h); void paintEvent(QPaintEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - void leaveEvent(QEvent *e) override; - void leaveToChildEvent(QEvent *e, QWidget *child) override; - void enterFromChildEvent(QEvent *e, QWidget *child) override; - void step_selected(uint64 ms, bool timer); void hideFinish(); @@ -140,13 +133,20 @@ public: void refreshRecent(); - void setScrollTop(int top); + void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void fillPanels(QVector<EmojiPanel*> &panels); void refreshPanels(QVector<EmojiPanel*> &panels); -public slots: +protected: + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void leaveEvent(QEvent *e) override; + void leaveToChildEvent(QEvent *e, QWidget *child) override; + void enterFromChildEvent(QEvent *e, QWidget *child) override; +public slots: void updateSelected(); void onShowPicker(); @@ -156,7 +156,6 @@ public slots: bool checkPickerHide(); signals: - void selected(EmojiPtr emoji); void switchToStickers(); @@ -168,7 +167,6 @@ signals: void saveConfigDelayed(int32 delay); private: - int32 _maxHeight; int countHeight(); @@ -180,7 +178,9 @@ private: Animations _animations; Animation _a_selected; - int _top = 0, _counts[emojiTabCount]; + int _visibleTop = 0; + int _visibleBottom = 0; + int _counts[emojiTabCount]; QVector<EmojiPtr> _emojis[emojiTabCount]; QVector<float64> _hovers[emojiTabCount]; @@ -207,23 +207,15 @@ struct StickerIcon { int pixh = 0; }; -class StickerPanInner : public TWidget { +class StickerPanInner : public ScrolledWidget { Q_OBJECT public: - StickerPanInner(); void setMaxHeight(int32 h); void paintEvent(QPaintEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - void leaveEvent(QEvent *e) override; - void leaveToChildEvent(QEvent *e, QWidget *child) override; - void enterFromChildEvent(QEvent *e, QWidget *child) override; - void step_selected(uint64 ms, bool timer); void hideFinish(bool completely); @@ -247,7 +239,7 @@ public: void fillPanels(QVector<EmojiPanel*> &panels); void refreshPanels(QVector<EmojiPanel*> &panels); - void setScrollTop(int top); + void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void preloadImages(); uint64 currentSet(int yOffset) const; @@ -264,12 +256,21 @@ public: ~StickerPanInner(); +protected: + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void leaveEvent(QEvent *e) override; + void leaveToChildEvent(QEvent *e, QWidget *child) override; + void enterFromChildEvent(QEvent *e, QWidget *child) override; + private slots: void updateSelected(); void onSettings(); void onPreview(); void onUpdateInlineItems(); void onSwitchPm(); + void onImageLoaded(); signals: void selected(DocumentData *sticker); @@ -310,6 +311,7 @@ private: return const_cast<StickerPanInner*>(this)->shownSets(); } int featuredRowHeight() const; + void readVisibleSets(); bool showingInlineItems() const { // Gifs or Inline results return (_section == Section::Inlines) || (_section == Section::Gifs); @@ -324,7 +326,11 @@ private: void refreshSwitchPmButton(const InlineCacheEntry *entry); - void appendSet(Sets &to, uint64 setId); + enum class AppendSkip { + Archived, + Installed, + }; + void appendSet(Sets &to, uint64 setId, AppendSkip skip); void selectEmoji(EmojiPtr emoji); QRect stickerRect(int tab, int sel); @@ -335,7 +341,8 @@ private: Animations _animations; Animation _a_selected; - int _top = 0; + int _visibleTop = 0; + int _visibleBottom = 0; Sets _mySets; Sets _featuredSets; diff --git a/Telegram/SourceFiles/stickers/stickers.cpp b/Telegram/SourceFiles/stickers/stickers.cpp index 4f5412d62..266ede52d 100644 --- a/Telegram/SourceFiles/stickers/stickers.cpp +++ b/Telegram/SourceFiles/stickers/stickers.cpp @@ -19,15 +19,22 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #include "stdafx.h" -#include "lang.h" +#include "stickers.h" #include "boxes/stickersetbox.h" #include "boxes/confirmbox.h" +#include "lang.h" #include "apiwrap.h" #include "localstorage.h" #include "mainwidget.h" namespace Stickers { +namespace { + +constexpr int kReadFeaturedSetsTimeoutMs = 1000; +internal::FeaturedReader *FeaturedReaderInstance = nullptr; + +} // namespace void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) { auto &v = d.vsets.c_vector().v; @@ -140,4 +147,61 @@ void undoInstallLocally(uint64 setId) { Ui::showLayer(new InformBox(lang(lng_stickers_not_found)), KeepOtherLayers); } +void markFeaturedAsRead(uint64 setId) { + if (!FeaturedReaderInstance) { + if (auto main = App::main()) { + FeaturedReaderInstance = new internal::FeaturedReader(main); + } else { + return; + } + } + FeaturedReaderInstance->scheduleRead(setId); +} + +namespace internal { + +void readFeaturedDone() { + Local::writeFeaturedStickers(); + if (App::main()) { + emit App::main()->stickersUpdated(); + } +} + +FeaturedReader::FeaturedReader(QObject *parent) : QObject(parent) +, _timer(new QTimer(this)) { + _timer->setSingleShot(true); + connect(_timer, SIGNAL(timeout()), this, SLOT(onReadSets())); +} + +void FeaturedReader::scheduleRead(uint64 setId) { + if (!_setIds.contains(setId)) { + _setIds.insert(setId); + _timer->start(kReadFeaturedSetsTimeoutMs); + } +} + +void FeaturedReader::onReadSets() { + auto &sets = Global::RefStickerSets(); + auto count = Global::FeaturedStickerSetsUnreadCount(); + QVector<MTPlong> wrappedIds; + wrappedIds.reserve(_setIds.size()); + for_const (auto setId, _setIds) { + auto it = sets.find(setId); + if (it != sets.cend()) { + it->flags &= ~MTPDstickerSet_ClientFlag::f_unread; + wrappedIds.append(MTP_long(setId)); + if (count) { + --count; + } + } + } + _setIds.clear(); + + if (!wrappedIds.empty()) { + MTP::send(MTPmessages_ReadFeaturedStickers(MTP_vector<MTPlong>(wrappedIds)), rpcDone(&readFeaturedDone)); + Global::SetFeaturedStickerSetsUnreadCount(count); + } +} + +} // namespace internal } // namespace Stickers diff --git a/Telegram/SourceFiles/stickers/stickers.h b/Telegram/SourceFiles/stickers/stickers.h index 06df73d47..c2449c6af 100644 --- a/Telegram/SourceFiles/stickers/stickers.h +++ b/Telegram/SourceFiles/stickers/stickers.h @@ -25,5 +25,25 @@ namespace Stickers { void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d); void installLocally(uint64 setId); void undoInstallLocally(uint64 setId); +void markFeaturedAsRead(uint64 setId); +namespace internal { + +class FeaturedReader : public QObject { + Q_OBJECT + +public: + FeaturedReader(QObject *parent); + void scheduleRead(uint64 setId); + +private slots: + void onReadSets(); + +private: + QTimer *_timer; + OrderedSet<uint64> _setIds; + +}; + +} // namespace internal } // namespace Stickers diff --git a/Telegram/SourceFiles/stickers/stickers.style b/Telegram/SourceFiles/stickers/stickers.style index 11168295c..ae74a48f7 100644 --- a/Telegram/SourceFiles/stickers/stickers.style +++ b/Telegram/SourceFiles/stickers/stickers.style @@ -37,3 +37,24 @@ featuredStickersAdd: RoundButton(defaultActiveButton) { textTop: 4px; downTextTop: 5px; } + +stickerEmojiSkip: 5px; + +stickersAddIcon: icon { + { "stickers_add", #ffffff }, +}; +stickersAddSize: size(30px, 24px); + +stickersFeaturedHeight: 32px; +stickersFeaturedFont: contactsNameFont; +stickersFeaturedPosition: point(16px, 6px); +stickersFeaturedBadgeFont: semiboldFont; +stickersFeaturedBadgeSize: 21px; +stickersFeaturedPen: contactsNewItemFg; +stickersFeaturedUnreadBg: msgFileInBg; +stickersFeaturedUnreadSize: 5px; +stickersFeaturedUnreadSkip: 5px; +stickersFeaturedUnreadTop: 7px; +stickersFeaturedInstalled: icon { + { "mediaview_save_check", #40ace3 } +}; diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index e6098fa03..459c48387 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -1155,7 +1155,9 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes } if (sticker()) { sticker()->alt = qs(d.valt); - sticker()->set = d.vstickerset; + if (sticker()->set.type() != mtpc_inputStickerSetID || d.vstickerset.type() == mtpc_inputStickerSetID) { + sticker()->set = d.vstickerset; + } } } break; case mtpc_documentAttributeVideo: { diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 3fc4cec2e..f9627501c 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -1029,12 +1029,10 @@ struct DocumentAdditionalData { }; struct StickerData : public DocumentAdditionalData { - StickerData() : set(MTP_inputStickerSetEmpty()) { - } ImagePtr img; QString alt; - MTPInputStickerSet set; + MTPInputStickerSet set = MTP_inputStickerSetEmpty(); bool setInstalled() const; StorageImageLocation loc; // doc thumb location