Make nice emoji status selector in profile.

This commit is contained in:
John Preston 2022-08-11 13:10:40 +03:00
parent 165d3143de
commit 64bd4f0926
10 changed files with 327 additions and 229 deletions

View file

@ -364,8 +364,14 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) {
EmojiListWidget::EmojiListWidget( EmojiListWidget::EmojiListWidget(
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
Window::GifPauseReason level) Window::GifPauseReason level,
Mode mode)
: Inner(parent, controller, level) : Inner(parent, controller, level)
, _mode(mode)
, _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1)
, _premiumIcon(_mode == Mode::EmojiStatus
? std::make_unique<GradientPremiumStar>()
: nullptr)
, _localSetsManager( , _localSetsManager(
std::make_unique<LocalStickersManager>(&controller->session())) std::make_unique<LocalStickersManager>(&controller->session()))
, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg) , _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg)
@ -376,7 +382,7 @@ EmojiListWidget::EmojiListWidget(
_picker->hide(); _picker->hide();
for (auto i = 1; i != kEmojiSectionCount; ++i) { for (auto i = 1; i != _staticCount; ++i) {
const auto section = static_cast<Section>(i); const auto section = static_cast<Section>(i);
_counts[i] = Ui::Emoji::GetSectionCount(section); _counts[i] = Ui::Emoji::GetSectionCount(section);
} }
@ -430,8 +436,8 @@ void EmojiListWidget::repaintCustom(uint64 setId) {
const auto repaint1 = repaintRecent const auto repaint1 = repaintRecent
&& (info.section == int(Section::Recent)); && (info.section == int(Section::Recent));
const auto repaint2 = !repaint1 const auto repaint2 = !repaint1
&& (info.section >= kEmojiSectionCount) && (info.section >= _staticCount)
&& (setId == _custom[info.section - kEmojiSectionCount].id); && (setId == _custom[info.section - _staticCount].id);
if (repaint1 || repaint2) { if (repaint1 || repaint2) {
update( update(
0, 0,
@ -496,10 +502,10 @@ void EmojiListWidget::unloadCustomIn(const SectionInfo &info) {
} }
} }
return; return;
} else if (info.section < kEmojiSectionCount) { } else if (info.section < _staticCount) {
return; return;
} }
auto &custom = _custom[info.section - kEmojiSectionCount]; auto &custom = _custom[info.section - _staticCount];
if (!custom.painted) { if (!custom.painted) {
return; return;
} }
@ -549,7 +555,7 @@ bool EmojiListWidget::enumerateSections(Callback callback) const {
info.top = info.rowsBottom; info.top = info.rowsBottom;
return true; return true;
}; };
for (; i != kEmojiSectionCount; ++i) { for (; i != _staticCount; ++i) {
info.section = i; info.section = i;
info.count = i ? _counts[i] : _recent.size(); info.count = i ? _counts[i] : _recent.size();
if (!next()) { if (!next()) {
@ -599,7 +605,7 @@ EmojiListWidget::SectionInfo EmojiListWidget::sectionInfoByOffset(
} }
int EmojiListWidget::sectionsCount() const { int EmojiListWidget::sectionsCount() const {
return kEmojiSectionCount + int(_custom.size()); return _staticCount + int(_custom.size());
} }
void EmojiListWidget::setSingleSize(QSize size) { void EmojiListWidget::setSingleSize(QSize size) {
@ -612,6 +618,9 @@ void EmojiListWidget::setSingleSize(QSize size) {
_innerPosition = QPoint( _innerPosition = QPoint(
(area.width() - esize) / 2, (area.width() - esize) / 2,
(area.height() - esize) / 2); (area.height() - esize) / 2);
const auto customSize = Ui::Text::AdjustCustomEmojiSize(esize);
const auto customSkip = (esize - customSize) / 2;
_customPosition = QPoint(customSkip, customSkip);
_picker->setSingleSize(_singleSize); _picker->setSingleSize(_singleSize);
} }
@ -649,7 +658,7 @@ void EmojiListWidget::ensureLoaded(int section) {
fillRecent(); fillRecent();
} }
return; return;
} else if (section >= kEmojiSectionCount || !_emoji[section].empty()) { } else if (section >= _staticCount || !_emoji[section].empty()) {
return; return;
} }
_emoji[section] = Ui::Emoji::GetSection(static_cast<Section>(section)); _emoji[section] = Ui::Emoji::GetSection(static_cast<Section>(section));
@ -671,11 +680,17 @@ void EmojiListWidget::fillRecent() {
_recentCustomIds.clear(); _recentCustomIds.clear();
const auto &list = Core::App().settings().recentEmoji(); const auto &list = Core::App().settings().recentEmoji();
_recent.reserve(std::min(int(list.size()), Core::kRecentEmojiLimit)); _recent.reserve(std::min(int(list.size()), Core::kRecentEmojiLimit) + 1);
if (_mode == Mode::EmojiStatus) {
const auto star = QString::fromUtf8("\xe2\xad\x90\xef\xb8\x8f");
_recent.push_back({ .id = { Ui::Emoji::Find(star) } });
}
const auto test = controller()->session().isTestMode(); const auto test = controller()->session().isTestMode();
for (const auto &one : list) { for (const auto &one : list) {
const auto document = std::get_if<RecentEmojiDocument>(&one.id.data); const auto document = std::get_if<RecentEmojiDocument>(&one.id.data);
if (document && document->test != test) { if (_mode == Mode::EmojiStatus && !document) {
continue;
} else if (document && document->test != test) {
continue; continue;
} }
_recent.push_back({ _recent.push_back({
@ -730,9 +745,9 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
if (info.section > 0 && r.top() < info.rowsTop) { if (info.section > 0 && r.top() < info.rowsTop) {
p.setFont(st::emojiPanHeaderFont); p.setFont(st::emojiPanHeaderFont);
p.setPen(st::emojiPanHeaderFg); p.setPen(st::emojiPanHeaderFg);
auto titleText = (info.section < kEmojiSectionCount) auto titleText = (info.section < _staticCount)
? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now) ? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now)
: _custom[info.section - kEmojiSectionCount].title; : _custom[info.section - _staticCount].title;
auto titleWidth = st::emojiPanHeaderFont->width(titleText); auto titleWidth = st::emojiPanHeaderFont->width(titleText);
if (titleWidth > widthForTitle) { if (titleWidth > widthForTitle) {
titleText = st::emojiPanHeaderFont->elided(titleText, widthForTitle); titleText = st::emojiPanHeaderFont->elided(titleText, widthForTitle);
@ -793,10 +808,10 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
} }
if (info.section == int(Section::Recent)) { if (info.section == int(Section::Recent)) {
drawRecent(p, w, now, paused, index); drawRecent(p, w, now, paused, index);
} else if (info.section < kEmojiSectionCount) { } else if (info.section < _staticCount) {
drawEmoji(p, w, _emoji[info.section][index]); drawEmoji(p, w, _emoji[info.section][index]);
} else { } else {
const auto set = info.section - kEmojiSectionCount; const auto set = info.section - _staticCount;
drawCustom(p, w, now, paused, set, index); drawCustom(p, w, now, paused, set, index);
} }
} }
@ -834,10 +849,18 @@ void EmojiListWidget::drawRecent(
int index) { int index) {
_recentPainted = true; _recentPainted = true;
if (const auto emoji = std::get_if<EmojiPtr>(&_recent[index].id.data)) { if (const auto emoji = std::get_if<EmojiPtr>(&_recent[index].id.data)) {
drawEmoji(p, position, *emoji); if (_mode == Mode::EmojiStatus) {
position += QPoint(
(_singleSize.width() - st::stickersPremium.width()) / 2,
(_singleSize.height() - st::stickersPremium.height()) / 2
) - _areaPosition;
p.drawImage(position, _premiumIcon->image());
} else {
drawEmoji(p, position, *emoji);
}
} else { } else {
Assert(_recent[index].custom != nullptr); Assert(_recent[index].custom != nullptr);
position += _innerPosition; position += _innerPosition + _customPosition;
_recent[index].custom->paint( _recent[index].custom->paint(
p, p,
position.x(), position.x(),
@ -868,7 +891,7 @@ void EmojiListWidget::drawCustom(
bool paused, bool paused,
int set, int set,
int index) { int index) {
position += _innerPosition; position += _innerPosition + _customPosition;
_custom[set].painted = true; _custom[set].painted = true;
_custom[set].list[index].custom->paint( _custom[set].list[index].custom->paint(
p, p,
@ -897,7 +920,7 @@ EmojiPtr EmojiListWidget::lookupOverEmoji(const OverEmoji *over) const {
&& v::is<EmojiPtr>(_recent[index].id.data)) && v::is<EmojiPtr>(_recent[index].id.data))
? v::get<EmojiPtr>(_recent[index].id.data) ? v::get<EmojiPtr>(_recent[index].id.data)
: (section > int(Section::Recent) : (section > int(Section::Recent)
&& section < kEmojiSectionCount && section < _staticCount
&& index < _emoji[section].size()) && index < _emoji[section].size())
? _emoji[section][index] ? _emoji[section][index]
: nullptr; : nullptr;
@ -958,10 +981,10 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
if (const auto over = std::get_if<OverEmoji>(&_selected)) { if (const auto over = std::get_if<OverEmoji>(&_selected)) {
const auto section = over->section; const auto section = over->section;
const auto index = over->index; const auto index = over->index;
if (section >= kEmojiSectionCount if (section >= _staticCount
&& sectionInfo(section).collapsed && sectionInfo(section).collapsed
&& index + 1 == _columnCount * kCollapsedRows) { && index + 1 == _columnCount * kCollapsedRows) {
_custom[section - kEmojiSectionCount].expanded = true; _custom[section - _staticCount].expanded = true;
resizeToWidth(width()); resizeToWidth(width());
update(); update();
return; return;
@ -980,19 +1003,19 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
if (custom && custom->sticker()) { if (custom && custom->sticker()) {
selectCustom(custom); selectCustom(custom);
} }
} else if (section >= kEmojiSectionCount } else if (section >= _staticCount
&& index < _custom[section - kEmojiSectionCount].list.size()) { && index < _custom[section - _staticCount].list.size()) {
auto &set = _custom[section - kEmojiSectionCount]; auto &set = _custom[section - _staticCount];
selectCustom(set.list[index].document); selectCustom(set.list[index].document);
} }
} else if (const auto set = std::get_if<OverSet>(&pressed)) { } else if (const auto set = std::get_if<OverSet>(&pressed)) {
Assert(set->section >= kEmojiSectionCount Assert(set->section >= _staticCount
&& set->section < kEmojiSectionCount + _custom.size()); && set->section < _staticCount + _custom.size());
displaySet(_custom[set->section - kEmojiSectionCount].id); displaySet(_custom[set->section - _staticCount].id);
} else if (auto button = std::get_if<OverButton>(&pressed)) { } else if (auto button = std::get_if<OverButton>(&pressed)) {
Assert(button->section >= kEmojiSectionCount Assert(button->section >= _staticCount
&& button->section < kEmojiSectionCount + _custom.size()); && button->section < _staticCount + _custom.size());
const auto id = _custom[button->section - kEmojiSectionCount].id; const auto id = _custom[button->section - _staticCount].id;
if (hasRemoveButton(button->section)) { if (hasRemoveButton(button->section)) {
removeSet(id); removeSet(id);
} else if (hasAddButton(button->section)) { } else if (hasAddButton(button->section)) {
@ -1074,11 +1097,11 @@ void EmojiListWidget::pickerHidden() {
} }
bool EmojiListWidget::hasRemoveButton(int index) const { bool EmojiListWidget::hasRemoveButton(int index) const {
if (index < kEmojiSectionCount if (index < _staticCount
|| index >= kEmojiSectionCount + _custom.size()) { || index >= _staticCount + _custom.size()) {
return false; return false;
} }
const auto &set = _custom[index - kEmojiSectionCount]; const auto &set = _custom[index - _staticCount];
return set.canRemove && !set.premiumRequired; return set.canRemove && !set.premiumRequired;
} }
@ -1096,11 +1119,11 @@ QRect EmojiListWidget::removeButtonRect(const SectionInfo &info) const {
} }
bool EmojiListWidget::hasAddButton(int index) const { bool EmojiListWidget::hasAddButton(int index) const {
if (index < kEmojiSectionCount if (index < _staticCount
|| index >= kEmojiSectionCount + _custom.size()) { || index >= _staticCount + _custom.size()) {
return false; return false;
} }
const auto &set = _custom[index - kEmojiSectionCount]; const auto &set = _custom[index - _staticCount];
return !set.canRemove && !set.premiumRequired; return !set.canRemove && !set.premiumRequired;
} }
@ -1109,24 +1132,24 @@ QRect EmojiListWidget::addButtonRect(int index) const {
} }
bool EmojiListWidget::hasUnlockButton(int index) const { bool EmojiListWidget::hasUnlockButton(int index) const {
if (index < kEmojiSectionCount if (index < _staticCount
|| index >= kEmojiSectionCount + _custom.size()) { || index >= _staticCount + _custom.size()) {
return false; return false;
} }
const auto &set = _custom[index - kEmojiSectionCount]; const auto &set = _custom[index - _staticCount];
return set.premiumRequired; return set.premiumRequired;
} }
QRect EmojiListWidget::unlockButtonRect(int index) const { QRect EmojiListWidget::unlockButtonRect(int index) const {
Expects(index >= kEmojiSectionCount Expects(index >= _staticCount
&& index < kEmojiSectionCount + _custom.size()); && index < _staticCount + _custom.size());
return buttonRect(sectionInfo(index), rightButton(index)); return buttonRect(sectionInfo(index), rightButton(index));
} }
bool EmojiListWidget::hasButton(int index) const { bool EmojiListWidget::hasButton(int index) const {
if (index < kEmojiSectionCount if (index < _staticCount
|| index >= kEmojiSectionCount + _custom.size()) { || index >= _staticCount + _custom.size()) {
return false; return false;
} }
return true; return true;
@ -1151,11 +1174,11 @@ QRect EmojiListWidget::buttonRect(
} }
auto EmojiListWidget::rightButton(int index) const -> const RightButton & { auto EmojiListWidget::rightButton(int index) const -> const RightButton & {
Expects(index >= kEmojiSectionCount Expects(index >= _staticCount
&& index < kEmojiSectionCount + _custom.size()); && index < _staticCount + _custom.size());
return hasAddButton(index) return hasAddButton(index)
? _add ? _add
: _custom[index - kEmojiSectionCount].canRemove : _custom[index - _staticCount].canRemove
? _restore ? _restore
: _unlock; : _unlock;
} }
@ -1187,7 +1210,7 @@ void EmojiListWidget::colorChosen(EmojiPtr emoji) {
const auto over = std::get_if<OverEmoji>(&_pickerSelected); const auto over = std::get_if<OverEmoji>(&_pickerSelected);
if (over if (over
&& over->section > int(Section::Recent) && over->section > int(Section::Recent)
&& over->section < kEmojiSectionCount && over->section < _staticCount
&& over->index < _emoji[over->section].size()) { && over->index < _emoji[over->section].size()) {
_emoji[over->section][over->index] = emoji; _emoji[over->section][over->index] = emoji;
rtlupdate(emojiRect(over->section, over->index)); rtlupdate(emojiRect(over->section, over->index));
@ -1466,7 +1489,8 @@ std::vector<StickerIcon> EmojiListWidget::fillIcons() {
result.reserve(2 + _custom.size()); result.reserve(2 + _custom.size());
result.emplace_back(RecentEmojiSectionSetId()); result.emplace_back(RecentEmojiSectionSetId());
if (_custom.empty()) { if (_mode == Mode::EmojiStatus) {
} else if (_custom.empty()) {
using Section = Ui::Emoji::Section; using Section = Ui::Emoji::Section;
for (auto i = int(Section::People); i <= int(Section::Symbols); ++i) { for (auto i = int(Section::People); i <= int(Section::Symbols); ++i) {
result.emplace_back(EmojiSectionSetId(Section(i))); result.emplace_back(EmojiSectionSetId(Section(i)));
@ -1489,11 +1513,11 @@ int EmojiListWidget::paintButtonGetWidth(
const SectionInfo &info, const SectionInfo &info,
bool selected, bool selected,
QRect clip) const { QRect clip) const {
if (info.section < kEmojiSectionCount if (info.section < _staticCount
|| info.section >= kEmojiSectionCount + _custom.size()) { || info.section >= _staticCount + _custom.size()) {
return 0; return 0;
} }
auto &custom = _custom[info.section - kEmojiSectionCount]; auto &custom = _custom[info.section - _staticCount];
if (hasRemoveButton(info.section)) { if (hasRemoveButton(info.section)) {
const auto remove = removeButtonRect(info); const auto remove = removeButtonRect(info);
if (remove.intersects(clip)) { if (remove.intersects(clip)) {
@ -1565,7 +1589,7 @@ void EmojiListWidget::updateSelected() {
if (hasButton(section) if (hasButton(section)
&& myrtlrect(buttonRect(section)).contains(p.x(), p.y())) { && myrtlrect(buttonRect(section)).contains(p.x(), p.y())) {
newSelected = OverButton{ section }; newSelected = OverButton{ section };
} else if (section >= kEmojiSectionCount) { } else if (section >= _staticCount) {
newSelected = OverSet{ section }; newSelected = OverSet{ section };
} }
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) { } else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
@ -1616,18 +1640,18 @@ void EmojiListWidget::setSelected(OverState newSelected) {
void EmojiListWidget::setPressed(OverState newPressed) { void EmojiListWidget::setPressed(OverState newPressed) {
if (auto button = std::get_if<OverButton>(&_pressed)) { if (auto button = std::get_if<OverButton>(&_pressed)) {
Assert(button->section >= kEmojiSectionCount Assert(button->section >= _staticCount
&& button->section < kEmojiSectionCount + _custom.size()); && button->section < _staticCount + _custom.size());
auto &set = _custom[button->section - kEmojiSectionCount]; auto &set = _custom[button->section - _staticCount];
if (set.ripple) { if (set.ripple) {
set.ripple->lastStop(); set.ripple->lastStop();
} }
} }
_pressed = newPressed; _pressed = newPressed;
if (auto button = std::get_if<OverButton>(&_pressed)) { if (auto button = std::get_if<OverButton>(&_pressed)) {
Assert(button->section >= kEmojiSectionCount Assert(button->section >= _staticCount
&& button->section < kEmojiSectionCount + _custom.size()); && button->section < _staticCount + _custom.size());
auto &set = _custom[button->section - kEmojiSectionCount]; auto &set = _custom[button->section - _staticCount];
if (!set.ripple) { if (!set.ripple) {
set.ripple = createButtonRipple(button->section); set.ripple = createButtonRipple(button->section);
} }
@ -1675,8 +1699,8 @@ void EmojiListWidget::initButton(
std::unique_ptr<Ui::RippleAnimation> EmojiListWidget::createButtonRipple( std::unique_ptr<Ui::RippleAnimation> EmojiListWidget::createButtonRipple(
int section) { int section) {
Expects(section >= kEmojiSectionCount Expects(section >= _staticCount
&& section < kEmojiSectionCount + _custom.size()); && section < _staticCount + _custom.size());
const auto remove = hasRemoveButton(section); const auto remove = hasRemoveButton(section);
const auto &st = remove const auto &st = remove
@ -1694,8 +1718,8 @@ std::unique_ptr<Ui::RippleAnimation> EmojiListWidget::createButtonRipple(
} }
QPoint EmojiListWidget::buttonRippleTopLeft(int section) const { QPoint EmojiListWidget::buttonRippleTopLeft(int section) const {
Expects(section >= kEmojiSectionCount Expects(section >= _staticCount
&& section < kEmojiSectionCount + _custom.size()); && section < _staticCount + _custom.size());
return myrtlrect(buttonRect(section)).topLeft() return myrtlrect(buttonRect(section)).topLeft()
+ (hasRemoveButton(section) + (hasRemoveButton(section)
@ -1727,12 +1751,12 @@ void EmojiListWidget::showSet(uint64 setId) {
} }
uint64 EmojiListWidget::sectionSetId(int section) const { uint64 EmojiListWidget::sectionSetId(int section) const {
Expects(section < kEmojiSectionCount Expects(section < _staticCount
|| (section - kEmojiSectionCount) < _custom.size()); || (section - _staticCount) < _custom.size());
return (section < kEmojiSectionCount) return (section < _staticCount)
? EmojiSectionSetId(static_cast<Section>(section)) ? EmojiSectionSetId(static_cast<Section>(section))
: _custom[section - kEmojiSectionCount].id; : _custom[section - _staticCount].id;
} }
tr::phrase<> EmojiCategoryTitle(int index) { tr::phrase<> EmojiCategoryTitle(int index) {

View file

@ -50,16 +50,22 @@ inline constexpr auto kEmojiSectionCount = 8;
struct StickerIcon; struct StickerIcon;
class EmojiColorPicker; class EmojiColorPicker;
class StickersListFooter; class StickersListFooter;
class GradientPremiumStar;
class LocalStickersManager; class LocalStickersManager;
class EmojiListWidget class EmojiListWidget
: public TabbedSelector::Inner : public TabbedSelector::Inner
, public Ui::AbstractTooltipShower { , public Ui::AbstractTooltipShower {
public: public:
enum class Mode {
Full,
EmojiStatus,
};
EmojiListWidget( EmojiListWidget(
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
Window::GifPauseReason level); Window::GifPauseReason level,
Mode mode);
~EmojiListWidget(); ~EmojiListWidget();
using Section = Ui::Emoji::Section; using Section = Ui::Emoji::Section;
@ -266,7 +272,10 @@ private:
DocumentId documentId, DocumentId documentId,
uint64 setId); uint64 setId);
Mode _mode = Mode::Full;
const int _staticCount = 0;
StickersListFooter *_footer = nullptr; StickersListFooter *_footer = nullptr;
std::unique_ptr<GradientPremiumStar> _premiumIcon;
std::unique_ptr<LocalStickersManager> _localSetsManager; std::unique_ptr<LocalStickersManager> _localSetsManager;
int _counts[kEmojiSectionCount]; int _counts[kEmojiSectionCount];
@ -284,6 +293,7 @@ private:
QSize _singleSize; QSize _singleSize;
QPoint _areaPosition; QPoint _areaPosition;
QPoint _innerPosition; QPoint _innerPosition;
QPoint _customPosition;
RightButton _add; RightButton _add;
RightButton _unlock; RightButton _unlock;

View file

@ -145,6 +145,42 @@ bool StickersListFooter::ScrollState::animationCallback(crl::time now) {
return true; return true;
} }
GradientPremiumStar::GradientPremiumStar() {
style::PaletteChanged(
) | rpl::start_with_next([=] {
_image = QImage();
}, _lifetime);
}
QImage GradientPremiumStar::image() const {
if (_image.isNull()) {
renderOnDemand();
}
return _image;
}
void GradientPremiumStar::renderOnDemand() const {
const auto size = st::stickersPremium.size();
const auto mask = st::stickersPremium.instance(Qt::white);
const auto factor = style::DevicePixelRatio();
_image = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
_image.setDevicePixelRatio(factor);
QPainter p(&_image);
auto gradient = QLinearGradient(
QPoint(0, size.height()),
QPoint(size.width(), 0));
gradient.setStops({
{ 0., st::stickerPanPremium1->c },
{ 1., st::stickerPanPremium2->c },
});
p.fillRect(QRect(QPoint(), size), gradient);
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawImage(QRect(QPoint(), size), mask);
}
StickersListFooter::StickersListFooter(Descriptor &&descriptor) StickersListFooter::StickersListFooter(Descriptor &&descriptor)
: InnerFooter(descriptor.parent) : InnerFooter(descriptor.parent)
, _controller(descriptor.controller) , _controller(descriptor.controller)
@ -169,36 +205,6 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor)
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
update(); update();
}, lifetime()); }, lifetime());
style::PaletteChanged(
) | rpl::start_with_next([=] {
_premiumIcon = QImage();
}, lifetime());
}
void StickersListFooter::validatePremiumIcon() const {
if (!_premiumIcon.isNull()) {
return;
}
const auto size = st::stickersPremium.size();
const auto mask = st::stickersPremium.instance(Qt::white);
const auto factor = style::DevicePixelRatio();
_premiumIcon = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
_premiumIcon.setDevicePixelRatio(factor);
QPainter p(&_premiumIcon);
auto gradient = QLinearGradient(
QPoint(0, size.height()),
QPoint(size.width(), 0));
gradient.setStops({
{ 0., st::stickerPanPremium1->c },
{ 1., st::stickerPanPremium2->c },
});
p.fillRect(QRect(QPoint(), size), gradient);
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawImage(QRect(QPoint(), size), mask);
} }
void StickersListFooter::clearHeavyData() { void StickersListFooter::clearHeavyData() {
@ -1211,12 +1217,11 @@ void StickersListFooter::paintSetIcon(
width(), width(),
st::stickerGroupCategorySize); st::stickerGroupCategorySize);
} else if (icon.setId == Data::Stickers::PremiumSetId) { } else if (icon.setId == Data::Stickers::PremiumSetId) {
validatePremiumIcon();
const auto size = st::stickersPremium.size(); const auto size = st::stickersPremium.size();
p.drawImage( p.drawImage(
info.adjustedLeft + (_singleWidth - size.width()) / 2, info.adjustedLeft + (_singleWidth - size.width()) / 2,
_iconsTop + (st::emojiFooterHeight - size.height()) / 2, _iconsTop + (st::emojiFooterHeight - size.height()) / 2,
_premiumIcon); _premiumIcon.image());
} else { } else {
using Section = Ui::Emoji::Section; using Section = Ui::Emoji::Section;
const auto sectionIcon = [&](Section section, bool active) { const auto sectionIcon = [&](Section section, bool active) {

View file

@ -75,6 +75,20 @@ struct StickerIcon {
mutable rpl::lifetime lifetime; mutable rpl::lifetime lifetime;
}; };
class GradientPremiumStar {
public:
GradientPremiumStar();
[[nodiscard]] QImage image() const;
private:
void renderOnDemand() const;
mutable QImage _image;
rpl::lifetime _lifetime;
};
class StickersListFooter final : public TabbedSelector::InnerFooter { class StickersListFooter final : public TabbedSelector::InnerFooter {
public: public:
struct Descriptor { struct Descriptor {
@ -203,7 +217,6 @@ private:
void paintSelectionBg(Painter &p) const; void paintSelectionBg(Painter &p) const;
void paintSelectionBar(Painter &p) const; void paintSelectionBar(Painter &p) const;
void paintLeftRightFading(Painter &p) const; void paintLeftRightFading(Painter &p) const;
void validatePremiumIcon() const;
void updateEmojiSectionWidth(); void updateEmojiSectionWidth();
void updateEmojiWidthCallback(); void updateEmojiWidthCallback();
@ -230,7 +243,7 @@ private:
OverState _pressed = SpecialOver::None; OverState _pressed = SpecialOver::None;
QPoint _iconsMousePos, _iconsMouseDown; QPoint _iconsMousePos, _iconsMouseDown;
mutable QImage _premiumIcon; GradientPremiumStar _premiumIcon;
int _iconsLeft = 0; int _iconsLeft = 0;
int _iconsRight = 0; int _iconsRight = 0;
int _iconsTop = 0; int _iconsTop = 0;

View file

@ -132,7 +132,19 @@ void TabbedPanel::moveBottomRight(int bottom, int right) {
_right = right; _right = right;
// If the panel is already shown, update the position. // If the panel is already shown, update the position.
if (!isHidden() && isNew) { if (!isHidden() && isNew) {
moveByBottom(); moveHorizontally();
} else {
updateContentHeight();
}
}
void TabbedPanel::moveTopRight(int top, int right) {
const auto isNew = (_top != top || _right != right);
_top = top;
_right = right;
// If the panel is already shown, update the position.
if (!isHidden() && isNew) {
moveHorizontally();
} else { } else {
updateContentHeight(); updateContentHeight();
} }
@ -148,16 +160,26 @@ void TabbedPanel::setDesiredHeightValues(
updateContentHeight(); updateContentHeight();
} }
void TabbedPanel::setDropDown(bool dropDown) {
selector()->setDropDown(dropDown);
_dropDown = dropDown;
}
void TabbedPanel::updateContentHeight() { void TabbedPanel::updateContentHeight() {
auto addedHeight = innerPadding().top() + innerPadding().bottom(); auto addedHeight = innerPadding().top() + innerPadding().bottom();
auto marginsHeight = _selector->marginTop() + _selector->marginBottom(); auto marginsHeight = _selector->marginTop() + _selector->marginBottom();
auto availableHeight = _bottom - marginsHeight; auto availableHeight = _dropDown
auto wantedContentHeight = qRound(_heightRatio * availableHeight) - addedHeight; ? (parentWidget()->height() - _top - marginsHeight)
: (_bottom - marginsHeight);
auto wantedContentHeight = qRound(_heightRatio * availableHeight)
- addedHeight;
auto contentHeight = marginsHeight + std::clamp( auto contentHeight = marginsHeight + std::clamp(
wantedContentHeight, wantedContentHeight,
_minContentHeight, _minContentHeight,
_maxContentHeight); _maxContentHeight);
auto resultTop = _bottom - addedHeight - contentHeight; auto resultTop = _dropDown
? _top
: (_bottom - addedHeight - contentHeight);
if (contentHeight == _contentHeight) { if (contentHeight == _contentHeight) {
move(x(), resultTop); move(x(), resultTop);
return; return;
@ -204,7 +226,7 @@ void TabbedPanel::paintEvent(QPaintEvent *e) {
} }
} }
void TabbedPanel::moveByBottom() { void TabbedPanel::moveHorizontally() {
const auto right = std::max(parentWidget()->width() - _right, 0); const auto right = std::max(parentWidget()->width() - _right, 0);
moveToRight(right, y()); moveToRight(right, y());
updateContentHeight(); updateContentHeight();
@ -318,7 +340,7 @@ void TabbedPanel::startShowAnimation() {
if (!_a_show.animating()) { if (!_a_show.animating()) {
auto image = grabForAnimation(); auto image = grabForAnimation();
_showAnimation = std::make_unique<Ui::PanelAnimation>(st::emojiPanAnimation, Ui::PanelAnimation::Origin::BottomRight); _showAnimation = std::make_unique<Ui::PanelAnimation>(st::emojiPanAnimation, _dropDown ? Ui::PanelAnimation::Origin::TopRight : Ui::PanelAnimation::Origin::BottomRight);
auto inner = rect().marginsRemoved(st::emojiPanMargins); auto inner = rect().marginsRemoved(st::emojiPanMargins);
_showAnimation->setFinalImage(std::move(image), QRect(inner.topLeft() * cIntRetinaFactor(), inner.size() * cIntRetinaFactor())); _showAnimation->setFinalImage(std::move(image), QRect(inner.topLeft() * cIntRetinaFactor(), inner.size() * cIntRetinaFactor()));
_showAnimation->setCornerMasks(Images::CornersMask(ImageRoundRadius::Small)); _showAnimation->setCornerMasks(Images::CornersMask(ImageRoundRadius::Small));
@ -402,7 +424,7 @@ void TabbedPanel::showStarted() {
} }
if (isHidden()) { if (isHidden()) {
_selector->showStarted(); _selector->showStarted();
moveByBottom(); moveHorizontally();
raise(); raise();
show(); show();
startShowAnimation(); startShowAnimation();
@ -424,7 +446,7 @@ bool TabbedPanel::eventFilter(QObject *obj, QEvent *e) {
void TabbedPanel::showFromSelector() { void TabbedPanel::showFromSelector() {
if (isHidden()) { if (isHidden()) {
moveByBottom(); moveHorizontally();
startShowAnimation(); startShowAnimation();
show(); show();
} }

View file

@ -41,10 +41,12 @@ public:
[[nodiscard]] not_null<TabbedSelector*> selector() const; [[nodiscard]] not_null<TabbedSelector*> selector() const;
void moveBottomRight(int bottom, int right); void moveBottomRight(int bottom, int right);
void moveTopRight(int top, int right);
void setDesiredHeightValues( void setDesiredHeightValues(
float64 ratio, float64 ratio,
int minHeight, int minHeight,
int maxHeight); int maxHeight);
void setDropDown(bool dropDown);
void hideFast(); void hideFast();
bool hiding() const { bool hiding() const {
@ -76,7 +78,7 @@ private:
TabbedSelector *nonOwnedSelector); TabbedSelector *nonOwnedSelector);
void hideByTimerOrLeave(); void hideByTimerOrLeave();
void moveByBottom(); void moveHorizontally();
void showFromSelector(); void showFromSelector();
style::margins innerPadding() const; style::margins innerPadding() const;
@ -103,6 +105,7 @@ private:
int _contentMaxHeight = 0; int _contentMaxHeight = 0;
int _contentHeight = 0; int _contentHeight = 0;
int _top = 0;
int _bottom = 0; int _bottom = 0;
int _right = 0; int _right = 0;
float64 _heightRatio = 1.; float64 _heightRatio = 1.;
@ -113,6 +116,7 @@ private:
Ui::Animations::Simple _a_show; Ui::Animations::Simple _a_show;
bool _shouldFinishHide = false; bool _shouldFinishHide = false;
bool _dropDown = false;
bool _hiding = false; bool _hiding = false;
bool _hideAfterSlide = false; bool _hideAfterSlide = false;

View file

@ -439,7 +439,14 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) {
auto createWidget = [&]() -> object_ptr<Inner> { auto createWidget = [&]() -> object_ptr<Inner> {
switch (type) { switch (type) {
case SelectorTab::Emoji: case SelectorTab::Emoji:
return object_ptr<EmojiListWidget>(this, _controller, _level); using EmojiMode = EmojiListWidget::Mode;
return object_ptr<EmojiListWidget>(
this,
_controller,
_level,
(_mode == Mode::EmojiStatus
? EmojiMode::EmojiStatus
: EmojiMode::Full));
case SelectorTab::Stickers: case SelectorTab::Stickers:
return object_ptr<StickersListWidget>(this, _controller, _level); return object_ptr<StickersListWidget>(this, _controller, _level);
case SelectorTab::Gifs: case SelectorTab::Gifs:
@ -561,7 +568,7 @@ void TabbedSelector::resizeEvent(QResizeEvent *e) {
} }
auto scrollWidth = width() - st::roundRadiusSmall; auto scrollWidth = width() - st::roundRadiusSmall;
auto scrollHeight = height() - scrollTop() - marginBottom(); auto scrollHeight = height() - scrollTop() - scrollBottom();
auto inner = currentTab()->widget(); auto inner = currentTab()->widget();
auto innerWidth = scrollWidth - st::emojiScroll.width; auto innerWidth = scrollWidth - st::emojiScroll.width;
auto updateScrollGeometry = [&] { auto updateScrollGeometry = [&] {
@ -591,7 +598,7 @@ void TabbedSelector::resizeEvent(QResizeEvent *e) {
st::lineWidth); st::lineWidth);
updateRestrictedLabelGeometry(); updateRestrictedLabelGeometry();
_footerTop = height() - st::emojiFooterHeight; _footerTop = _dropDown ? 0 : (height() - st::emojiFooterHeight);
for (auto &tab : _tabs) { for (auto &tab : _tabs) {
tab.footer()->resizeToWidth(width()); tab.footer()->resizeToWidth(width());
tab.footer()->moveToLeft(0, _footerTop); tab.footer()->moveToLeft(0, _footerTop);
@ -630,21 +637,7 @@ void TabbedSelector::paintEvent(QPaintEvent *e) {
void TabbedSelector::paintSlideFrame(Painter &p) { void TabbedSelector::paintSlideFrame(Painter &p) {
if (_roundRadius > 0) { if (_roundRadius > 0) {
const auto topPart = QRect( paintBgRoundedPart(p);
0,
0,
width(),
_tabsSlider
? _tabsSlider->height() + _roundRadius
: 3 * _roundRadius);
Ui::FillRoundRect(
p,
topPart,
st::emojiPanBg,
ImageRoundRadius::Small,
tabbed()
? RectPart::FullTop | RectPart::NoTopBottom
: RectPart::FullTop);
} else if (_tabsSlider) { } else if (_tabsSlider) {
p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg); p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg);
} }
@ -652,43 +645,53 @@ void TabbedSelector::paintSlideFrame(Painter &p) {
_slideAnimation->paintFrame(p, slideDt, 1.); _slideAnimation->paintFrame(p, slideDt, 1.);
} }
void TabbedSelector::paintContent(Painter &p) { void TabbedSelector::paintBgRoundedPart(Painter &p) {
auto &bottomBg = hasSectionIcons() const auto threeRadius = 3 * _roundRadius;
? st::emojiPanCategories const auto topOrBottomPart = _dropDown
: st::emojiPanBg; ? QRect(0, height() - threeRadius, width(), threeRadius)
if (_roundRadius > 0) { : QRect(
const auto topPart = QRect(
0, 0,
0, 0,
width(), width(),
_tabsSlider (_tabsSlider
? _tabsSlider->height() + _roundRadius ? _tabsSlider->height() + _roundRadius
: 3 * _roundRadius); : threeRadius));
Ui::FillRoundRect( Ui::FillRoundRect(
p, p,
topPart, topOrBottomPart,
st::emojiPanBg, st::emojiPanBg,
ImageRoundRadius::Small, ImageRoundRadius::Small,
tabbed() (_dropDown
? RectPart::FullTop | RectPart::NoTopBottom ? RectPart::FullBottom
: RectPart::FullTop); : tabbed()
? (RectPart::FullTop | RectPart::NoTopBottom)
: RectPart::FullTop));
}
const auto bottomPart = QRect( void TabbedSelector::paintContent(Painter &p) {
auto &footerBg = hasSectionIcons()
? st::emojiPanCategories
: st::emojiPanBg;
if (_roundRadius > 0) {
paintBgRoundedPart(p);
const auto footerPart = QRect(
0, 0,
_footerTop - _roundRadius, _footerTop - (_dropDown ? 0 : _roundRadius),
width(), width(),
st::emojiFooterHeight + _roundRadius); st::emojiFooterHeight + _roundRadius);
Ui::FillRoundRect( Ui::FillRoundRect(
p, p,
bottomPart, footerPart,
bottomBg, footerBg,
ImageRoundRadius::Small, ImageRoundRadius::Small,
RectPart::NoTopBottom | RectPart::FullBottom); (RectPart::NoTopBottom
| (_dropDown ? RectPart::FullTop : RectPart::FullBottom)));
} else { } else {
if (_tabsSlider) { if (_tabsSlider) {
p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg); p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg);
} }
p.fillRect(0, _footerTop, width(), st::emojiFooterHeight, bottomBg); p.fillRect(0, _footerTop, width(), st::emojiFooterHeight, footerBg);
} }
auto sidesTop = marginTop(); auto sidesTop = marginTop();
@ -710,17 +713,23 @@ void TabbedSelector::paintContent(Painter &p) {
} }
int TabbedSelector::marginTop() const { int TabbedSelector::marginTop() const {
return _tabsSlider return _dropDown
? st::emojiFooterHeight
: _tabsSlider
? (_tabsSlider->height() - st::lineWidth) ? (_tabsSlider->height() - st::lineWidth)
: _roundRadius; : _roundRadius;
} }
int TabbedSelector::scrollTop() const { int TabbedSelector::scrollTop() const {
return tabbed() ? marginTop() : 0; return tabbed() ? marginTop() : _dropDown ? st::emojiFooterHeight : 0;
} }
int TabbedSelector::marginBottom() const { int TabbedSelector::marginBottom() const {
return st::emojiFooterHeight; return _dropDown ? _roundRadius : st::emojiFooterHeight;
}
int TabbedSelector::scrollBottom() const {
return _dropDown ? 0 : marginBottom();
} }
void TabbedSelector::refreshStickers() { void TabbedSelector::refreshStickers() {

View file

@ -70,6 +70,7 @@ public:
Full, Full,
EmojiOnly, EmojiOnly,
MediaEditor, MediaEditor,
EmojiStatus,
}; };
enum class Action { enum class Action {
Update, Update,
@ -110,9 +111,10 @@ public:
void beforeHiding(); void beforeHiding();
void afterShown(); void afterShown();
int marginTop() const; [[nodiscard]] int marginTop() const;
int marginBottom() const; [[nodiscard]] int marginBottom() const;
int scrollTop() const; [[nodiscard]] int scrollTop() const;
[[nodiscard]] int scrollBottom() const;
bool preventAutoHide() const; bool preventAutoHide() const;
bool isSliding() const { bool isSliding() const {
@ -128,6 +130,9 @@ public:
} }
void showMenuWithType(SendMenu::Type type); void showMenuWithType(SendMenu::Type type);
void setDropDown(bool dropDown) {
_dropDown = dropDown;
}
// Float player interface. // Float player interface.
bool floatPlayerHandleWheelEvent(QEvent *e); bool floatPlayerHandleWheelEvent(QEvent *e);
@ -193,6 +198,7 @@ private:
Tab createTab(SelectorTab type, int index); Tab createTab(SelectorTab type, int index);
void paintSlideFrame(Painter &p); void paintSlideFrame(Painter &p);
void paintBgRoundedPart(Painter &p);
void paintContent(Painter &p); void paintContent(Painter &p);
void checkRestrictedPeer(); void checkRestrictedPeer();
@ -252,6 +258,7 @@ private:
const bool _hasGifsTab; const bool _hasGifsTab;
const bool _hasMasksTab; const bool _hasMasksTab;
const bool _tabbed; const bool _tabbed;
bool _dropDown = false;
base::unique_qptr<Ui::PopupMenu> _menu; base::unique_qptr<Ui::PopupMenu> _menu;

View file

@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/text/text_block.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/special_buttons.h" #include "ui/special_buttons.h"
#include "ui/unread_badge.h" #include "ui/unread_badge.h"
@ -215,29 +216,25 @@ void Cover::setBadge(Badge badge, DocumentId emojiStatusId) {
_badge = badge; _badge = badge;
_emojiStatusId = emojiStatusId; _emojiStatusId = emojiStatusId;
_emojiStatus = nullptr; _emojiStatus = nullptr;
_verifiedCheck.destroy(); _badgeView.destroy();
_scamFakeBadge.destroy();
switch (_badge) { switch (_badge) {
case Badge::Verified: case Badge::Verified:
case Badge::Premium: { case Badge::Premium: {
const auto icon = (_badge == Badge::Verified) _badgeView.create(this);
? &st::infoVerifiedCheck _badgeView->show();
: &st::infoPremiumStar;
_verifiedCheck.create(this);
_verifiedCheck->show();
_verifiedCheck->resize(icon->size());
if (_emojiStatusId) { if (_emojiStatusId) {
auto &owner = _controller->session().data(); auto &owner = _controller->session().data();
_emojiStatus = owner.customEmojiManager().create( _emojiStatus = owner.customEmojiManager().create(
_emojiStatusId, _emojiStatusId,
[raw = _verifiedCheck.data()]{ raw->update(); }, [raw = _badgeView.data()]{ raw->update(); },
Data::CustomEmojiManager::SizeTag::Normal); Data::CustomEmojiManager::SizeTag::Large);
} const auto size = Ui::Emoji::GetSizeLarge()
/ style::DevicePixelRatio();
_verifiedCheck->paintRequest( const auto emoji = Ui::Text::AdjustCustomEmojiSize(size);
) | rpl::start_with_next([=, check = _verifiedCheck.data()] { _badgeView->resize(emoji, emoji);
Painter p(check); _badgeView->paintRequest(
if (_emojiStatus) { ) | rpl::start_with_next([=, check = _badgeView.data()]{
Painter p(check);
_emojiStatus->paint( _emojiStatus->paint(
p, p,
0, 0,
@ -246,24 +243,17 @@ void Cover::setBadge(Badge badge, DocumentId emojiStatusId) {
st::windowBgOver->c, st::windowBgOver->c,
_controller->isGifPausedAtLeastFor( _controller->isGifPausedAtLeastFor(
Window::GifPauseReason::Layer)); Window::GifPauseReason::Layer));
} else { }, _badgeView->lifetime());
icon->paint(p, 0, 0, check->width());
}
}, _verifiedCheck->lifetime());
if (_badge == Badge::Premium) {
const auto userId = peerToUser(_peer->id).bare;
_verifiedCheck->setClickedCallback([=] {
if (_peer->isSelf()) {
showEmojiStatusSelector();
} else {
::Settings::ShowPremium(
_controller,
u"profile__%1"_q.arg(userId));
}
});
} else { } else {
_verifiedCheck->setAttribute(Qt::WA_TransparentForMouseEvents); const auto icon = (_badge == Badge::Verified)
? &st::infoVerifiedCheck
: &st::infoPremiumStar;
_badgeView->resize(icon->size());
_badgeView->paintRequest(
) | rpl::start_with_next([=, check = _badgeView.data()]{
Painter p(check);
icon->paint(p, 0, 0, check->width());
}, _badgeView->lifetime());
} }
} break; } break;
case Badge::Scam: case Badge::Scam:
@ -271,13 +261,13 @@ void Cover::setBadge(Badge badge, DocumentId emojiStatusId) {
const auto fake = (_badge == Badge::Fake); const auto fake = (_badge == Badge::Fake);
const auto size = Ui::ScamBadgeSize(fake); const auto size = Ui::ScamBadgeSize(fake);
const auto skip = st::infoVerifiedCheckPosition.x(); const auto skip = st::infoVerifiedCheckPosition.x();
_scamFakeBadge.create(this); _badgeView.create(this);
_scamFakeBadge->show(); _badgeView->show();
_scamFakeBadge->resize( _badgeView->resize(
size.width() + 2 * skip, size.width() + 2 * skip,
size.height() + 2 * skip); size.height() + 2 * skip);
_scamFakeBadge->paintRequest( _badgeView->paintRequest(
) | rpl::start_with_next([=, badge = _scamFakeBadge.data()]{ ) | rpl::start_with_next([=, badge = _badgeView.data()]{
Painter p(badge); Painter p(badge);
Ui::DrawScamBadge( Ui::DrawScamBadge(
fake, fake,
@ -285,28 +275,51 @@ void Cover::setBadge(Badge badge, DocumentId emojiStatusId) {
badge->rect().marginsRemoved({ skip, skip, skip, skip }), badge->rect().marginsRemoved({ skip, skip, skip, skip }),
badge->width(), badge->width(),
st::attentionButtonFg); st::attentionButtonFg);
}, _scamFakeBadge->lifetime()); }, _badgeView->lifetime());
} break; } break;
} }
if (_badge == Badge::Premium) {
const auto userId = peerToUser(_peer->id).bare;
_badgeView->setClickedCallback([=] {
if (_peer->isSelf()) {
showEmojiStatusSelector();
} else {
::Settings::ShowPremium(
_controller,
u"profile__%1"_q.arg(userId));
}
});
} else {
_badgeView->setAttribute(Qt::WA_TransparentForMouseEvents);
}
refreshNameGeometry(width()); refreshNameGeometry(width());
} }
void Cover::showEmojiStatusSelector() { void Cover::showEmojiStatusSelector() {
Expects(_verifiedCheck != nullptr); Expects(_badgeView != nullptr);
if (!_emojiStatusPanel) { if (!_emojiStatusPanel) {
createEmojiStatusSelector(); createEmojiStatusSelector();
} }
const auto parent = _emojiStatusPanel->parentWidget(); const auto parent = _emojiStatusPanel->parentWidget();
const auto global = _verifiedCheck->mapToGlobal({ 0, 0 }); const auto global = _badgeView->mapToGlobal({ 0, 0 });
const auto local = parent->mapFromGlobal(global); const auto local = parent->mapFromGlobal(global);
_emojiStatusPanel->moveBottomRight( _emojiStatusPanel->moveTopRight(
local.y(), local.y() + _badgeView->height(),
local.x() + _verifiedCheck->width() * 3); local.x() + _badgeView->width() * 3);
_emojiStatusPanel->toggleAnimated(); _emojiStatusPanel->toggleAnimated();
} }
void Cover::createEmojiStatusSelector() { void Cover::createEmojiStatusSelector() {
const auto set = [=](DocumentId id) {
_controller->session().user()->setEmojiStatus(id);
_controller->session().api().request(MTPaccount_UpdateEmojiStatus(
id ? MTP_emojiStatus(MTP_long(id)) : MTP_emojiStatusEmpty()
)).send();
_emojiStatusPanel->hideAnimated();
};
const auto container = _controller->window().widget()->bodyWidget(); const auto container = _controller->window().widget()->bodyWidget();
using Selector = ChatHelpers::TabbedSelector; using Selector = ChatHelpers::TabbedSelector;
_emojiStatusPanel = base::make_unique_q<ChatHelpers::TabbedPanel>( _emojiStatusPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
@ -316,20 +329,21 @@ void Cover::createEmojiStatusSelector() {
nullptr, nullptr,
_controller, _controller,
Window::GifPauseReason::Layer, Window::GifPauseReason::Layer,
ChatHelpers::TabbedSelector::Mode::EmojiOnly)); ChatHelpers::TabbedSelector::Mode::EmojiStatus));
_emojiStatusPanel->setDropDown(true);
_emojiStatusPanel->setDesiredHeightValues( _emojiStatusPanel->setDesiredHeightValues(
1., 1.,
st::emojiPanMinHeight / 2, st::emojiPanMinHeight / 2,
st::emojiPanMinHeight); st::emojiPanMinHeight);
_emojiStatusPanel->hide(); _emojiStatusPanel->hide();
_emojiStatusPanel->selector()->setAllowEmojiWithoutPremium(false); _emojiStatusPanel->selector()->setAllowEmojiWithoutPremium(false);
_emojiStatusPanel->selector()->emojiChosen(
) | rpl::start_with_next([=] {
set(0);
}, _emojiStatusPanel->lifetime());
_emojiStatusPanel->selector()->customEmojiChosen( _emojiStatusPanel->selector()->customEmojiChosen(
) | rpl::start_with_next([=](Selector::FileChosen data) { ) | rpl::start_with_next([=](Selector::FileChosen data) {
_controller->session().user()->setEmojiStatus(data.document->id); set(data.document->id);
_controller->session().api().request(MTPaccount_UpdateEmojiStatus(
MTP_emojiStatus(MTP_long(data.document->id))
)).send();
_emojiStatusPanel->hideAnimated();
}, _emojiStatusPanel->lifetime()); }, _emojiStatusPanel->lifetime());
_emojiStatusPanel->selector()->showPromoForPremiumEmoji(); _emojiStatusPanel->selector()->showPromoForPremiumEmoji();
} }
@ -392,31 +406,22 @@ void Cover::refreshNameGeometry(int newWidth) {
auto nameWidth = newWidth auto nameWidth = newWidth
- nameLeft - nameLeft
- st::infoProfileNameRight; - st::infoProfileNameRight;
if (_verifiedCheck) { if (_badgeView) {
nameWidth -= st::infoVerifiedCheckPosition.x() nameWidth -= st::infoVerifiedCheckPosition.x() + _badgeView->width();
+ _verifiedCheck->width();
} else if (_scamFakeBadge) {
nameWidth -= st::infoVerifiedCheckPosition.x()
+ _scamFakeBadge->width();
} }
_name->resizeToNaturalWidth(nameWidth); _name->resizeToNaturalWidth(nameWidth);
_name->moveToLeft(nameLeft, nameTop, newWidth); _name->moveToLeft(nameLeft, nameTop, newWidth);
if (_verifiedCheck) { if (_badgeView) {
const auto checkLeft = nameLeft const auto star = !_emojiStatus
+ _name->width() && (_badge == Badge::Premium || _badge == Badge::Verified);
+ st::infoVerifiedCheckPosition.x(); const auto fake = !_emojiStatus && !star;
const auto checkTop = nameTop const auto skip = fake ? 0 : st::infoVerifiedCheckPosition.x();
+ st::infoVerifiedCheckPosition.y(); const auto badgeLeft = nameLeft + _name->width() + skip;
_verifiedCheck->moveToLeft(checkLeft, checkTop, newWidth);
} else if (_scamFakeBadge) {
const auto skip = st::infoVerifiedCheckPosition.x();
const auto badgeLeft = nameLeft
+ _name->width()
+ st::infoVerifiedCheckPosition.x()
- skip;
const auto badgeTop = nameTop const auto badgeTop = nameTop
+ (_name->height() - _scamFakeBadge->height()) / 2; + (star
_scamFakeBadge->moveToLeft(badgeLeft, badgeTop, newWidth); ? st::infoVerifiedCheckPosition.y()
: (_name->height() - _badgeView->height()) / 2);
_badgeView->moveToLeft(badgeLeft, badgeTop, newWidth);
} }
} }

View file

@ -82,8 +82,7 @@ private:
object_ptr<Ui::UserpicButton> _userpic; object_ptr<Ui::UserpicButton> _userpic;
object_ptr<Ui::FlatLabel> _name = { nullptr }; object_ptr<Ui::FlatLabel> _name = { nullptr };
object_ptr<Ui::AbstractButton> _verifiedCheck = { nullptr }; object_ptr<Ui::AbstractButton> _badgeView = { nullptr };
object_ptr<Ui::RpWidget> _scamFakeBadge = { nullptr };
object_ptr<Ui::FlatLabel> _status = { nullptr }; object_ptr<Ui::FlatLabel> _status = { nullptr };
//object_ptr<CoverDropArea> _dropArea = { nullptr }; //object_ptr<CoverDropArea> _dropArea = { nullptr };
base::Timer _refreshStatusTimer; base::Timer _refreshStatusTimer;