Featured stickers fully supported (unread badges, box, adding, etc).

This commit is contained in:
John Preston 2016-06-28 21:05:38 +03:00
parent 991c6ddd99
commit cd696ade4e
24 changed files with 656 additions and 304 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 KiB

After

Width:  |  Height:  |  Size: 238 KiB

View File

@ -1838,6 +1838,20 @@ stickersReorderFg: #777;
stickersRowDisabledOpacity: 0.4; stickersRowDisabledOpacity: 0.4;
stickersRowDuration: 200; stickersRowDuration: 200;
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 }
};
emojiScroll: flatScroll(solidScroll) { emojiScroll: flatScroll(solidScroll) {
deltat: 48px; deltat: 48px;
} }
@ -1861,6 +1875,9 @@ stickersSettings: sprite(140px, 124px, 21px, 22px);
savedGifsOver: sprite(329px, 286px, 21px, 22px); savedGifsOver: sprite(329px, 286px, 21px, 22px);
savedGifsActive: sprite(350px, 286px, 21px, 22px); savedGifsActive: sprite(350px, 286px, 21px, 22px);
stickersSettingsUnreadSize: 17px;
stickersSettingsUnreadPosition: point(4px, 5px);
emojiPanCategories: #f7f7f7; emojiPanCategories: #f7f7f7;
rbEmoji: flatCheckbox { rbEmoji: flatCheckbox {
@ -2133,7 +2150,9 @@ mvCaptionRadius: 2px;
mvCaptionBg: #11111180; mvCaptionBg: #11111180;
mvCaptionFont: font(fsize); mvCaptionFont: font(fsize);
medviewSaveMsgCheck: sprite(311px, 309px, 22px, 18px); medviewSaveMsgCheck: icon {
{ "mediaview_save_check", #ffffff }
};
medviewSaveMsgFont: font(16px); medviewSaveMsgFont: font(16px);
medviewSaveMsgPadding: margins(55px, 19px, 29px, 20px); medviewSaveMsgPadding: margins(55px, 19px, 29px, 20px);
medviewSaveMsgCheckPos: point(23px, 21px); medviewSaveMsgCheckPos: point(23px, 21px);

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

View File

@ -685,9 +685,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_stickers_you_have" = "Manage and reorder sticker packs"; "lng_stickers_you_have" = "Manage and reorder sticker packs";
"lng_stickers_packs" = "Sticker Packs"; "lng_stickers_packs" = "Sticker Packs";
"lng_stickers_reorder" = "Click and drag to reorder sticker packs"; "lng_stickers_reorder" = "Click and drag to reorder sticker packs";
"lng_stickers_featured" = "Featured Stickers";
"lng_stickers_remove" = "Delete"; "lng_stickers_remove" = "Delete";
"lng_stickers_return" = "Undo"; "lng_stickers_return" = "Undo";
"lng_stickers_restore" = "Restore"; "lng_stickers_restore" = "Restore";
"lng_stickers_add" = "Add";
"lng_stickers_count" = "{count:Loading...|# sticker|# stickers}"; "lng_stickers_count" = "{count:Loading...|# sticker|# stickers}";
"lng_in_dlg_photo" = "Photo"; "lng_in_dlg_photo" = "Photo";

View File

@ -924,10 +924,10 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
_stickerSetRequests.remove(setId); _stickerSetRequests.remove(setId);
if (result.type() != mtpc_messages_stickerSet) return; if (result.type() != mtpc_messages_stickerSet) return;
const auto &d(result.c_messages_stickerSet()); auto &d(result.c_messages_stickerSet());
if (d.vset.type() != mtpc_stickerSet) return; if (d.vset.type() != mtpc_stickerSet) return;
const auto &s(d.vset.c_stickerSet()); auto &s(d.vset.c_stickerSet());
auto &sets = Global::RefStickerSets(); auto &sets = Global::RefStickerSets();
auto it = sets.find(setId); auto it = sets.find(setId);
@ -937,7 +937,7 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
it->hash = s.vhash.v; it->hash = s.vhash.v;
it->shortName = qs(s.vshort_name); it->shortName = qs(s.vshort_name);
it->title = stickerSetTitle(s); it->title = stickerSetTitle(s);
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded); auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded);
it->flags = s.vflags.v | clientFlags; it->flags = s.vflags.v | clientFlags;
it->flags &= ~MTPDstickerSet_ClientFlag::f_not_loaded; it->flags &= ~MTPDstickerSet_ClientFlag::f_not_loaded;

View File

@ -1979,6 +1979,9 @@ namespace {
Global::SetStickerSets(Stickers::Sets()); Global::SetStickerSets(Stickers::Sets());
Global::SetStickerSetsOrder(Stickers::Order()); Global::SetStickerSetsOrder(Stickers::Order());
Global::SetLastStickersUpdate(0); Global::SetLastStickersUpdate(0);
Global::SetFeaturedStickerSetsOrder(Stickers::Order());
Global::SetFeaturedStickerSetsUnreadCount(0);
Global::SetLastFeaturedStickersUpdate(0);
cSetSavedGifs(SavedGifs()); cSetSavedGifs(SavedGifs());
cSetLastSavedGifsUpdate(0); cSetLastSavedGifsUpdate(0);
cSetReportSpamStatuses(ReportSpamStatuses()); cSetReportSpamStatuses(ReportSpamStatuses());

View File

@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "localstorage.h" #include "localstorage.h"
#include "dialogs/dialogs_layout.h"
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget() StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget()
, _input(set) { , _input(set) {
@ -47,21 +48,21 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_pack.clear(); _pack.clear();
_emoji.clear(); _emoji.clear();
if (set.type() == mtpc_messages_stickerSet) { if (set.type() == mtpc_messages_stickerSet) {
const auto &d(set.c_messages_stickerSet()); auto &d(set.c_messages_stickerSet());
const auto &v(d.vdocuments.c_vector().v); auto &v(d.vdocuments.c_vector().v);
_pack.reserve(v.size()); _pack.reserve(v.size());
for (int32 i = 0, l = v.size(); i < l; ++i) { for (int 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; if (!doc || !doc->sticker()) continue;
_pack.push_back(doc); _pack.push_back(doc);
} }
const auto &packs(d.vpacks.c_vector().v); auto &packs(d.vpacks.c_vector().v);
for (int32 i = 0, l = packs.size(); i < l; ++i) { for (int i = 0, l = packs.size(); i < l; ++i) {
if (packs.at(i).type() != mtpc_stickerPack) continue; 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)))) { if (auto e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) {
const auto &stickers(pack.vdocuments.c_vector().v); auto &stickers(pack.vdocuments.c_vector().v);
StickerPack p; StickerPack p;
p.reserve(stickers.size()); p.reserve(stickers.size());
for (int32 j = 0, c = stickers.size(); j < c; ++j) { for (int32 j = 0, c = stickers.size(); j < c; ++j) {
@ -74,7 +75,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
} }
} }
if (d.vset.type() == mtpc_stickerSet) { if (d.vset.type() == mtpc_stickerSet) {
const auto &s(d.vset.c_stickerSet()); auto &s(d.vset.c_stickerSet());
_setTitle = stickerSetTitle(s); _setTitle = stickerSetTitle(s);
_title = st::boxTitleFont->elided(_setTitle, width() - st::boxTitlePosition.x() - st::boxTitleHeight); _title = st::boxTitleFont->elided(_setTitle, width() - st::boxTitlePosition.x() - st::boxTitleHeight);
_setShortName = qs(s.vshort_name); _setShortName = qs(s.vshort_name);
@ -83,6 +84,15 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_setCount = s.vcount.v; _setCount = s.vcount.v;
_setHash = s.vhash.v; _setHash = s.vhash.v;
_setFlags = s.vflags.v; _setFlags = s.vflags.v;
auto &sets = Global::RefStickerSets();
auto it = sets.find(_setId);
if (it != sets.cend()) {
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded | MTPDstickerSet_ClientFlag::f_unread);
_setFlags |= clientFlags;
it->flags = _setFlags;
it->stickers = _pack;
it->emoji = _emoji;
}
} }
} }
@ -116,13 +126,13 @@ void StickerSetInner::installDone(const MTPBool &result) {
if (it == sets.cend()) { if (it == sets.cend()) {
it = sets.insert(_setId, Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)); it = sets.insert(_setId, Stickers::Set(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags));
} else { } else {
it.value().flags = _setFlags; it->flags = _setFlags;
} }
it.value().stickers = _pack; it->stickers = _pack;
it.value().emoji = _emoji; it->emoji = _emoji;
auto &order = Global::RefStickerSetsOrder(); auto &order = Global::RefStickerSetsOrder();
int32 insertAtIndex = 0, currentIndex = order.indexOf(_setId); int insertAtIndex = 0, currentIndex = order.indexOf(_setId);
if (currentIndex != insertAtIndex) { if (currentIndex != insertAtIndex) {
if (currentIndex > 0) { if (currentIndex > 0) {
order.removeAt(currentIndex); order.removeAt(currentIndex);
@ -132,8 +142,8 @@ void StickerSetInner::installDone(const MTPBool &result) {
auto custom = sets.find(Stickers::CustomSetId); auto custom = sets.find(Stickers::CustomSetId);
if (custom != sets.cend()) { if (custom != sets.cend()) {
for (int32 i = 0, l = _pack.size(); i < l; ++i) { for_const (auto sticker, _pack) {
int32 removeIndex = custom->stickers.indexOf(_pack.at(i)); int removeIndex = custom->stickers.indexOf(sticker);
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex); if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
} }
if (custom->stickers.isEmpty()) { if (custom->stickers.isEmpty()) {
@ -141,8 +151,8 @@ void StickerSetInner::installDone(const MTPBool &result) {
} }
} }
Local::writeStickers(); Local::writeStickers();
emit App::main()->stickersUpdated();
emit installed(_setId); emit installed(_setId);
Ui::hideLayer();
} }
bool StickerSetInner::installFailed(const RPCError &error) { bool StickerSetInner::installFailed(const RPCError &error) {
@ -295,7 +305,7 @@ StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st::
connect(&_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons())); connect(&_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons()));
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(&_inner, SIGNAL(installed(uint64)), this, SIGNAL(installed(uint64))); connect(&_inner, SIGNAL(installed(uint64)), this, SLOT(onInstalled(uint64)));
onStickersUpdated(); onStickersUpdated();
@ -304,6 +314,11 @@ StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st::
prepare(); prepare();
} }
void StickerSetBox::onInstalled(uint64 setId) {
emit installed(setId);
onClose();
}
void StickerSetBox::onStickersUpdated() { void StickerSetBox::onStickersUpdated() {
showAll(); showAll();
} }
@ -392,28 +407,44 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) {
} }
} }
StickersInner::StickersInner() : TWidget() namespace internal {
StickersInner::StickersInner(StickersBox::Section section) : TWidget()
, _section(section)
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _aboveShadowFadeStart(0)
, _aboveShadowFadeOpacity(0, 0)
, _a_shifting(animation(this, &StickersInner::step_shifting)) , _a_shifting(animation(this, &StickersInner::step_shifting))
, _itemsTop(st::membersPadding.top()) , _itemsTop(st::membersPadding.top())
, _saving(false)
, _removeSel(-1)
, _removeDown(-1)
, _removeWidth(st::normalFont->width(lang(lng_stickers_remove))) , _removeWidth(st::normalFont->width(lang(lng_stickers_remove)))
, _returnWidth(st::normalFont->width(lang(lng_stickers_return))) , _returnWidth(st::normalFont->width(lang(lng_stickers_return)))
, _restoreWidth(st::normalFont->width(lang(lng_stickers_restore))) , _restoreWidth(st::normalFont->width(lang(lng_stickers_restore)))
, _selected(-1) , _addText(lang(lng_stickers_add).toUpper())
, _started(-1) , _addWidth(st::defaultActiveButton.font->width(_addText))
, _dragging(-1) , _aboveShadow(st::boxShadow) {
, _above(-1)
, _aboveShadow(st::boxShadow)
, _scrollbar(0) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
setMouseTracking(true); setMouseTracking(true);
} }
void StickersInner::paintFeaturedButton(Painter &p) const {
if (!_featuredHeight) return;
if (_selected == -1) {
p.fillRect(0, st::membersPadding.top(), width(), _featuredHeight, 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));
if (auto unread = Global::FeaturedStickerSetsUnreadCount()) {
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);
}
}
void StickersInner::paintEvent(QPaintEvent *e) { void StickersInner::paintEvent(QPaintEvent *e) {
QRect r(e->rect()); QRect r(e->rect());
Painter p(this); Painter p(this);
@ -422,10 +453,13 @@ void StickersInner::paintEvent(QPaintEvent *e) {
p.fillRect(r, st::white); p.fillRect(r, st::white);
p.setClipRect(r); p.setClipRect(r);
paintFeaturedButton(p);
if (_rows.isEmpty()) { if (_rows.isEmpty()) {
p.setFont(st::noContactsFont->f); p.setFont(st::noContactsFont);
p.setPen(st::noContactsColor->p); p.setPen(st::noContactsColor);
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); p.drawText(QRect(0, _featuredHeight, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
} else { } else {
p.translate(0, _itemsTop); p.translate(0, _itemsTop);
@ -452,33 +486,50 @@ void StickersInner::paintRow(Painter &p, int32 index) {
int32 xadd = 0, yadd = s->yadd.current(); int32 xadd = 0, yadd = s->yadd.current();
if (xadd || yadd) p.translate(xadd, yadd); if (xadd || yadd) p.translate(xadd, yadd);
bool removeSel = (index == _removeSel && (_removeDown < 0 || index == _removeDown)); if (_section == Section::Installed) {
bool removeDown = removeSel && (index == _removeDown); bool removeSel = (index == _actionSel && (_actionDown < 0 || index == _actionDown));
bool removeDown = removeSel && (index == _actionDown);
p.setFont((removeSel ? st::linkOverFont : st::linkFont)->f); p.setFont(removeSel ? st::linkOverFont : st::linkFont);
if (removeDown) { if (removeDown) {
p.setPen(st::btnDefLink.downColor->p); p.setPen(st::btnDefLink.downColor);
} else { } else {
p.setPen(st::btnDefLink.color->p); p.setPen(st::btnDefLink.color);
}
int32 remWidth = s->disabled ? (s->official ? _restoreWidth : _returnWidth) : _removeWidth;
QString remText = lang(s->disabled ? (s->official ? lng_stickers_restore : lng_stickers_return) : lng_stickers_remove);
p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), remText, remWidth);
if (index == _above) {
float64 current = _aboveShadowFadeOpacity.current();
if (_started >= 0) {
float64 o = aboveShadowOpacity();
if (o > current) {
_aboveShadowFadeOpacity = anim::fvalue(o, o);
current = o;
}
} }
p.setOpacity(current); int32 remWidth = s->disabled ? (s->official ? _restoreWidth : _returnWidth) : _removeWidth;
QRect row(myrtlrect(_aboveShadow.getDimensions(st::boxShadowShift).left(), st::contactsPadding.top() / 2, width() - (st::contactsPadding.left() / 2) - _scrollbar - _aboveShadow.getDimensions(st::boxShadowShift).right(), _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2))); QString remText = lang(s->disabled ? (s->official ? lng_stickers_restore : lng_stickers_return) : lng_stickers_remove);
_aboveShadow.paint(p, row, st::boxShadowShift); p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), remText, remWidth);
p.fillRect(row, st::white);
p.setOpacity(1); if (index == _above) {
float64 current = _aboveShadowFadeOpacity.current();
if (_started >= 0) {
float64 o = aboveShadowOpacity();
if (o > current) {
_aboveShadowFadeOpacity = anim::fvalue(o, o);
current = o;
}
}
p.setOpacity(current);
QRect row(myrtlrect(_aboveShadow.getDimensions(st::boxShadowShift).left(), st::contactsPadding.top() / 2, width() - (st::contactsPadding.left() / 2) - _scrollbar - _aboveShadow.getDimensions(st::boxShadowShift).right(), _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2)));
_aboveShadow.paint(p, row, st::boxShadowShift);
p.fillRect(row, st::white);
p.setOpacity(1);
}
} else if (s->installed) {
int addw = _addWidth - st::defaultActiveButton.width;
int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (addw + st::stickersFeaturedInstalled.width()) / 2);
int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2;
st::stickersFeaturedInstalled.paint(p, QPoint(checkx, checky), width());
} else {
int addw = _addWidth - st::defaultActiveButton.width;
int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw;
int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2;
QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.height));
App::roundRect(p, add, st::defaultActiveButton.textBgOver);
p.setFont(st::defaultActiveButton.font);
p.setPen(st::defaultActiveButton.textFg);
p.drawTextLeft(addx - st::defaultActiveButton.width / 2, addy + st::defaultActiveButton.textTop, width(), _addText, _addWidth);
} }
if (s->disabled) p.setOpacity(st::stickersRowDisabledOpacity); if (s->disabled) p.setOpacity(st::stickersRowDisabledOpacity);
@ -487,15 +538,28 @@ void StickersInner::paintRow(Painter &p, int32 index) {
QPixmap pix(s->sticker->thumb->pix(s->pixw, s->pixh)); QPixmap pix(s->sticker->thumb->pix(s->pixw, s->pixh));
p.drawPixmapLeft(st::contactsPadding.left() + (st::contactsPhotoSize - s->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - s->pixh) / 2, width(), pix); p.drawPixmapLeft(st::contactsPadding.left() + (st::contactsPhotoSize - s->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - s->pixh) / 2, width(), pix);
} }
int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
int namey = st::contactsPadding.top() + st::contactsNameTop;
int statusx = namex;
int statusy = st::contactsPadding.top() + st::contactsStatusTop;
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.setRenderHint(QPainter::HighQualityAntialiasing, false);
namex += st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip;
}
p.setFont(st::contactsNameFont); p.setFont(st::contactsNameFont);
p.setPen(st::black); p.setPen(st::black);
p.drawTextLeft(namex, namey, width(), s->title);
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsNameTop, width(), s->title);
p.setFont(st::contactsStatusFont); p.setFont(st::contactsStatusFont);
p.setPen(st::contactsStatusFg); p.setPen(st::contactsStatusFg);
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), lng_stickers_count(lt_count, s->count)); p.drawTextLeft(statusx, statusy, width(), lng_stickers_count(lt_count, s->count));
p.setOpacity(1); p.setOpacity(1);
if (xadd || yadd) p.translate(-xadd, -yadd); if (xadd || yadd) p.translate(-xadd, -yadd);
@ -506,10 +570,12 @@ void StickersInner::mousePressEvent(QMouseEvent *e) {
if (_dragging >= 0) mouseReleaseEvent(e); if (_dragging >= 0) mouseReleaseEvent(e);
_mouse = e->globalPos(); _mouse = e->globalPos();
onUpdateSelected(); onUpdateSelected();
if (_removeSel >= 0) {
_removeDown = _removeSel; _pressed = _selected;
update(0, _itemsTop + _removeSel * _rowHeight, width(), _rowHeight); if (_actionSel >= 0) {
} else if (_selected >= 0) { _actionDown = _actionSel;
update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
} else if (_selected >= 0 && _section == Section::Installed) {
_above = _dragging = _started = _selected; _above = _dragging = _started = _selected;
_dragStart = mapFromGlobal(_mouse); _dragStart = mapFromGlobal(_mouse);
} }
@ -557,15 +623,39 @@ void StickersInner::onUpdateSelected() {
emit checkDraggingScroll(local.y()); emit checkDraggingScroll(local.y());
} else { } else {
bool in = rect().marginsRemoved(QMargins(0, _itemsTop, 0, st::membersPadding.bottom())).contains(local); bool in = rect().marginsRemoved(QMargins(0, _itemsTop, 0, st::membersPadding.bottom())).contains(local);
_selected = in ? floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1) : -1; int selected = -2;
int32 removeSel = -1; int actionSel = -1;
if (in) {
selected = floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1);
if (_selected >= 0) { if (_section == Section::Installed) {
int32 remw = _rows.at(_selected)->disabled ? (_rows.at(_selected)->official ? _restoreWidth : _returnWidth) : _removeWidth; int remw = _rows.at(selected)->disabled ? (_rows.at(selected)->official ? _restoreWidth : _returnWidth) : _removeWidth;
QRect rem(myrtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - remw, st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, remw, st::normalFont->height)); QRect rem(myrtlrect(width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - remw, st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, remw, st::normalFont->height));
removeSel = rem.contains(local.x(), local.y() - _itemsTop - _selected * _rowHeight) ? _selected : -1; actionSel = rem.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1;
} else if (_rows.at(selected)->installed) {
actionSel = -1;
} else {
int addw = _addWidth - st::defaultActiveButton.width;
int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw;
int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::defaultActiveButton.height) / 2;
QRect add(myrtlrect(addx, addy, addw, st::defaultActiveButton.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)) {
selected = -1;
} else {
selected = -2;
} }
setRemoveSel(removeSel); if (_selected != selected) {
if ((_selected == -1) != (selected == -1)) {
update();
}
if (_section == Section::Featured && ((_selected >= 0 || _pressed >= 0) != (selected >= 0 || _pressed >= 0))) {
setCursor((selected >= 0 || _pressed >= 0) ? style::cur_pointer : style::cur_default);
}
_selected = selected;
}
setActionSel(actionSel);
emit noDraggingScroll(); emit noDraggingScroll();
} }
} }
@ -579,11 +669,23 @@ float64 StickersInner::aboveShadowOpacity() const {
} }
void StickersInner::mouseReleaseEvent(QMouseEvent *e) { void StickersInner::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = _pressed;
_pressed = -2;
if (_section == Section::Featured && _selected < 0 && pressed >= 0) {
setCursor(style::cur_default);
}
if (_saving) return; if (_saving) return;
_mouse = e->globalPos(); _mouse = e->globalPos();
onUpdateSelected(); onUpdateSelected();
if (_removeDown == _removeSel && _removeSel >= 0) { if (_actionDown == _actionSel && _actionSel >= 0) {
_rows[_removeDown]->disabled = !_rows[_removeDown]->disabled; if (_section == Section::Installed) {
_rows[_actionDown]->disabled = !_rows[_actionDown]->disabled;
} else {
installSet(_rows[_actionDown]->id);
}
} else if (_dragging >= 0) { } else if (_dragging >= 0) {
QPoint local(mapFromGlobal(_mouse)); QPoint local(mapFromGlobal(_mouse));
_rows[_dragging]->yadd.start(0); _rows[_dragging]->yadd.start(0);
@ -594,13 +696,66 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) {
} }
_dragging = _started = -1; _dragging = _started = -1;
} else if (pressed == _selected) {
if (_selected == -1) {
_selected = -2;
Ui::showLayer(new StickersBox(Section::Featured), KeepOtherLayers);
} else if (_selected >= 0 && _section == Section::Featured) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(_rows.at(pressed)->id);
if (it != sets.cend()) {
_selected = -2;
Ui::showLayer(new StickerSetBox(Stickers::inputSetId(*it)), KeepOtherLayers);
}
}
} }
if (_removeDown >= 0) { if (_actionDown >= 0) {
update(0, _itemsTop + _removeDown * _rowHeight, width(), _rowHeight); update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
_removeDown = -1; _actionDown = -1;
} }
} }
void StickersInner::leaveEvent(QEvent *e) {
_mouse = QPoint(-1, -1);
onUpdateSelected();
}
void StickersInner::installSet(uint64 setId) {
auto &sets = Global::RefStickerSets();
auto it = sets.find(setId);
if (it == sets.cend()) {
rebuild();
return;
}
MTP::send(MTPmessages_InstallStickerSet(Stickers::inputSetId(*it), MTP_boolFalse()));
it->flags &= ~(MTPDstickerSet::Flag::f_disabled | MTPDstickerSet_ClientFlag::f_unread);
it->flags |= MTPDstickerSet::Flag::f_installed;
auto &order = Global::RefStickerSetsOrder();
int insertAtIndex = 0, currentIndex = order.indexOf(setId);
if (currentIndex != insertAtIndex) {
if (currentIndex > 0) {
order.removeAt(currentIndex);
}
order.insert(insertAtIndex, setId);
}
auto custom = sets.find(Stickers::CustomSetId);
if (custom != sets.cend()) {
for_const (auto sticker, it->stickers) {
int removeIndex = custom->stickers.indexOf(sticker);
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
}
if (custom->stickers.isEmpty()) {
sets.erase(custom);
}
}
Local::writeStickers();
emit App::main()->stickersUpdated();
}
void StickersInner::step_shifting(uint64 ms, bool timer) { void StickersInner::step_shifting(uint64 ms, bool timer) {
bool animating = false; bool animating = false;
int32 updateMin = -1, updateMax = 0; int32 updateMin = -1, updateMax = 0;
@ -653,72 +808,123 @@ void StickersInner::clear() {
_aboveShadowFadeStart = 0; _aboveShadowFadeStart = 0;
_aboveShadowFadeOpacity = anim::fvalue(0, 0); _aboveShadowFadeOpacity = anim::fvalue(0, 0);
_a_shifting.stop(); _a_shifting.stop();
_above = _dragging = _started = -1; _above = _dragging = _started = -1;
_selected = -1; _selected = -2;
_removeDown = -1; _pressed = -2;
setRemoveSel(-1); _actionDown = -1;
update(); setActionSel(-1);
update();
} }
void StickersInner::setRemoveSel(int32 removeSel) { void StickersInner::setActionSel(int32 actionSel) {
if (removeSel != _removeSel) { if (actionSel != _actionSel) {
if (_removeSel >= 0) update(0, _itemsTop + _removeSel * _rowHeight, width(), _rowHeight); if (_actionSel >= 0) update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
_removeSel = removeSel; _actionSel = actionSel;
if (_removeSel >= 0) update(0, _itemsTop + _removeSel * _rowHeight, width(), _rowHeight); if (_actionSel >= 0) update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
setCursor((_removeSel >= 0 && (_removeDown < 0 || _removeDown == _removeSel)) ? style::cur_pointer : style::cur_default); if (_section == Section::Installed) {
setCursor((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel)) ? style::cur_pointer : style::cur_default);
}
} }
} }
void StickersInner::rebuild() { void StickersInner::rebuild() {
QList<StickerSetRow*> rows, rowsDisabled; QList<StickerSetRow*> rows, rowsDisabled;
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); _itemsTop = st::membersPadding.top();
int32 namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x() - qMax(qMax(_returnWidth, _removeWidth), _restoreWidth); _featuredHeight = 0;
if (_section == Section::Installed && !Global::FeaturedStickerSetsOrder().isEmpty()) {
_featuredHeight = st::stickersFeaturedHeight;
_itemsTop += _featuredHeight + 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(_returnWidth, _removeWidth), _restoreWidth);
} else {
namew -= _addWidth - st::defaultActiveButton.width;
}
clear(); clear();
auto &order = Global::StickerSetsOrder(); auto &order = (_section == Section::Installed) ? Global::StickerSetsOrder() : Global::FeaturedStickerSetsOrder();
_animStartTimes.reserve(order.size()); _animStartTimes.reserve(order.size());
auto &sets = Global::StickerSets(); auto &sets = Global::StickerSets();
for (int i = 0, l = order.size(); i < l; ++i) { for_const (auto setId, order) {
auto it = sets.constFind(order.at(i)); auto it = sets.constFind(setId);
if (it != sets.cend()) { if (it == sets.cend()) {
bool disabled = (it->flags & MTPDstickerSet::Flag::f_disabled); continue;
}
DocumentData *sticker = it->stickers.isEmpty() ? 0 : it->stickers.at(0); bool installed = (it->flags & MTPDstickerSet::Flag::f_installed);
int32 pixw = 0, pixh = 0; bool disabled = (_section == Section::Installed) && (it->flags & MTPDstickerSet::Flag::f_disabled);
if (sticker) { bool official = (it->flags & MTPDstickerSet::Flag::f_official);
pixw = sticker->thumb->width(); bool unread = (_section == Section::Featured) && _unreadSets.contains(it->id);
pixh = sticker->thumb->height(); if (!unread && _section == Section::Featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
if (pixw > st::contactsPhotoSize) { unread = true;
if (pixw > pixh) { _unreadSets.insert(it->id);
pixh = (pixh * st::contactsPhotoSize) / pixw; }
pixw = st::contactsPhotoSize;
} else { DocumentData *sticker = it->stickers.isEmpty() ? 0 : it->stickers.at(0);
pixw = (pixw * st::contactsPhotoSize) / pixh; int32 pixw = 0, pixh = 0;
pixh = st::contactsPhotoSize; if (sticker) {
} pixw = sticker->thumb->width();
} else if (pixh > st::contactsPhotoSize) { 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; pixw = (pixw * st::contactsPhotoSize) / pixh;
pixh = st::contactsPhotoSize; pixh = st::contactsPhotoSize;
} }
} else if (pixh > st::contactsPhotoSize) {
pixw = (pixw * st::contactsPhotoSize) / pixh;
pixh = st::contactsPhotoSize;
} }
QString title = it->title; }
int32 titleWidth = st::contactsNameFont->width(title); QString title = it->title;
if (titleWidth > namew) { int32 titleWidth = st::contactsNameFont->width(title);
title = st::contactsNameFont->elided(title, namew); if (titleWidth > namew) {
} title = st::contactsNameFont->elided(title, namew);
bool official = (it->flags & MTPDstickerSet::Flag::f_official); }
(disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, official, disabled, pixw, pixh)); (disabled ? rowsDisabled : rows).push_back(new StickerSetRow(it->id, sticker, it->stickers.size(), title, installed, official, unread, disabled, pixw, pixh));
_animStartTimes.push_back(0); _animStartTimes.push_back(0);
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
App::api()->scheduleStickerSetRequest(it->id, it->access); App::api()->scheduleStickerSetRequest(it->id, it->access);
}
} }
} }
App::api()->requestStickerSets(); App::api()->requestStickerSets();
_rows = rows + rowsDisabled; _rows = rows + rowsDisabled;
resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom()); resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersPadding.bottom());
if (_section == Section::Featured && Global::FeaturedStickerSetsUnreadCount()) {
Global::SetFeaturedStickerSetsUnreadCount(0);
for (auto &set : Global::RefStickerSets()) {
set.flags &= ~MTPDstickerSet_ClientFlag::f_unread;
}
MTP::send(MTPmessages_ReadFeaturedStickers(), rpcDone(&StickersInner::readFeaturedDone), rpcFail(&StickersInner::readFeaturedFail));
}
}
void StickersInner::readFeaturedDone(const MTPBool &result) {
Local::writeStickers();
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;
} }
QVector<uint64> StickersInner::getOrder() const { QVector<uint64> StickersInner::getOrder() const {
@ -755,27 +961,38 @@ StickersInner::~StickersInner() {
clear(); clear();
} }
StickersBox::StickersBox() : ItemListBox(st::boxScroll) } // namespace internal
, _save(this, lang(lng_settings_save), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) StickersBox::StickersBox(Section section) : ItemListBox(st::boxScroll)
, _section(section)
, _inner(section)
, _reorderRequest(0) , _reorderRequest(0)
, _topShadow(this, st::contactsAboutShadow) , _topShadow(this, st::contactsAboutShadow)
, _bottomShadow(this)
, _scrollDelta(0) , _scrollDelta(0)
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left()) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left())
, _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) , _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth) {
, _aboutHeight(st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom()) {
ItemListBox::init(&_inner, st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(), st::boxTitleHeight + _aboutHeight); int bottomSkip = st::boxPadding.bottom();
if (_section == Section::Installed) {
_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
_save = new BoxButton(this, lang(lng_settings_save), st::defaultBoxButton);
connect(_save, SIGNAL(clicked()), this, SLOT(onSave()));
_cancel = new BoxButton(this, lang(lng_cancel), st::cancelBoxButton);
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
_bottomShadow = new ScrollableBoxShadow(this);
bottomSkip = st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom();
}
ItemListBox::init(_inner, bottomSkip, st::boxTitleHeight + _aboutHeight);
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated())); connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated()));
App::main()->updateStickers(); App::main()->updateStickers();
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); connect(_inner, SIGNAL(checkDraggingScroll(int)), this, SLOT(onCheckDraggingScroll(int)));
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); connect(_inner, SIGNAL(noDraggingScroll()), this, SLOT(onNoDraggingScroll()));
connect(&_inner, SIGNAL(checkDraggingScroll(int)), this, SLOT(onCheckDraggingScroll(int)));
connect(&_inner, SIGNAL(noDraggingScroll()), this, SLOT(onNoDraggingScroll()));
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer())); connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
_scrollTimer.setSingleShot(false); _scrollTimer.setSingleShot(false);
@ -785,7 +1002,11 @@ StickersBox::StickersBox() : ItemListBox(st::boxScroll)
} }
int32 StickersBox::countHeight() const { int32 StickersBox::countHeight() const {
return st::boxTitleHeight + _aboutHeight + _inner.height() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); int bottomSkip = st::boxPadding.bottom();
if (_section == Section::Installed) {
bottomSkip = st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom();
}
return st::boxTitleHeight + _aboutHeight + _inner->height() + bottomSkip;
} }
void StickersBox::disenableDone(const MTPBool & result, mtpRequestId req) { void StickersBox::disenableDone(const MTPBool & result, mtpRequestId req) {
@ -805,7 +1026,7 @@ bool StickersBox::disenableFail(const RPCError &error, mtpRequestId req) {
} }
void StickersBox::saveOrder() { void StickersBox::saveOrder() {
QVector<uint64> order = _inner.getOrder(); auto order = _inner->getOrder();
if (order.size() > 1) { if (order.size() > 1) {
QVector<MTPlong> mtpOrder; QVector<MTPlong> mtpOrder;
mtpOrder.reserve(order.size()); mtpOrder.reserve(order.size());
@ -839,9 +1060,11 @@ void StickersBox::paintEvent(QPaintEvent *e) {
paintTitle(p, lang(lng_stickers_packs)); paintTitle(p, lang(lng_stickers_packs));
p.translate(0, st::boxTitleHeight); p.translate(0, st::boxTitleHeight);
p.fillRect(0, 0, width(), _aboutHeight, st::contactsAboutBg); if (_aboutHeight > 0) {
p.setPen(st::stickersReorderFg); p.fillRect(0, 0, width(), _aboutHeight, st::contactsAboutBg);
_about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center); p.setPen(st::stickersReorderFg);
_about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center);
}
} }
void StickersBox::closePressed() { void StickersBox::closePressed() {
@ -862,18 +1085,20 @@ void StickersBox::closePressed() {
void StickersBox::resizeEvent(QResizeEvent *e) { void StickersBox::resizeEvent(QResizeEvent *e) {
ItemListBox::resizeEvent(e); ItemListBox::resizeEvent(e);
_save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); _inner->resize(width(), _inner->height());
_cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y());
_inner.resize(width(), _inner.height());
_topShadow.setGeometry(0, st::boxTitleHeight + _aboutHeight, width(), st::lineWidth); _topShadow.setGeometry(0, st::boxTitleHeight + _aboutHeight, width(), st::lineWidth);
_bottomShadow.setGeometry(0, height() - st::boxButtonPadding.bottom() - _save.height() - st::boxButtonPadding.top() - st::lineWidth, width(), st::lineWidth); _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0);
_inner.setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); if (_save) {
_save->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save->height());
_cancel->moveToRight(st::boxButtonPadding.right() + _save->width() + st::boxButtonPadding.left(), _save->y());
_bottomShadow->setGeometry(0, height() - st::boxButtonPadding.bottom() - _save->height() - st::boxButtonPadding.top() - st::lineWidth, width(), st::lineWidth);
}
} }
void StickersBox::onStickersUpdated() { void StickersBox::onStickersUpdated() {
_inner.rebuild(); _inner->rebuild();
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight))); setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
_inner.setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0); _inner->setVisibleScrollbar((_scroll.scrollTopMax() > 0) ? (st::boxScroll.width - st::boxScroll.deltax) : 0);
} }
void StickersBox::onCheckDraggingScroll(int localY) { void StickersBox::onCheckDraggingScroll(int localY) {
@ -901,7 +1126,7 @@ void StickersBox::onScrollTimer() {
} }
void StickersBox::onSave() { void StickersBox::onSave() {
if (!_inner.savingStart()) { if (!_inner->savingStart()) {
return; return;
} }
@ -909,7 +1134,7 @@ void StickersBox::onSave() {
RecentStickerPack &recent(cGetRecentStickers()); RecentStickerPack &recent(cGetRecentStickers());
auto &sets = Global::RefStickerSets(); auto &sets = Global::RefStickerSets();
QVector<uint64> reorder = _inner.getOrder(), disabled = _inner.getDisabledSets(); QVector<uint64> reorder = _inner->getOrder(), disabled = _inner->getDisabledSets();
for (int32 i = 0, l = disabled.size(); i < l; ++i) { for (int32 i = 0, l = disabled.size(); i < l; ++i) {
auto it = sets.find(disabled.at(i)); auto it = sets.find(disabled.at(i));
if (it != sets.cend()) { if (it != sets.cend()) {
@ -932,12 +1157,20 @@ void StickersBox::onSave() {
if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex); if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex);
if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)) { if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)) {
sets.erase(it); sets.erase(it);
} else {
it->flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet::Flag::f_disabled);
} }
} }
} }
} }
} }
Stickers::Order &order(Global::RefStickerSetsOrder());
// Clear all installed flags, set only for sets from order.
for (auto &set : sets) {
set.flags &= ~MTPDstickerSet::Flag::f_installed;
}
auto &order(Global::RefStickerSetsOrder());
order.clear(); order.clear();
for (int i = 0, l = reorder.size(); i < l; ++i) { for (int i = 0, l = reorder.size(); i < l; ++i) {
auto it = sets.find(reorder.at(i)); auto it = sets.find(reorder.at(i));
@ -948,13 +1181,14 @@ void StickersBox::onSave() {
it->flags &= ~MTPDstickerSet::Flag::f_disabled; it->flags &= ~MTPDstickerSet::Flag::f_disabled;
} }
order.push_back(reorder.at(i)); order.push_back(reorder.at(i));
it->flags |= MTPDstickerSet::Flag::f_installed;
} }
} }
for (auto it = sets.begin(); it != sets.cend();) { for (auto it = sets.begin(); it != sets.cend();) {
if (it->id == Stickers::CustomSetId if (it->id == Stickers::CustomSetId
|| it->id == Stickers::RecentSetId || it->id == Stickers::RecentSetId
|| (it->flags & MTPDstickerSet_ClientFlag::f_featured) || (it->flags & MTPDstickerSet_ClientFlag::f_featured)
|| order.contains(it->id)) { || (it->flags & MTPDstickerSet::Flag::f_installed)) {
++it; ++it;
} else { } else {
it = sets.erase(it); it = sets.erase(it);
@ -973,18 +1207,22 @@ void StickersBox::onSave() {
} }
void StickersBox::hideAll() { void StickersBox::hideAll() {
_save.hide();
_cancel.hide();
_topShadow.hide(); _topShadow.hide();
_bottomShadow.hide(); if (_save) {
_save->hide();
_cancel->hide();
_bottomShadow->hide();
}
ItemListBox::hideAll(); ItemListBox::hideAll();
} }
void StickersBox::showAll() { void StickersBox::showAll() {
_save.show();
_cancel.show();
_topShadow.show(); _topShadow.show();
_bottomShadow.show(); if (_save) {
_save->show();
_cancel->show();
_bottomShadow->show();
}
ItemListBox::showAll(); ItemListBox::showAll();
} }

View File

@ -95,7 +95,6 @@ public:
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e);
public slots: public slots:
void onStickersUpdated(); void onStickersUpdated();
void onAddStickers(); void onAddStickers();
void onShareStickers(); void onShareStickers();
@ -103,115 +102,38 @@ public slots:
void onScroll(); void onScroll();
signals: private slots:
void onInstalled(uint64 id);
signals:
void installed(uint64 id); void installed(uint64 id);
protected: protected:
void hideAll(); void hideAll();
void showAll(); void showAll();
private: private:
StickerSetInner _inner; StickerSetInner _inner;
ScrollableBoxShadow _shadow; ScrollableBoxShadow _shadow;
BoxButton _add, _share, _cancel, _done; BoxButton _add, _share, _cancel, _done;
QString _title; QString _title;
}; };
class StickersInner : public TWidget { namespace internal {
Q_OBJECT class StickersInner;
} // namespace internal
public:
StickersInner();
void paintEvent(QPaintEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void rebuild();
bool savingStart() {
if (_saving) return false;
_saving = true;
return true;
}
QVector<uint64> getOrder() const;
QVector<uint64> getDisabledSets() const;
void setVisibleScrollbar(int32 width);
~StickersInner();
signals:
void checkDraggingScroll(int localY);
void noDraggingScroll();
public slots:
void onUpdateSelected();
private:
void step_shifting(uint64 ms, bool timer);
void paintRow(Painter &p, int32 index);
void clear();
void setRemoveSel(int32 removeSel);
float64 aboveShadowOpacity() const;
int32 _rowHeight;
struct StickerSetRow {
StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, bool official, bool disabled, int32 pixw, int32 pixh) : id(id)
, sticker(sticker)
, count(count)
, title(title)
, official(official)
, disabled(disabled)
, pixw(pixw)
, pixh(pixh)
, yadd(0, 0) {
}
uint64 id;
DocumentData *sticker;
int32 count;
QString title;
bool official, disabled;
int32 pixw, pixh;
anim::ivalue yadd;
};
typedef QList<StickerSetRow*> StickerSetRows;
StickerSetRows _rows;
QList<uint64> _animStartTimes;
uint64 _aboveShadowFadeStart;
anim::fvalue _aboveShadowFadeOpacity;
Animation _a_shifting;
int32 _itemsTop;
bool _saving;
int32 _removeSel, _removeDown, _removeWidth, _returnWidth, _restoreWidth;
QPoint _mouse;
int32 _selected;
QPoint _dragStart;
int32 _started, _dragging, _above;
BoxShadow _aboveShadow;
int32 _scrollbar;
};
class StickersBox : public ItemListBox, public RPCSender { class StickersBox : public ItemListBox, public RPCSender {
Q_OBJECT Q_OBJECT
public: public:
StickersBox(); enum class Section {
Installed,
Featured,
};
StickersBox(Section section = Section::Installed);
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
@ -242,20 +164,135 @@ private:
bool reorderFail(const RPCError &result); bool reorderFail(const RPCError &result);
void saveOrder(); void saveOrder();
StickersInner _inner; Section _section;
BoxButton _save, _cancel;
ChildWidget<internal::StickersInner> _inner;
ChildWidget<BoxButton> _save = { nullptr };
ChildWidget<BoxButton> _cancel = { nullptr };
QMap<mtpRequestId, NullType> _disenableRequests; QMap<mtpRequestId, NullType> _disenableRequests;
mtpRequestId _reorderRequest; mtpRequestId _reorderRequest;
PlainShadow _topShadow; PlainShadow _topShadow;
ScrollableBoxShadow _bottomShadow; ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
QTimer _scrollTimer; QTimer _scrollTimer;
int32 _scrollDelta; int32 _scrollDelta;
int32 _aboutWidth; int _aboutWidth = 0;
Text _about; Text _about;
int32 _aboutHeight; int _aboutHeight = 0;
}; };
int32 stickerPacksCount(bool includeDisabledOfficial = false); int32 stickerPacksCount(bool includeDisabledOfficial = false);
namespace internal {
class StickersInner : public TWidget, public RPCSender {
Q_OBJECT
public:
using Section = StickersBox::Section;
StickersInner(Section section);
void rebuild();
bool savingStart() {
if (_saving) return false;
_saving = true;
return true;
}
QVector<uint64> getOrder() const;
QVector<uint64> getDisabledSets() const;
void setVisibleScrollbar(int32 width);
~StickersInner();
protected:
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void leaveEvent(QEvent *e) override;
signals:
void checkDraggingScroll(int localY);
void noDraggingScroll();
public slots:
void onUpdateSelected();
private:
void paintFeaturedButton(Painter &p) const;
void step_shifting(uint64 ms, bool timer);
void paintRow(Painter &p, int32 index);
void clear();
void setActionSel(int32 actionSel);
float64 aboveShadowOpacity() const;
void installSet(uint64 setId);
void readFeaturedDone(const MTPBool &result);
bool readFeaturedFail(const RPCError &error);
Section _section;
int32 _rowHeight;
struct StickerSetRow {
StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, bool installed, bool official, bool unread, bool disabled, int32 pixw, int32 pixh) : id(id)
, sticker(sticker)
, count(count)
, title(title)
, installed(installed)
, official(official)
, unread(unread)
, disabled(disabled)
, pixw(pixw)
, pixh(pixh)
, yadd(0, 0) {
}
uint64 id;
DocumentData *sticker;
int32 count;
QString title;
bool installed, official, unread, disabled;
int32 pixw, pixh;
anim::ivalue yadd;
};
typedef QList<StickerSetRow*> StickerSetRows;
StickerSetRows _rows;
QList<uint64> _animStartTimes;
uint64 _aboveShadowFadeStart = 0;
anim::fvalue _aboveShadowFadeOpacity = { 0., 0. };
Animation _a_shifting;
int32 _itemsTop;
bool _saving = false;
int _actionSel = -1;
int _actionDown = -1;
int _removeWidth, _returnWidth, _restoreWidth;
QString _addText;
int _addWidth;
int _featuredHeight = 0;
// Remember all the unread set ids to display unread dots.
OrderedSet<uint64> _unreadSets;
QPoint _mouse;
int _selected = -2; // -1 - featured stickers button
int _pressed = -2;
QPoint _dragStart;
int _started = -1;
int _dragging = -1;
int _above = -1;
BoxShadow _aboveShadow;
int32 _scrollbar = 0;
};
} // namespace internal

