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;
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) {
deltat: 48px;
}
@ -1861,6 +1875,9 @@ stickersSettings: sprite(140px, 124px, 21px, 22px);
savedGifsOver: sprite(329px, 286px, 21px, 22px);
savedGifsActive: sprite(350px, 286px, 21px, 22px);
stickersSettingsUnreadSize: 17px;
stickersSettingsUnreadPosition: point(4px, 5px);
emojiPanCategories: #f7f7f7;
rbEmoji: flatCheckbox {
@ -2133,7 +2150,9 @@ mvCaptionRadius: 2px;
mvCaptionBg: #11111180;
mvCaptionFont: font(fsize);
medviewSaveMsgCheck: sprite(311px, 309px, 22px, 18px);
medviewSaveMsgCheck: icon {
{ "mediaview_save_check", #ffffff }
};
medviewSaveMsgFont: font(16px);
medviewSaveMsgPadding: margins(55px, 19px, 29px, 20px);
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_packs" = "Sticker Packs";
"lng_stickers_reorder" = "Click and drag to reorder sticker packs";
"lng_stickers_featured" = "Featured Stickers";
"lng_stickers_remove" = "Delete";
"lng_stickers_return" = "Undo";
"lng_stickers_restore" = "Restore";
"lng_stickers_add" = "Add";
"lng_stickers_count" = "{count:Loading...|# sticker|# stickers}";
"lng_in_dlg_photo" = "Photo";

View file

@ -924,10 +924,10 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
_stickerSetRequests.remove(setId);
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;
const auto &s(d.vset.c_stickerSet());
auto &s(d.vset.c_stickerSet());
auto &sets = Global::RefStickerSets();
auto it = sets.find(setId);
@ -937,7 +937,7 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
it->hash = s.vhash.v;
it->shortName = qs(s.vshort_name);
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 &= ~MTPDstickerSet_ClientFlag::f_not_loaded;

View file

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

View file

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

View file

@ -95,7 +95,6 @@ public:
void resizeEvent(QResizeEvent *e);
public slots:
void onStickersUpdated();
void onAddStickers();
void onShareStickers();
@ -103,115 +102,38 @@ public slots:
void onScroll();
signals:
private slots:
void onInstalled(uint64 id);
signals:
void installed(uint64 id);
protected:
void hideAll();
void showAll();
private:
StickerSetInner _inner;
ScrollableBoxShadow _shadow;
BoxButton _add, _share, _cancel, _done;
QString _title;
};
class StickersInner : public TWidget {
Q_OBJECT
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;
};
namespace internal {
class StickersInner;
} // namespace internal
class StickersBox : public ItemListBox, public RPCSender {
Q_OBJECT
public:
StickersBox();
enum class Section {
Installed,
Featured,
};
StickersBox(Section section = Section::Installed);
void resizeEvent(QResizeEvent *e);
void paintEvent(QPaintEvent *e);
@ -242,20 +164,135 @@ private:
bool reorderFail(const RPCError &result);
void saveOrder();
StickersInner _inner;
BoxButton _save, _cancel;
Section _section;
ChildWidget<internal::StickersInner> _inner;
ChildWidget<BoxButton> _save = { nullptr };
ChildWidget<BoxButton> _cancel = { nullptr };
QMap<mtpRequestId, NullType> _disenableRequests;
mtpRequestId _reorderRequest;
PlainShadow _topShadow;
ScrollableBoxShadow _bottomShadow;
ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
QTimer _scrollTimer;
int32 _scrollDelta;
int32 _aboutWidth;
int _aboutWidth = 0;
Text _about;
int32 _aboutHeight;
int _aboutHeight = 0;
};
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;
dialogsUnreadFont: font(12px bold);
dialogsUnreadHeight: 19px;
dialogsUnreadTop: 1px;
dialogsUnreadPadding: 5px;
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.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) {
@ -258,7 +258,7 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele
auto counter = QString::number(unreadCount);
auto mutedCounter = history->mute();
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;
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;
bool mutedHidden = (current == Dialogs::Mode::Important);
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);
if (mutedHidden) {

View file

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

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "boxes/stickersetbox.h"
#include "inline_bots/inline_bot_result.h"
#include "inline_bots/inline_bot_layout_item.h"
#include "dialogs/dialogs_layout.h"
#include "historywidget.h"
#include "localstorage.h"
#include "lang.h"
@ -2829,6 +2830,20 @@ void EmojiPan::onSaveConfigDelayed(int32 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) {
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);
if (_stickersShown && s_inner.showSectionIcons()) {
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()) {
int32 x = _iconsLeft, i = 0, selxrel = _iconsLeft + _iconSelX.current(), selx = selxrel - _iconsX.current();
@ -3093,6 +3108,7 @@ void EmojiPan::refreshStickers() {
if (!_stickersShown) {
s_inner.preloadImages();
}
update();
}
void EmojiPan::refreshSavedGifs() {

View file

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

View file

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

View file

@ -199,7 +199,13 @@ struct Set {
};
using Sets = QMap<uint64, Set>;
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
@ -250,7 +256,7 @@ DeclareVar(Stickers::Sets, StickerSets);
DeclareVar(Stickers::Order, StickerSetsOrder);
DeclareVar(uint64, LastStickersUpdate);
DeclareVar(Stickers::Order, FeaturedStickerSetsOrder);
DeclareVar(Stickers::UnreadMap, FeaturedUnreadSets);
DeclareVar(int, FeaturedStickerSetsUnreadCount);
DeclareVar(uint64, LastFeaturedStickersUpdate);
DeclareVar(MTP::DcOptions, DcOptions);

View file

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

View file

@ -29,6 +29,8 @@ historyToDownArrow: icon {
{ "history_down_arrow", #b9b9b9, point(14px, 19px) },
};
historyToDownPaddingTop: 10px;
historyToDownBadgeFont: semiboldFont;
historyToDownBadgeSize: 22px;
membersInnerScroll: flatScroll(solidScroll) {
deltat: 3px;
@ -42,5 +44,3 @@ membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
scrollMargin: margins(0px, 5px, 0px, 5px);
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->title = title;
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;
if (it->count != set.vcount.v || it->hash != set.vhash.v || it->emoji.isEmpty()) {
it->count = set.vcount.v;
@ -3739,6 +3739,11 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
if (stickers.type() != mtpc_messages_featuredStickers) return;
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 &setsOrder = Global::RefFeaturedStickerSetsOrder();
@ -3755,13 +3760,23 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
auto it = sets.find(set.vid.v);
QString title = stickerSetTitle(set);
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 {
it->access = set.vaccess_hash.v;
it->title = title;
it->shortName = qs(set.vshort_name);
auto clientFlags = it->flags & (MTPDstickerSet_ClientFlag::f_featured | MTPDstickerSet_ClientFlag::f_not_loaded);
it->flags = set.vflags.v | clientFlags | MTPDstickerSet_ClientFlag::f_featured;
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 |= 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()) {
it->count = set.vcount.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 featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
if (installed || featured) {
if (featured && (it->flags & MTPDstickerSet_ClientFlag::f_unread)) {
++unreadCount;
}
++it;
} else {
it = sets.erase(it);
}
}
auto &unreadFeatured = Global::RefFeaturedUnreadSets();
unreadFeatured.clear();
for_const (auto &unreadSetId, d.vunread.c_vector().v) {
unreadFeatured.insert(unreadSetId.v);
}
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
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()));

View file

@ -3079,7 +3079,6 @@ namespace Local {
}
size += sizeof(qint32) + (Global::StickerSetsOrder().size() * sizeof(quint64));
size += sizeof(qint32) + (Global::FeaturedStickerSetsOrder().size() * sizeof(quint64));
size += sizeof(qint32) + (Global::FeaturedUnreadSets().size() * sizeof(quint64));
if (!_stickersKey) {
_stickersKey = genKey();
@ -3094,11 +3093,6 @@ namespace Local {
data.stream << Global::StickerSetsOrder();
data.stream << Global::FeaturedStickerSetsOrder();
data.stream << qint32(Global::FeaturedUnreadSets().size());
for_const (auto setId, Global::FeaturedUnreadSets()) {
data.stream << quint64(setId);
}
FileWriteDescriptor file(_stickersKey);
file.writeEncrypted(data);
}
@ -3200,9 +3194,6 @@ namespace Local {
auto &featuredOrder = Global::RefFeaturedStickerSetsOrder();
featuredOrder.clear();
auto &unreadFeatured = Global::RefFeaturedUnreadSets();
unreadFeatured.clear();
quint32 cnt;
QByteArray hash;
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();
// 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
set.count = -scnt;
continue;
@ -3293,23 +3286,32 @@ namespace Local {
stickers.stream >> order;
stickers.stream >> featuredOrder;
qint32 unreadCount = 0;
stickers.stream >> unreadCount;
for (int i = 0; i < unreadCount; ++i) {
quint64 setId = 0;
stickers.stream >> setId;
if (setId) {
unreadFeatured.insert(setId);
// Set flags and count unread featured sets.
for_const (auto setId, order) {
auto it = sets.find(setId);
if (it != sets.cend()) {
it->flags |= MTPDstickerSet::Flag::f_installed;
}
}
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) {
uint32 acc = 0;
bool foundOfficial = false, foundBad = false;;
const Stickers::Sets &sets(Global::StickerSets());
const Stickers::Order &order(Global::StickerSetsOrder());
auto &sets = Global::StickerSets();
auto &order = Global::StickerSetsOrder();
for (auto i = order.cbegin(), e = order.cend(); i != e; ++i) {
auto j = sets.constFind(*i);
if (j != sets.cend()) {
@ -3328,11 +3330,14 @@ namespace Local {
int32 countFeaturedStickersHash() {
uint32 acc = 0;
auto &featured(Global::FeaturedStickerSetsOrder());
auto &sets = Global::StickerSets();
auto &featured = Global::FeaturedStickerSetsOrder();
for_const (auto setId, featured) {
acc = (acc * 20261) + uint32(setId >> 32);
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;
}
}

View file

@ -3378,7 +3378,6 @@ void MainWidget::stickersBox(const MTPInputStickerSet &set) {
}
void MainWidget::onStickersInstalled(uint64 setId) {
emit stickersUpdated();
_history->stickersInstalled(setId);
}
@ -4731,9 +4730,16 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break;
case mtpc_updateReadFeaturedStickers: {
Global::RefFeaturedUnreadSets().clear();
Local::writeStickers();
emit stickersUpdated();
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::writeStickers();
emit stickersUpdated();
}
} break;
////// Cloud saved GIFs

View file

@ -1291,7 +1291,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
if (_saveMsgOpacity.current() > 0) {
p.setOpacity(_saveMsgOpacity.current());
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);
textstyleSet(&st::medviewSaveAsTextStyle);

View file

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