View File

@ -29,7 +29,6 @@ dialogsUnreadBgActive: #ffffff;
dialogsUnreadBgMutedActive: #d3e2ee; dialogsUnreadBgMutedActive: #d3e2ee;
dialogsUnreadFont: font(12px bold); dialogsUnreadFont: font(12px bold);
dialogsUnreadHeight: 19px; dialogsUnreadHeight: 19px;
dialogsUnreadTop: 1px;
dialogsUnreadPadding: 5px; dialogsUnreadPadding: 5px;
dialogsBg: windowBg; dialogsBg: windowBg;

View File

@ -222,7 +222,7 @@ void paintUnreadCount(Painter &p, const QString &text, int x, int y, const Unrea
p.setFont(st.font); p.setFont(st.font);
p.setPen(st.active ? st::dialogsUnreadFgActive : st::dialogsUnreadFg); p.setPen(st.active ? st::dialogsUnreadFgActive : st::dialogsUnreadFg);
p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + st::dialogsUnreadTop + st.font->ascent, text); p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + (unreadRectHeight - st.font->height) / 2 + st.font->ascent, text);
} }
void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) { void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) {
@ -258,7 +258,7 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele
auto counter = QString::number(unreadCount); auto counter = QString::number(unreadCount);
auto mutedCounter = history->mute(); auto mutedCounter = history->mute();
int unreadRight = w - st::dialogsPadding.x(); int unreadRight = w - st::dialogsPadding.x();
int unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - st::dialogsUnreadTop; int unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
int unreadWidth = 0; int unreadWidth = 0;
UnreadBadgeStyle st; UnreadBadgeStyle st;
@ -297,7 +297,7 @@ void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool o
int unreadTop = (st::dialogsImportantBarHeight - st::dialogsUnreadHeight) / 2; int unreadTop = (st::dialogsImportantBarHeight - st::dialogsUnreadHeight) / 2;
bool mutedHidden = (current == Dialogs::Mode::Important); bool mutedHidden = (current == Dialogs::Mode::Important);
QString text = mutedHidden ? qsl("Show all chats") : qsl("Hide muted chats"); QString text = mutedHidden ? qsl("Show all chats") : qsl("Hide muted chats");
int textBaseline = unreadTop + st::dialogsUnreadTop + st::dialogsUnreadFont->ascent; int textBaseline = unreadTop + (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2 + st::dialogsUnreadFont->ascent;
p.drawText(st::dialogsPadding.x(), textBaseline, text); p.drawText(st::dialogsPadding.x(), textBaseline, text);
if (mutedHidden) { if (mutedHidden) {

View File

@ -38,6 +38,8 @@ void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool o
enum UnreadBadgeSize { enum UnreadBadgeSize {
UnreadBadgeInDialogs = 0, UnreadBadgeInDialogs = 0,
UnreadBadgeInHistoryToDown, UnreadBadgeInHistoryToDown,
UnreadBadgeInStickersPanel,
UnreadBadgeInStickersBox,
UnreadBadgeSizesCount UnreadBadgeSizesCount
}; };

View File

@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "boxes/stickersetbox.h" #include "boxes/stickersetbox.h"
#include "inline_bots/inline_bot_result.h" #include "inline_bots/inline_bot_result.h"
#include "inline_bots/inline_bot_layout_item.h" #include "inline_bots/inline_bot_layout_item.h"
#include "dialogs/dialogs_layout.h"
#include "historywidget.h" #include "historywidget.h"
#include "localstorage.h" #include "localstorage.h"
#include "lang.h" #include "lang.h"
@ -2829,6 +2830,20 @@ void EmojiPan::onSaveConfigDelayed(int32 delay) {
_saveConfigTimer.start(delay); _saveConfigTimer.start(delay);
} }
void EmojiPan::paintStickerSettingsIcon(Painter &p) const {
int settingsLeft = _iconsLeft + 7 * st::rbEmoji.width;
p.drawSpriteLeft(settingsLeft + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::stickersSettings);
if (auto unread = Global::FeaturedStickerSetsUnreadCount()) {
Dialogs::Layout::UnreadBadgeStyle unreadSt;
unreadSt.sizeId = Dialogs::Layout::UnreadBadgeInStickersPanel;
unreadSt.size = st::stickersSettingsUnreadSize;
int unreadRight = settingsLeft + st::rbEmoji.width - st::stickersSettingsUnreadPosition.x();
if (rtl()) unreadRight = width() - unreadRight;
int unreadTop = _iconsTop + st::stickersSettingsUnreadPosition.y();
Dialogs::Layout::paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, unreadSt);
}
}
void EmojiPan::paintEvent(QPaintEvent *e) { void EmojiPan::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
@ -2846,7 +2861,7 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
p.fillRect(myrtlrect(r.x() + r.width() - st::emojiScroll.width, r.y(), st::emojiScroll.width, e_scroll.height()), st::white->b); p.fillRect(myrtlrect(r.x() + r.width() - st::emojiScroll.width, r.y(), st::emojiScroll.width, e_scroll.height()), st::white->b);
if (_stickersShown && s_inner.showSectionIcons()) { if (_stickersShown && s_inner.showSectionIcons()) {
p.fillRect(r.left(), _iconsTop, r.width(), st::rbEmoji.height, st::emojiPanCategories); p.fillRect(r.left(), _iconsTop, r.width(), st::rbEmoji.height, st::emojiPanCategories);
p.drawSpriteLeft(_iconsLeft + 7 * st::rbEmoji.width + st::rbEmojiRecent.imagePos.x(), _iconsTop + st::rbEmojiRecent.imagePos.y(), width(), st::stickersSettings); paintStickerSettingsIcon(p);
if (!_icons.isEmpty()) { if (!_icons.isEmpty()) {
int32 x = _iconsLeft, i = 0, selxrel = _iconsLeft + _iconSelX.current(), selx = selxrel - _iconsX.current(); int32 x = _iconsLeft, i = 0, selxrel = _iconsLeft + _iconSelX.current(), selx = selxrel - _iconsX.current();
@ -3093,6 +3108,7 @@ void EmojiPan::refreshStickers() {
if (!_stickersShown) { if (!_stickersShown) {
s_inner.preloadImages(); s_inner.preloadImages();
} }
update();
} }
void EmojiPan::refreshSavedGifs() { void EmojiPan::refreshSavedGifs() {

View File

@ -656,6 +656,7 @@ signals:
void updateStickers(); void updateStickers();
private: private:
void paintStickerSettingsIcon(Painter &p) const;
void validateSelectedIcon(bool animated = false); void validateSelectedIcon(bool animated = false);

View File

@ -561,7 +561,7 @@ struct Data {
Stickers::Order StickerSetsOrder; Stickers::Order StickerSetsOrder;
uint64 LastStickersUpdate = 0; uint64 LastStickersUpdate = 0;
Stickers::Order FeaturedStickerSetsOrder; Stickers::Order FeaturedStickerSetsOrder;
Stickers::UnreadMap FeaturedUnreadSets; int FeaturedStickerSetsUnreadCount = 0;
uint64 LastFeaturedStickersUpdate = 0; uint64 LastFeaturedStickersUpdate = 0;
MTP::DcOptions DcOptions; MTP::DcOptions DcOptions;
@ -630,7 +630,7 @@ DefineVar(Global, Stickers::Sets, StickerSets);
DefineVar(Global, Stickers::Order, StickerSetsOrder); DefineVar(Global, Stickers::Order, StickerSetsOrder);
DefineVar(Global, uint64, LastStickersUpdate); DefineVar(Global, uint64, LastStickersUpdate);
DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder); DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder);
DefineVar(Global, Stickers::UnreadMap, FeaturedUnreadSets); DefineVar(Global, int, FeaturedStickerSetsUnreadCount);
DefineVar(Global, uint64, LastFeaturedStickersUpdate); DefineVar(Global, uint64, LastFeaturedStickersUpdate);
DefineVar(Global, MTP::DcOptions, DcOptions); DefineVar(Global, MTP::DcOptions, DcOptions);

View File

@ -199,7 +199,13 @@ struct Set {
}; };
using Sets = QMap<uint64, Set>; using Sets = QMap<uint64, Set>;
using Order = QList<uint64>; using Order = QList<uint64>;
using UnreadMap = OrderedSet<uint64>;
inline MTPInputStickerSet inputSetId(const Set &set) {
if (set.id && set.access) {
return MTP_inputStickerSetID(MTP_long(set.id), MTP_long(set.access));
}
return MTP_inputStickerSetShortName(MTP_string(set.shortName));
}
} // namespace Stickers } // namespace Stickers
@ -250,7 +256,7 @@ DeclareVar(Stickers::Sets, StickerSets);
DeclareVar(Stickers::Order, StickerSetsOrder); DeclareVar(Stickers::Order, StickerSetsOrder);
DeclareVar(uint64, LastStickersUpdate); DeclareVar(uint64, LastStickersUpdate);
DeclareVar(Stickers::Order, FeaturedStickerSetsOrder); DeclareVar(Stickers::Order, FeaturedStickerSetsOrder);
DeclareVar(Stickers::UnreadMap, FeaturedUnreadSets); DeclareVar(int, FeaturedStickerSetsUnreadCount);
DeclareVar(uint64, LastFeaturedStickersUpdate); DeclareVar(uint64, LastFeaturedStickersUpdate);
DeclareVar(MTP::DcOptions, DcOptions); DeclareVar(MTP::DcOptions, DcOptions);

View File

@ -196,14 +196,14 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
} }
return true; return true;
}; };
auto filterNotPassedByName = [this](UserData *user) -> bool { auto filterNotPassedByName = [this, &filterNotPassedByUsername](UserData *user) -> bool {
for_const (auto &namePart, user->names) { for_const (auto &namePart, user->names) {
if (namePart.startsWith(_filter, Qt::CaseInsensitive)) { if (namePart.startsWith(_filter, Qt::CaseInsensitive)) {
bool exactUsername = (user->username.compare(_filter, Qt::CaseInsensitive) == 0); bool exactUsername = (user->username.compare(_filter, Qt::CaseInsensitive) == 0);
return exactUsername; return exactUsername;
} }
} }
return true; return filterNotPassedByUsername(user);
}; };
bool listAllSuggestions = _filter.isEmpty(); bool listAllSuggestions = _filter.isEmpty();

View File

@ -29,6 +29,8 @@ historyToDownArrow: icon {
{ "history_down_arrow", #b9b9b9, point(14px, 19px) }, { "history_down_arrow", #b9b9b9, point(14px, 19px) },
}; };
historyToDownPaddingTop: 10px; historyToDownPaddingTop: 10px;
historyToDownBadgeFont: semiboldFont;
historyToDownBadgeSize: 22px;
membersInnerScroll: flatScroll(solidScroll) { membersInnerScroll: flatScroll(solidScroll) {
deltat: 3px; deltat: 3px;
@ -42,5 +44,3 @@ membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
scrollMargin: margins(0px, 5px, 0px, 5px); scrollMargin: margins(0px, 5px, 0px, 5px);
scrollPadding: margins(0px, 3px, 8px, 3px); scrollPadding: margins(0px, 3px, 8px, 3px);
} }
historyToDownBadgeFont: semiboldFont;
historyToDownBadgeSize: 22px;

View File

@ -3667,7 +3667,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
it->access = set.vaccess_hash.v; it->access = set.vaccess_hash.v;
it->title = title; it->title = title;
it->shortName = qs(set.vshort_name); it->shortName = qs(set.vshort_name);
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded); auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded);
it->flags = set.vflags.v | clientFlags; it->flags = set.vflags.v | clientFlags;
if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) { if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) {
it->count = set.vcount.v; it->count = set.vcount.v;
@ -3739,6 +3739,11 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
if (stickers.type() != mtpc_messages_featuredStickers) return; 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(); auto &setsOrder = Global::RefFeaturedStickerSetsOrder();
@ -3755,13 +3760,23 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
auto it = sets.find(set.vid.v); auto it = sets.find(set.vid.v);
QString title = stickerSetTitle(set); QString title = stickerSetTitle(set);
if (it == sets.cend()) { if (it == sets.cend()) {
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 | MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded)); auto clientFlags = MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded;
if (unread.contains(set.vid.v)) {
clientFlags |= 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 | clientFlags));
} else { } else {
it->access = set.vaccess_hash.v; it->access = set.vaccess_hash.v;
it->title = title; it->title = title;
it->shortName = qs(set.vshort_name); it->shortName = qs(set.vshort_name);
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded); auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_unread | MTPDstickerSet_ClientFlag::f_not_loaded);
it->flags = set.vflags.v | clientFlags | MTPDstickerSet_ClientFlag::f_featured; it->flags = set.vflags.v | clientFlags;
it->flags |= MTPDstickerSet_ClientFlag::f_featured;
if (unread.contains(it->id)) {
it->flags |= MTPDstickerSet_ClientFlag::f_unread;
} else {
it->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
}
if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) { if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) {
it->count = set.vcount.v; it->count = set.vcount.v;
it->hash = set.vhash.v; it->hash = set.vhash.v;
@ -3774,21 +3789,21 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
} }
} }
} }
for (Stickers::Sets::iterator it = sets.begin(), e = sets.end(); it != e;) {
int unreadCount = 0;
for (auto it = sets.begin(), e = sets.end(); it != e;) {
bool installed = (it->flags & MTPDstickerSet::Flag::f_installed); bool installed = (it->flags & MTPDstickerSet::Flag::f_installed);
bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured); bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
if (installed || featured) { if (installed || featured) {
if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
++unreadCount;
}
++it; ++it;
} else { } else {
it = sets.erase(it); it = sets.erase(it);
} }
} }
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
auto &unreadFeatured = Global::RefFeaturedUnreadSets();
unreadFeatured.clear();
for_const (auto &unreadSetId, d.vunread.c_vector().v) {
unreadFeatured.insert(unreadSetId.v);
}
if (Local::countFeaturedStickersHash() != d.vhash.v) { if (Local::countFeaturedStickersHash() != d.vhash.v) {
LOG(("API Error: received featured stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countFeaturedStickersHash())); LOG(("API Error: received featured stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countFeaturedStickersHash()));

View File

@ -3079,7 +3079,6 @@ namespace Local {
} }
size += sizeof(qint32) + (Global::StickerSetsOrder().size() * sizeof(quint64)); size += sizeof(qint32) + (Global::StickerSetsOrder().size() * sizeof(quint64));
size += sizeof(qint32) + (Global::FeaturedStickerSetsOrder().size() * sizeof(quint64)); size += sizeof(qint32) + (Global::FeaturedStickerSetsOrder().size() * sizeof(quint64));
size += sizeof(qint32) + (Global::FeaturedUnreadSets().size() * sizeof(quint64));
if (!_stickersKey) { if (!_stickersKey) {
_stickersKey = genKey(); _stickersKey = genKey();
@ -3094,11 +3093,6 @@ namespace Local {
data.stream << Global::StickerSetsOrder(); data.stream << Global::StickerSetsOrder();
data.stream << Global::FeaturedStickerSetsOrder(); data.stream << Global::FeaturedStickerSetsOrder();
data.stream << qint32(Global::FeaturedUnreadSets().size());
for_const (auto setId, Global::FeaturedUnreadSets()) {
data.stream << quint64(setId);
}
FileWriteDescriptor file(_stickersKey); FileWriteDescriptor file(_stickersKey);
file.writeEncrypted(data); file.writeEncrypted(data);
} }
@ -3200,9 +3194,6 @@ namespace Local {
auto &featuredOrder = Global::RefFeaturedStickerSetsOrder(); auto &featuredOrder = Global::RefFeaturedStickerSetsOrder();
featuredOrder.clear(); featuredOrder.clear();
auto &unreadFeatured = Global::RefFeaturedUnreadSets();
unreadFeatured.clear();
quint32 cnt; quint32 cnt;
QByteArray hash; QByteArray hash;
stickers.stream >> cnt >> hash; // ignore hash, it is counted stickers.stream >> cnt >> hash; // ignore hash, it is counted
@ -3244,6 +3235,8 @@ namespace Local {
} }
auto &set = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))).value(); auto &set = sets.insert(setId, Stickers::Set(setId, setAccess, setTitle, setShortName, 0, setHash, MTPDstickerSet::Flags(setFlags))).value();
// We will set this flags from order lists below.
set.flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_featured);
if (scnt < 0) { // disabled not loaded set if (scnt < 0) { // disabled not loaded set
set.count = -scnt; set.count = -scnt;
continue; continue;
@ -3293,23 +3286,32 @@ namespace Local {
stickers.stream >> order; stickers.stream >> order;
stickers.stream >> featuredOrder; stickers.stream >> featuredOrder;
qint32 unreadCount = 0; // Set flags and count unread featured sets.
stickers.stream >> unreadCount; for_const (auto setId, order) {
for (int i = 0; i < unreadCount; ++i) { auto it = sets.find(setId);
quint64 setId = 0; if (it != sets.cend()) {
stickers.stream >> setId; it->flags |= MTPDstickerSet::Flag::f_installed;
if (setId) {
unreadFeatured.insert(setId);
} }
} }
int unreadCount = 0;
for_const (auto setId, featuredOrder) {
auto it = sets.find(setId);
if (it != sets.cend()) {
it->flags |= MTPDstickerSet_ClientFlag::f_featured;
if (it->flags & MTPDstickerSet_ClientFlag::f_unread) {
++unreadCount;
}
}
}
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
} }
} }
int32 countStickersHash(bool checkOfficial) { int32 countStickersHash(bool checkOfficial) {
uint32 acc = 0; uint32 acc = 0;
bool foundOfficial = false, foundBad = false;; bool foundOfficial = false, foundBad = false;;
const Stickers::Sets &sets(Global::StickerSets()); auto &sets = Global::StickerSets();
const Stickers::Order &order(Global::StickerSetsOrder()); auto &order = Global::StickerSetsOrder();
for (auto i = order.cbegin(), e = order.cend(); i != e; ++i) { for (auto i = order.cbegin(), e = order.cend(); i != e; ++i) {
auto j = sets.constFind(*i); auto j = sets.constFind(*i);
if (j != sets.cend()) { if (j != sets.cend()) {
@ -3328,11 +3330,14 @@ namespace Local {
int32 countFeaturedStickersHash() { int32 countFeaturedStickersHash() {
uint32 acc = 0; uint32 acc = 0;
auto &featured(Global::FeaturedStickerSetsOrder()); auto &sets = Global::StickerSets();
auto &featured = Global::FeaturedStickerSetsOrder();
for_const (auto setId, featured) { for_const (auto setId, featured) {
acc = (acc * 20261) + uint32(setId >> 32); acc = (acc * 20261) + uint32(setId >> 32);
acc = (acc * 20261) + uint32(setId & 0xFFFFFFFF); acc = (acc * 20261) + uint32(setId & 0xFFFFFFFF);
if (Global::FeaturedUnreadSets().contains(setId)) {
auto it = sets.constFind(setId);
if (it != sets.cend() && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
acc = (acc * 20261) + 1U; acc = (acc * 20261) + 1U;
} }
} }

View File

@ -3378,7 +3378,6 @@ void MainWidget::stickersBox(const MTPInputStickerSet &set) {
} }
void MainWidget::onStickersInstalled(uint64 setId) { void MainWidget::onStickersInstalled(uint64 setId) {
emit stickersUpdated();
_history->stickersInstalled(setId); _history->stickersInstalled(setId);
} }
@ -4731,9 +4730,16 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break; } break;
case mtpc_updateReadFeaturedStickers: { case mtpc_updateReadFeaturedStickers: {
Global::RefFeaturedUnreadSets().clear(); for (auto &set : Global::RefStickerSets()) {
Local::writeStickers(); if (set.flags & MTPDstickerSet_ClientFlag::f_unread) {
emit stickersUpdated(); set.flags &= ~MTPDstickerSet_ClientFlag::f_unread;
}
}
if (Global::FeaturedStickerSetsUnreadCount()) {
Global::SetFeaturedStickerSetsUnreadCount(0);
Local::writeStickers();
emit stickersUpdated();
}
} break; } break;
////// Cloud saved GIFs ////// Cloud saved GIFs

View File

@ -1291,7 +1291,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
if (_saveMsgOpacity.current() > 0) { if (_saveMsgOpacity.current() > 0) {
p.setOpacity(_saveMsgOpacity.current()); p.setOpacity(_saveMsgOpacity.current());
App::roundRect(p, _saveMsg, st::medviewSaveMsg, MediaviewSaveCorners); App::roundRect(p, _saveMsg, st::medviewSaveMsg, MediaviewSaveCorners);
p.drawSprite(_saveMsg.topLeft() + st::medviewSaveMsgCheckPos, st::medviewSaveMsgCheck); st::medviewSaveMsgCheck.paint(p, _saveMsg.topLeft() + st::medviewSaveMsgCheckPos, width());
p.setPen(st::white->p); p.setPen(st::white->p);
textstyleSet(&st::medviewSaveAsTextStyle); textstyleSet(&st::medviewSaveAsTextStyle);

View File

@ -1063,8 +1063,11 @@ enum class MTPDstickerSet_ClientFlag : int32 {
// sticker set is one of featured (should be saved locally) // sticker set is one of featured (should be saved locally)
f_featured = (1 << 29), f_featured = (1 << 29),
// sticker set is an unread featured set
f_unread = (1 << 28),
// update this when adding new client side flags // update this when adding new client side flags
MIN_FIELD = (1 << 29), MIN_FIELD = (1 << 28),
}; };
DEFINE_MTP_CLIENT_FLAGS(MTPDstickerSet) DEFINE_MTP_CLIENT_FLAGS(MTPDstickerSet)