mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Allow to open / remove sets from emoji panel.
This commit is contained in:
parent
a7e295ae64
commit
54d683171d
7 changed files with 419 additions and 214 deletions
|
@ -11,15 +11,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/text/custom_emoji_instance.h"
|
#include "ui/text/custom_emoji_instance.h"
|
||||||
|
#include "ui/effects/ripple_animation.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "ui/cached_round_corners.h"
|
#include "ui/cached_round_corners.h"
|
||||||
|
#include "boxes/sticker_set_box.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "layout/layout_position.h"
|
#include "layout/layout_position.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
#include "chat_helpers/stickers_list_widget.h"
|
||||||
#include "emoji_suggestions_data.h"
|
#include "emoji_suggestions_data.h"
|
||||||
#include "emoji_suggestions_helper.h"
|
#include "emoji_suggestions_helper.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
@ -708,6 +711,9 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
const auto paused = controller()->isGifPausedAtLeastFor(
|
const auto paused = controller()->isGifPausedAtLeastFor(
|
||||||
Window::GifPauseReason::SavedGifs);
|
Window::GifPauseReason::SavedGifs);
|
||||||
const auto now = crl::now();
|
const auto now = crl::now();
|
||||||
|
auto selectedButton = std::get_if<OverButton>(!v::is_null(_pressed)
|
||||||
|
? &_pressed
|
||||||
|
: &_selected);
|
||||||
enumerateSections([&](const SectionInfo &info) {
|
enumerateSections([&](const SectionInfo &info) {
|
||||||
if (r.top() >= info.rowsBottom) {
|
if (r.top() >= info.rowsBottom) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -717,14 +723,32 @@ 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);
|
||||||
const auto text = (info.section < kEmojiSectionCount)
|
auto titleText = (info.section < kEmojiSectionCount)
|
||||||
? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now)
|
? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now)
|
||||||
: _custom[info.section - kEmojiSectionCount].title;
|
: _custom[info.section - kEmojiSectionCount].title;
|
||||||
p.drawTextLeft(
|
auto titleWidth = st::stickersTrendingHeaderFont->width(titleText);
|
||||||
st::emojiPanHeaderLeft - st::roundRadiusSmall,
|
auto widthForTitle = emojiRight() - (st::emojiPanHeaderLeft - st::roundRadiusSmall);
|
||||||
info.top + st::emojiPanHeaderTop,
|
if (hasRemoveButton(info.section)) {
|
||||||
width(),
|
auto &custom = _custom[info.section - kEmojiSectionCount];
|
||||||
text);
|
auto remove = removeButtonRect(info.section);
|
||||||
|
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
|
||||||
|
if (custom.ripple) {
|
||||||
|
custom.ripple->paint(p, remove.x() + st::stickerPanRemoveSet.rippleAreaPosition.x(), remove.y() + st::stickerPanRemoveSet.rippleAreaPosition.y(), width());
|
||||||
|
if (custom.ripple->empty()) {
|
||||||
|
custom.ripple.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(selected ? st::stickerPanRemoveSet.iconOver : st::stickerPanRemoveSet.icon).paint(p, remove.topLeft() + st::stickerPanRemoveSet.iconPosition, width());
|
||||||
|
|
||||||
|
widthForTitle -= remove.width();
|
||||||
|
}
|
||||||
|
if (titleWidth > widthForTitle) {
|
||||||
|
titleText = st::stickersTrendingHeaderFont->elided(titleText, widthForTitle);
|
||||||
|
titleWidth = st::stickersTrendingHeaderFont->width(titleText);
|
||||||
|
}
|
||||||
|
p.setFont(st::emojiPanHeaderFont);
|
||||||
|
p.setPen(st::emojiPanHeaderFg);
|
||||||
|
p.drawTextLeft(st::emojiPanHeaderLeft - st::roundRadiusSmall, info.top + st::emojiPanHeaderTop, width(), titleText, titleWidth);
|
||||||
}
|
}
|
||||||
if (r.top() + r.height() > info.rowsTop) {
|
if (r.top() + r.height() > info.rowsTop) {
|
||||||
ensureLoaded(info.section);
|
ensureLoaded(info.section);
|
||||||
|
@ -735,12 +759,13 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
auto index = i * _columnCount + j;
|
auto index = i * _columnCount + j;
|
||||||
if (index >= info.count) break;
|
if (index >= info.count) break;
|
||||||
|
|
||||||
const auto selectedIndex = Layout::PositionToIndex(
|
const auto state = OverEmoji{
|
||||||
info.section,
|
.section = info.section,
|
||||||
index);
|
.index = index,
|
||||||
auto selected = (selectedIndex == _selected)
|
};
|
||||||
|
const auto selected = (state == _selected)
|
||||||
|| (!_picker->isHidden()
|
|| (!_picker->isHidden()
|
||||||
&& selectedIndex == _pickerSel);
|
&& state == _pickerSelected);
|
||||||
|
|
||||||
auto w = QPoint(_rowsLeft + j * _singleSize.width(), info.rowsTop + i * _singleSize.height());
|
auto w = QPoint(_rowsLeft + j * _singleSize.width(), info.rowsTop + i * _singleSize.height());
|
||||||
if (selected) {
|
if (selected) {
|
||||||
|
@ -794,9 +819,9 @@ void EmojiListWidget::drawCustom(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmojiListWidget::checkPickerHide() {
|
bool EmojiListWidget::checkPickerHide() {
|
||||||
if (!_picker->isHidden() && _pickerSel >= 0) {
|
if (!_picker->isHidden() && !v::is_null(_pickerSelected)) {
|
||||||
_picker->hideAnimated();
|
_picker->hideAnimated();
|
||||||
_pickerSel = -1;
|
_pickerSelected = v::null;
|
||||||
updateSelected();
|
updateSelected();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -809,17 +834,15 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
if (checkPickerHide() || e->button() != Qt::LeftButton) {
|
if (checkPickerHide() || e->button() != Qt::LeftButton) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_pressedSel = _selected;
|
setPressed(_selected);
|
||||||
|
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
||||||
if (_selected >= 0) {
|
if (over->section < kEmojiSectionCount
|
||||||
const auto &[section, sel] = Layout::IndexToPosition(_selected);
|
&& over->index < _emoji[over->section].size()
|
||||||
if (section < kEmojiSectionCount
|
&& _emoji[over->section][over->index]->hasVariants()) {
|
||||||
&& sel < _emoji[section].size()
|
_pickerSelected = _selected;
|
||||||
&& _emoji[section][sel]->hasVariants()) {
|
|
||||||
_pickerSel = _selected;
|
|
||||||
setCursor(style::cur_default);
|
setCursor(style::cur_default);
|
||||||
const auto &variants = Core::App().settings().emojiVariants();
|
const auto &variants = Core::App().settings().emojiVariants();
|
||||||
if (!variants.contains(_emoji[section][sel]->nonColoredId())) {
|
if (!variants.contains(_emoji[over->section][over->index]->nonColoredId())) {
|
||||||
showPicker();
|
showPicker();
|
||||||
} else {
|
} else {
|
||||||
_showPickerTimer.callOnce(500);
|
_showPickerTimer.callOnce(500);
|
||||||
|
@ -829,22 +852,22 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
int32 pressed = _pressedSel;
|
auto pressed = _pressed;
|
||||||
_pressedSel = -1;
|
setPressed(v::null);
|
||||||
|
|
||||||
_lastMousePos = e->globalPos();
|
_lastMousePos = e->globalPos();
|
||||||
if (!_picker->isHidden()) {
|
if (!_picker->isHidden()) {
|
||||||
if (_picker->rect().contains(_picker->mapFromGlobal(_lastMousePos))) {
|
if (_picker->rect().contains(_picker->mapFromGlobal(_lastMousePos))) {
|
||||||
return _picker->handleMouseRelease(QCursor::pos());
|
return _picker->handleMouseRelease(QCursor::pos());
|
||||||
} else if (_pickerSel >= 0) {
|
} else if (const auto over = std::get_if<OverEmoji>(&_pickerSelected)) {
|
||||||
const auto &[section, sel] = Layout::IndexToPosition(_pickerSel);
|
const auto section = over->section;
|
||||||
|
const auto index = over->index;
|
||||||
if (section < kEmojiSectionCount
|
if (section < kEmojiSectionCount
|
||||||
&& sel < _emoji[section].size()
|
&& index < _emoji[section].size()
|
||||||
&& _emoji[section][sel]->hasVariants()) {
|
&& _emoji[section][index]->hasVariants()) {
|
||||||
const auto &variants = Core::App().settings().emojiVariants();
|
const auto &variants = Core::App().settings().emojiVariants();
|
||||||
if (variants.contains(_emoji[section][sel]->nonColoredId())) {
|
if (variants.contains(_emoji[section][index]->nonColoredId())) {
|
||||||
_picker->hideAnimated();
|
_picker->hideAnimated();
|
||||||
_pickerSel = -1;
|
_pickerSelected = v::null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,25 +876,54 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
|
||||||
if (_showPickerTimer.isActive()) {
|
if (_showPickerTimer.isActive()) {
|
||||||
_showPickerTimer.cancel();
|
_showPickerTimer.cancel();
|
||||||
_pickerSel = -1;
|
_pickerSelected = v::null;
|
||||||
_picker->hide();
|
_picker->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_selected < 0 || _selected != pressed) {
|
if (v::is_null(_selected) || _selected != pressed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &[section, sel] = Layout::IndexToPosition(_selected);
|
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
||||||
if (section < kEmojiSectionCount && sel < _emoji[section].size()) {
|
const auto section = over->section;
|
||||||
const auto emoji = _emoji[section][sel];
|
const auto index = over->index;
|
||||||
if (emoji->hasVariants() && !_picker->isHidden()) {
|
if (section < kEmojiSectionCount && index < _emoji[section].size()) {
|
||||||
return;
|
const auto emoji = _emoji[section][index];
|
||||||
|
if (emoji->hasVariants() && !_picker->isHidden()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectEmoji(emoji);
|
||||||
|
} else if (section >= kEmojiSectionCount
|
||||||
|
&& index < _custom[section - kEmojiSectionCount].list.size()) {
|
||||||
|
auto &set = _custom[section - kEmojiSectionCount];
|
||||||
|
selectCustom(set.list[index].document);
|
||||||
}
|
}
|
||||||
selectEmoji(emoji);
|
} else if (const auto set = std::get_if<OverSet>(&pressed)) {
|
||||||
} else if (section >= kEmojiSectionCount
|
Assert(set->section >= kEmojiSectionCount
|
||||||
&& sel < _custom[section - kEmojiSectionCount].list.size()) {
|
&& set->section < kEmojiSectionCount + _custom.size());
|
||||||
auto &set = _custom[section - kEmojiSectionCount];
|
displaySet(_custom[set->section - kEmojiSectionCount].id);
|
||||||
selectCustom(set.list[sel].document);
|
} else if (auto button = std::get_if<OverButton>(&pressed)) {
|
||||||
|
Assert(button->section >= kEmojiSectionCount
|
||||||
|
&& button->section < kEmojiSectionCount + _custom.size());
|
||||||
|
removeSet(_custom[button->section - kEmojiSectionCount].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiListWidget::displaySet(uint64 setId) {
|
||||||
|
const auto &sets = session().data().stickers().sets();
|
||||||
|
auto it = sets.find(setId);
|
||||||
|
if (it != sets.cend()) {
|
||||||
|
checkHideWithBox(controller()->show(
|
||||||
|
Box<StickerSetBox>(controller(), it->second->identifier()),
|
||||||
|
Ui::LayerOption::KeepOther).data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiListWidget::removeSet(uint64 setId) {
|
||||||
|
if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) {
|
||||||
|
checkHideWithBox(controller()->show(
|
||||||
|
std::move(box),
|
||||||
|
Ui::LayerOption::KeepOther));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,19 +937,25 @@ void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::showPicker() {
|
void EmojiListWidget::showPicker() {
|
||||||
if (_pickerSel < 0) return;
|
if (v::is_null(_pickerSelected)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto &[section, sel] = Layout::IndexToPosition(_pickerSel);
|
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||||
if (section < kEmojiSectionCount && sel < _emoji[section].size() && _emoji[section][sel]->hasVariants()) {
|
const auto section = over ? over->section : -1;
|
||||||
_picker->showEmoji(_emoji[section][sel]);
|
if (section >= 0
|
||||||
|
&& section < kEmojiSectionCount
|
||||||
|
&& over->index < _emoji[section].size()
|
||||||
|
&& _emoji[section][over->index]->hasVariants()) {
|
||||||
|
_picker->showEmoji(_emoji[section][over->index]);
|
||||||
|
|
||||||
auto y = emojiRect(section, sel).y();
|
auto y = emojiRect(section, over->index).y();
|
||||||
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
|
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
|
||||||
if (y < st::emojiPanHeader) {
|
if (y < st::emojiPanHeader) {
|
||||||
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
|
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
|
||||||
}
|
}
|
||||||
auto xmax = width() - _picker->width();
|
auto xmax = width() - _picker->width();
|
||||||
auto coef = float64(sel % _columnCount) / float64(_columnCount - 1);
|
auto coef = float64(over->index % _columnCount) / float64(_columnCount - 1);
|
||||||
if (rtl()) coef = 1. - coef;
|
if (rtl()) coef = 1. - coef;
|
||||||
_picker->move(qRound(xmax * coef), y);
|
_picker->move(qRound(xmax * coef), y);
|
||||||
|
|
||||||
|
@ -906,7 +964,7 @@ void EmojiListWidget::showPicker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::pickerHidden() {
|
void EmojiListWidget::pickerHidden() {
|
||||||
_pickerSel = -1;
|
_pickerSelected = v::null;
|
||||||
update();
|
update();
|
||||||
disableScroll(false);
|
disableScroll(false);
|
||||||
|
|
||||||
|
@ -914,14 +972,39 @@ void EmojiListWidget::pickerHidden() {
|
||||||
updateSelected();
|
updateSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect EmojiListWidget::emojiRect(int section, int sel) const {
|
bool EmojiListWidget::hasRemoveButton(int index) const {
|
||||||
|
if (index < kEmojiSectionCount
|
||||||
|
|| index >= kEmojiSectionCount + _custom.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect EmojiListWidget::removeButtonRect(int index) const {
|
||||||
|
auto buttonw = st::stickerPanRemoveSet.width;
|
||||||
|
auto buttonh = st::stickerPanRemoveSet.height;
|
||||||
|
auto buttonx = emojiRight() - buttonw;
|
||||||
|
auto buttony = sectionInfo(index).top + (st::emojiPanHeader - buttonh) / 2;
|
||||||
|
return QRect(buttonx, buttony, buttonw, buttonh);
|
||||||
|
}
|
||||||
|
|
||||||
|
int EmojiListWidget::emojiRight() const {
|
||||||
|
return emojiLeft() + (_columnCount * _singleSize.width());
|
||||||
|
}
|
||||||
|
|
||||||
|
int EmojiListWidget::emojiLeft() const {
|
||||||
|
return _rowsLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect EmojiListWidget::emojiRect(int section, int index) const {
|
||||||
Expects(_columnCount > 0);
|
Expects(_columnCount > 0);
|
||||||
|
|
||||||
auto info = sectionInfo(section);
|
const auto info = sectionInfo(section);
|
||||||
auto countTillItem = (sel - (sel % _columnCount));
|
const auto countTillItem = (index - (index % _columnCount));
|
||||||
auto rowsToSkip = (countTillItem / _columnCount) + ((countTillItem % _columnCount) ? 1 : 0);
|
const auto rowsToSkip = (countTillItem / _columnCount)
|
||||||
auto x = _rowsLeft + ((sel % _columnCount) * _singleSize.width());
|
+ ((countTillItem % _columnCount) ? 1 : 0);
|
||||||
auto y = info.rowsTop + rowsToSkip * _singleSize.height();
|
const auto x = _rowsLeft + ((index % _columnCount) * _singleSize.width());
|
||||||
|
const auto y = info.rowsTop + rowsToSkip * _singleSize.height();
|
||||||
return QRect(x, y, _singleSize.width(), _singleSize.height());
|
return QRect(x, y, _singleSize.width(), _singleSize.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,12 +1012,10 @@ void EmojiListWidget::colorChosen(EmojiPtr emoji) {
|
||||||
if (emoji->hasVariants()) {
|
if (emoji->hasVariants()) {
|
||||||
Core::App().settings().saveEmojiVariant(emoji);
|
Core::App().settings().saveEmojiVariant(emoji);
|
||||||
}
|
}
|
||||||
if (_pickerSel >= 0) {
|
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||||
const auto &[section, sel] = Layout::IndexToPosition(_pickerSel);
|
if (over && over->section >= 0 && over->section < kEmojiSectionCount) {
|
||||||
if (section >= 0 && section < kEmojiSectionCount) {
|
_emoji[over->section][over->index] = emoji;
|
||||||
_emoji[section][sel] = emoji;
|
rtlupdate(emojiRect(over->section, over->index));
|
||||||
rtlupdate(emojiRect(section, sel));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
selectEmoji(emoji);
|
selectEmoji(emoji);
|
||||||
_picker->hideAnimated();
|
_picker->hideAnimated();
|
||||||
|
@ -966,9 +1047,9 @@ void EmojiListWidget::enterFromChildEvent(QEvent *e, QWidget *child) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::clearSelection() {
|
void EmojiListWidget::clearSelection() {
|
||||||
|
setPressed(v::null);
|
||||||
|
setSelected(v::null);
|
||||||
_lastMousePos = mapToGlobal(QPoint(-10, -10));
|
_lastMousePos = mapToGlobal(QPoint(-10, -10));
|
||||||
_pressedSel = -1;
|
|
||||||
setSelected(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ui::Emoji::Section EmojiListWidget::currentSection(int yOffset) const {
|
Ui::Emoji::Section EmojiListWidget::currentSection(int yOffset) const {
|
||||||
|
@ -977,9 +1058,13 @@ Ui::Emoji::Section EmojiListWidget::currentSection(int yOffset) const {
|
||||||
|
|
||||||
QString EmojiListWidget::tooltipText() const {
|
QString EmojiListWidget::tooltipText() const {
|
||||||
const auto &replacements = Ui::Emoji::internal::GetAllReplacements();
|
const auto &replacements = Ui::Emoji::internal::GetAllReplacements();
|
||||||
const auto &[section, sel] = Layout::IndexToPosition(_selected);
|
const auto over = std::get_if<OverEmoji>(&_selected);
|
||||||
if (_selected >= 0 && section < kEmojiSectionCount && sel < _emoji[section].size()) {
|
const auto section = over ? over->section : -1;
|
||||||
const auto emoji = _emoji[section][sel]->original();
|
const auto index = over ? over->index : -1;
|
||||||
|
if (section >= 0
|
||||||
|
&& section < kEmojiSectionCount
|
||||||
|
&& index < _emoji[section].size()) {
|
||||||
|
const auto emoji = _emoji[section][index]->original();
|
||||||
const auto text = emoji->text();
|
const auto text = emoji->text();
|
||||||
// find the replacement belonging to the emoji
|
// find the replacement belonging to the emoji
|
||||||
const auto it = ranges::find_if(replacements, [&](const auto &one) {
|
const auto it = ranges::find_if(replacements, [&](const auto &one) {
|
||||||
|
@ -1007,7 +1092,7 @@ TabbedSelector::InnerFooter *EmojiListWidget::getFooter() const {
|
||||||
void EmojiListWidget::processHideFinished() {
|
void EmojiListWidget::processHideFinished() {
|
||||||
if (!_picker->isHidden()) {
|
if (!_picker->isHidden()) {
|
||||||
_picker->hideFast();
|
_picker->hideFast();
|
||||||
_pickerSel = -1;
|
_pickerSelected = v::null;
|
||||||
}
|
}
|
||||||
clearSelection();
|
clearSelection();
|
||||||
}
|
}
|
||||||
|
@ -1102,48 +1187,59 @@ bool EmojiListWidget::eventHook(QEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::updateSelected() {
|
void EmojiListWidget::updateSelected() {
|
||||||
if (_pressedSel >= 0 || _pickerSel >= 0) return;
|
if (!v::is_null(_pressed) || !v::is_null(_pickerSelected)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto newSelected = -1;
|
auto newSelected = OverState{ v::null };
|
||||||
auto p = mapFromGlobal(_lastMousePos);
|
auto p = mapFromGlobal(_lastMousePos);
|
||||||
auto info = sectionInfoByOffset(p.y());
|
auto info = sectionInfoByOffset(p.y());
|
||||||
if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
|
auto section = info.section;
|
||||||
|
if (p.y() >= info.top && p.y() < info.rowsTop) {
|
||||||
|
if (hasRemoveButton(section) && myrtlrect(removeButtonRect(section)).contains(p.x(), p.y())) {
|
||||||
|
newSelected = OverButton{ section };
|
||||||
|
} else {
|
||||||
|
newSelected = OverSet{ section };
|
||||||
|
}
|
||||||
|
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
|
||||||
auto sx = (rtl() ? width() - p.x() : p.x()) - _rowsLeft;
|
auto sx = (rtl() ? width() - p.x() : p.x()) - _rowsLeft;
|
||||||
if (sx >= 0 && sx < _columnCount * _singleSize.width()) {
|
if (sx >= 0 && sx < _columnCount * _singleSize.width()) {
|
||||||
newSelected = qFloor((p.y() - info.rowsTop) / _singleSize.height()) * _columnCount + qFloor(sx / _singleSize.width());
|
const auto index = qFloor((p.y() - info.rowsTop) / _singleSize.height()) * _columnCount + qFloor(sx / _singleSize.width());
|
||||||
if (newSelected >= info.count) {
|
if (index < info.count) {
|
||||||
newSelected = -1;
|
newSelected = OverEmoji{ .section = section, .index = index };
|
||||||
} else {
|
|
||||||
newSelected += Layout::PositionToIndex(info.section, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelected(newSelected);
|
setSelected(newSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::setSelected(int newSelected) {
|
void EmojiListWidget::setSelected(OverState newSelected) {
|
||||||
if (_selected == newSelected) {
|
if (_selected == newSelected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto updateSelected = [this]() {
|
setCursor(!v::is_null(newSelected)
|
||||||
if (_selected < 0) {
|
? style::cur_pointer
|
||||||
return;
|
: style::cur_default);
|
||||||
|
|
||||||
|
const auto updateSelected = [&] {
|
||||||
|
if (const auto sticker = std::get_if<OverEmoji>(&_selected)) {
|
||||||
|
rtlupdate(emojiRect(sticker->section, sticker->index));
|
||||||
|
} else if (const auto button = std::get_if<OverButton>(&_selected)) {
|
||||||
|
rtlupdate(removeButtonRect(button->section));
|
||||||
}
|
}
|
||||||
const auto &[section, sel] = Layout::IndexToPosition(_selected);
|
|
||||||
rtlupdate(emojiRect(section, sel));
|
|
||||||
};
|
};
|
||||||
updateSelected();
|
updateSelected();
|
||||||
_selected = newSelected;
|
_selected = newSelected;
|
||||||
updateSelected();
|
updateSelected();
|
||||||
|
|
||||||
if (_selected >= 0 && Core::App().settings().suggestEmoji()) {
|
const auto hasSelection = !v::is_null(_selected);
|
||||||
|
if (hasSelection && Core::App().settings().suggestEmoji()) {
|
||||||
Ui::Tooltip::Show(1000, this);
|
Ui::Tooltip::Show(1000, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default);
|
setCursor(hasSelection ? style::cur_pointer : style::cur_default);
|
||||||
if (_selected >= 0 && !_picker->isHidden()) {
|
if (hasSelection && !_picker->isHidden()) {
|
||||||
if (_selected != _pickerSel) {
|
if (_selected != _pickerSelected) {
|
||||||
_picker->hideAnimated();
|
_picker->hideAnimated();
|
||||||
} else {
|
} else {
|
||||||
_picker->showAnimated();
|
_picker->showAnimated();
|
||||||
|
@ -1151,6 +1247,51 @@ void EmojiListWidget::setSelected(int newSelected) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmojiListWidget::setPressed(OverState newPressed) {
|
||||||
|
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||||
|
Assert(button->section >= kEmojiSectionCount
|
||||||
|
&& button->section < kEmojiSectionCount + _custom.size());
|
||||||
|
auto &set = _custom[button->section - kEmojiSectionCount];
|
||||||
|
if (set.ripple) {
|
||||||
|
set.ripple->lastStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_pressed = newPressed;
|
||||||
|
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||||
|
Assert(button->section >= kEmojiSectionCount
|
||||||
|
&& button->section < kEmojiSectionCount + _custom.size());
|
||||||
|
auto &set = _custom[button->section - kEmojiSectionCount];
|
||||||
|
if (!set.ripple) {
|
||||||
|
set.ripple = createButtonRipple(button->section);
|
||||||
|
}
|
||||||
|
set.ripple->add(mapFromGlobal(QCursor::pos()) - buttonRippleTopLeft(button->section));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::RippleAnimation> EmojiListWidget::createButtonRipple(
|
||||||
|
int section) {
|
||||||
|
Expects(section >= kEmojiSectionCount
|
||||||
|
&& section < kEmojiSectionCount + _custom.size());
|
||||||
|
|
||||||
|
const auto set = section - kEmojiSectionCount;
|
||||||
|
auto maskSize = QSize(
|
||||||
|
st::stickerPanRemoveSet.rippleAreaSize,
|
||||||
|
st::stickerPanRemoveSet.rippleAreaSize);
|
||||||
|
auto mask = Ui::RippleAnimation::ellipseMask(maskSize);
|
||||||
|
return std::make_unique<Ui::RippleAnimation>(
|
||||||
|
st::stickerPanRemoveSet.ripple,
|
||||||
|
std::move(mask),
|
||||||
|
[this, section] { rtlupdate(removeButtonRect(section)); });
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint EmojiListWidget::buttonRippleTopLeft(int section) const {
|
||||||
|
Expects(section >= kEmojiSectionCount
|
||||||
|
&& section < kEmojiSectionCount + _custom.size());
|
||||||
|
|
||||||
|
return myrtlrect(removeButtonRect(section)).topLeft()
|
||||||
|
+ st::stickerPanRemoveSet.rippleAreaPosition;
|
||||||
|
}
|
||||||
|
|
||||||
void EmojiListWidget::showEmojiSection(Section section) {
|
void EmojiListWidget::showEmojiSection(Section section) {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,10 @@ template <typename ...Tags>
|
||||||
struct phrase;
|
struct phrase;
|
||||||
} // namespace tr
|
} // namespace tr
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class RippleAnimation;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Ui::Emoji {
|
namespace Ui::Emoji {
|
||||||
enum class Section;
|
enum class Section;
|
||||||
} // namespace Ui::Emoji
|
} // namespace Ui::Emoji
|
||||||
|
@ -102,12 +106,50 @@ private:
|
||||||
uint64 id = 0;
|
uint64 id = 0;
|
||||||
QString title;
|
QString title;
|
||||||
std::vector<CustomOne> list;
|
std::vector<CustomOne> list;
|
||||||
|
std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||||
bool painted = false;
|
bool painted = false;
|
||||||
};
|
};
|
||||||
struct RepaintSet {
|
struct RepaintSet {
|
||||||
base::flat_set<uint64> ids;
|
base::flat_set<uint64> ids;
|
||||||
crl::time when = 0;
|
crl::time when = 0;
|
||||||
};
|
};
|
||||||
|
struct OverEmoji {
|
||||||
|
int section = 0;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
inline bool operator==(OverEmoji other) const {
|
||||||
|
return (section == other.section)
|
||||||
|
&& (index == other.index);
|
||||||
|
}
|
||||||
|
inline bool operator!=(OverEmoji other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct OverSet {
|
||||||
|
int section = 0;
|
||||||
|
|
||||||
|
inline bool operator==(OverSet other) const {
|
||||||
|
return (section == other.section);
|
||||||
|
}
|
||||||
|
inline bool operator!=(OverSet other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct OverButton {
|
||||||
|
int section = 0;
|
||||||
|
|
||||||
|
inline bool operator==(OverButton other) const {
|
||||||
|
return (section == other.section);
|
||||||
|
}
|
||||||
|
inline bool operator!=(OverButton other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using OverState = std::variant<
|
||||||
|
v::null_t,
|
||||||
|
OverEmoji,
|
||||||
|
OverSet,
|
||||||
|
OverButton>;
|
||||||
|
|
||||||
template <typename Callback>
|
template <typename Callback>
|
||||||
bool enumerateSections(Callback callback) const;
|
bool enumerateSections(Callback callback) const;
|
||||||
|
@ -124,7 +166,8 @@ private:
|
||||||
|
|
||||||
void ensureLoaded(int section);
|
void ensureLoaded(int section);
|
||||||
void updateSelected();
|
void updateSelected();
|
||||||
void setSelected(int newSelected);
|
void setSelected(OverState newSelected);
|
||||||
|
void setPressed(OverState newPressed);
|
||||||
|
|
||||||
void selectEmoji(EmojiPtr emoji);
|
void selectEmoji(EmojiPtr emoji);
|
||||||
void selectCustom(not_null<DocumentData*> document);
|
void selectCustom(not_null<DocumentData*> document);
|
||||||
|
@ -140,7 +183,18 @@ private:
|
||||||
bool paused,
|
bool paused,
|
||||||
int set,
|
int set,
|
||||||
int index);
|
int index);
|
||||||
[[nodiscard]] QRect emojiRect(int section, int sel) const;
|
[[nodiscard]] bool hasRemoveButton(int index) const;
|
||||||
|
[[nodiscard]] QRect removeButtonRect(int index) const;
|
||||||
|
[[nodiscard]] QRect emojiRect(int section, int index) const;
|
||||||
|
[[nodiscard]] int emojiRight() const;
|
||||||
|
[[nodiscard]] int emojiLeft() const;
|
||||||
|
|
||||||
|
void displaySet(uint64 setId);
|
||||||
|
void removeSet(uint64 setId);
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<Ui::RippleAnimation> createButtonRipple(
|
||||||
|
int section);
|
||||||
|
[[nodiscard]] QPoint buttonRippleTopLeft(int section) const;
|
||||||
|
|
||||||
void repaintLater(
|
void repaintLater(
|
||||||
uint64 setId,
|
uint64 setId,
|
||||||
|
@ -162,9 +216,9 @@ private:
|
||||||
QSize _singleSize;
|
QSize _singleSize;
|
||||||
int _esize = 0;
|
int _esize = 0;
|
||||||
|
|
||||||
int _selected = -1;
|
OverState _selected;
|
||||||
int _pressedSel = -1;
|
OverState _pressed;
|
||||||
int _pickerSel = -1;
|
OverState _pickerSelected;
|
||||||
QPoint _lastMousePos;
|
QPoint _lastMousePos;
|
||||||
|
|
||||||
object_ptr<EmojiColorPicker> _picker;
|
object_ptr<EmojiColorPicker> _picker;
|
||||||
|
|
|
@ -1195,10 +1195,6 @@ StickersListWidget::StickersListWidget(
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
Main::Session &StickersListWidget::session() const {
|
|
||||||
return controller()->session();
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<TabbedSelector::FileChosen> StickersListWidget::chosen() const {
|
rpl::producer<TabbedSelector::FileChosen> StickersListWidget::chosen() const {
|
||||||
return _chosen.events();
|
return _chosen.events();
|
||||||
}
|
}
|
||||||
|
@ -1207,10 +1203,6 @@ rpl::producer<> StickersListWidget::scrollUpdated() const {
|
||||||
return _scrollUpdated.events();
|
return _scrollUpdated.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<> StickersListWidget::checkForHide() const {
|
|
||||||
return _checkForHide.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto StickersListWidget::choosingUpdated() const
|
auto StickersListWidget::choosingUpdated() const
|
||||||
-> rpl::producer<TabbedSelector::Action> {
|
-> rpl::producer<TabbedSelector::Action> {
|
||||||
return _choosingUpdated.events();
|
return _choosingUpdated.events();
|
||||||
|
@ -2554,7 +2546,6 @@ QPoint StickersListWidget::buttonRippleTopLeft(int section) const {
|
||||||
|
|
||||||
void StickersListWidget::showStickerSetBox(not_null<DocumentData*> document) {
|
void StickersListWidget::showStickerSetBox(not_null<DocumentData*> document) {
|
||||||
if (document->sticker() && document->sticker()->set) {
|
if (document->sticker() && document->sticker()->set) {
|
||||||
_displayingSet = true;
|
|
||||||
checkHideWithBox(StickerSetBox::Show(controller(), document));
|
checkHideWithBox(StickerSetBox::Show(controller(), document));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3364,10 +3355,6 @@ std::vector<StickerIcon> StickersListWidget::fillIcons() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StickersListWidget::preventAutoHide() {
|
|
||||||
return _removingSetId != 0 || _displayingSet != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StickersListWidget::updateSelected() {
|
void StickersListWidget::updateSelected() {
|
||||||
if (!v::is_null(_pressed) && !_previewShown) {
|
if (!v::is_null(_pressed) && !_previewShown) {
|
||||||
return;
|
return;
|
||||||
|
@ -3598,7 +3585,6 @@ void StickersListWidget::beforeHiding() {
|
||||||
void StickersListWidget::displaySet(uint64 setId) {
|
void StickersListWidget::displaySet(uint64 setId) {
|
||||||
if (setId == Data::Stickers::MegagroupSetId) {
|
if (setId == Data::Stickers::MegagroupSetId) {
|
||||||
if (_megagroupSet->canEditStickers()) {
|
if (_megagroupSet->canEditStickers()) {
|
||||||
_displayingSet = true;
|
|
||||||
checkHideWithBox(controller()->show(
|
checkHideWithBox(controller()->show(
|
||||||
Box<StickersBox>(controller(), _megagroupSet),
|
Box<StickersBox>(controller(), _megagroupSet),
|
||||||
Ui::LayerOption::KeepOther).data());
|
Ui::LayerOption::KeepOther).data());
|
||||||
|
@ -3612,23 +3598,12 @@ void StickersListWidget::displaySet(uint64 setId) {
|
||||||
const auto &sets = session().data().stickers().sets();
|
const auto &sets = session().data().stickers().sets();
|
||||||
auto it = sets.find(setId);
|
auto it = sets.find(setId);
|
||||||
if (it != sets.cend()) {
|
if (it != sets.cend()) {
|
||||||
_displayingSet = true;
|
|
||||||
checkHideWithBox(controller()->show(
|
checkHideWithBox(controller()->show(
|
||||||
Box<StickerSetBox>(controller(), it->second->identifier()),
|
Box<StickerSetBox>(controller(), it->second->identifier()),
|
||||||
Ui::LayerOption::KeepOther).data());
|
Ui::LayerOption::KeepOther).data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListWidget::checkHideWithBox(QPointer<Ui::BoxContent> box) {
|
|
||||||
if (!box) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
connect(box, &QObject::destroyed, this, [=] {
|
|
||||||
_displayingSet = false;
|
|
||||||
_checkForHide.fire({});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void StickersListWidget::installSet(uint64 setId) {
|
void StickersListWidget::installSet(uint64 setId) {
|
||||||
const auto &sets = session().data().stickers().sets();
|
const auto &sets = session().data().stickers().sets();
|
||||||
const auto it = sets.find(setId);
|
const auto it = sets.find(setId);
|
||||||
|
@ -3680,8 +3655,7 @@ void StickersListWidget::removeMegagroupSet(bool locally) {
|
||||||
refreshStickers();
|
refreshStickers();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_removingSetId = Data::Stickers::MegagroupSetId;
|
checkHideWithBox(controller()->show(Ui::MakeConfirmBox({
|
||||||
controller()->show(Ui::MakeConfirmBox({
|
|
||||||
.text = tr::lng_stickers_remove_group_set(),
|
.text = tr::lng_stickers_remove_group_set(),
|
||||||
.confirmed = crl::guard(this, [this, group = _megagroupSet](
|
.confirmed = crl::guard(this, [this, group = _megagroupSet](
|
||||||
Fn<void()> &&close) {
|
Fn<void()> &&close) {
|
||||||
|
@ -3691,92 +3665,19 @@ void StickersListWidget::removeMegagroupSet(bool locally) {
|
||||||
session().api().setGroupStickerSet(group, {});
|
session().api().setGroupStickerSet(group, {});
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
_removingSetId = 0;
|
|
||||||
_checkForHide.fire({});
|
|
||||||
}),
|
}),
|
||||||
.cancelled = crl::guard(this, [this] {
|
.cancelled = crl::guard(this, [this](Fn<void()> &&close) {
|
||||||
_removingSetId = 0;
|
close();
|
||||||
_checkForHide.fire({});
|
|
||||||
}),
|
}),
|
||||||
}));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListWidget::removeSet(uint64 setId) {
|
void StickersListWidget::removeSet(uint64 setId) {
|
||||||
const auto &sets = session().data().stickers().sets();
|
if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) {
|
||||||
const auto it = sets.find(setId);
|
checkHideWithBox(controller()->show(
|
||||||
if (it == sets.cend()) {
|
std::move(box),
|
||||||
return;
|
Ui::LayerOption::KeepOther));
|
||||||
}
|
}
|
||||||
const auto set = it->second.get();
|
|
||||||
_removingSetId = set->id;
|
|
||||||
const auto text = tr::lng_stickers_remove_pack(
|
|
||||||
tr::now,
|
|
||||||
lt_sticker_pack,
|
|
||||||
set->title);
|
|
||||||
controller()->show(Ui::MakeConfirmBox({
|
|
||||||
.text = text,
|
|
||||||
.confirmed = crl::guard(this, [=](Fn<void()> &&close) {
|
|
||||||
close();
|
|
||||||
const auto &sets = session().data().stickers().sets();
|
|
||||||
const auto it = sets.find(_removingSetId);
|
|
||||||
if (it != sets.cend()) {
|
|
||||||
const auto set = it->second.get();
|
|
||||||
if (set->id && set->accessHash) {
|
|
||||||
_api.request(MTPmessages_UninstallStickerSet(
|
|
||||||
MTP_inputStickerSetID(
|
|
||||||
MTP_long(set->id),
|
|
||||||
MTP_long(set->accessHash)))
|
|
||||||
).send();
|
|
||||||
} else if (!set->shortName.isEmpty()) {
|
|
||||||
_api.request(MTPmessages_UninstallStickerSet(
|
|
||||||
MTP_inputStickerSetShortName(
|
|
||||||
MTP_string(set->shortName)))
|
|
||||||
).send();
|
|
||||||
}
|
|
||||||
auto writeRecent = false;
|
|
||||||
auto &recent = session().data().stickers().getRecentPack();
|
|
||||||
for (auto i = recent.begin(); i != recent.cend();) {
|
|
||||||
if (set->stickers.indexOf(i->first) >= 0) {
|
|
||||||
i = recent.erase(i);
|
|
||||||
writeRecent = true;
|
|
||||||
} else {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set->flags &= ~SetFlag::Installed;
|
|
||||||
set->installDate = TimeId(0);
|
|
||||||
//
|
|
||||||
// Set can be in search results.
|
|
||||||
//
|
|
||||||
//if (!(set->flags & SetFlag::Featured)
|
|
||||||
// && !(set->flags & SetFlag::Special)) {
|
|
||||||
// sets.erase(it);
|
|
||||||
//}
|
|
||||||
const auto removeIndex = defaultSetsOrder().indexOf(
|
|
||||||
_removingSetId);
|
|
||||||
if (removeIndex >= 0) {
|
|
||||||
defaultSetsOrderRef().removeAt(removeIndex);
|
|
||||||
}
|
|
||||||
refreshStickers();
|
|
||||||
if (set->flags & SetFlag::Masks) {
|
|
||||||
session().local().writeInstalledMasks();
|
|
||||||
} else {
|
|
||||||
session().local().writeInstalledStickers();
|
|
||||||
}
|
|
||||||
if (writeRecent) {
|
|
||||||
session().saveSettings();
|
|
||||||
}
|
|
||||||
session().data().stickers().notifyUpdated();
|
|
||||||
}
|
|
||||||
_removingSetId = 0;
|
|
||||||
_checkForHide.fire({});
|
|
||||||
}),
|
|
||||||
.cancelled = crl::guard(this, [=] {
|
|
||||||
_removingSetId = 0;
|
|
||||||
_checkForHide.fire({});
|
|
||||||
}),
|
|
||||||
.confirmText = tr::lng_stickers_remove_pack_confirm(),
|
|
||||||
}), Ui::LayerOption::KeepOther);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Data::StickersSetsOrder &StickersListWidget::defaultSetsOrder() const {
|
const Data::StickersSetsOrder &StickersListWidget::defaultSetsOrder() const {
|
||||||
|
@ -3797,4 +3698,83 @@ bool StickersListWidget::mySetsEmpty() const {
|
||||||
|
|
||||||
StickersListWidget::~StickersListWidget() = default;
|
StickersListWidget::~StickersListWidget() = default;
|
||||||
|
|
||||||
|
object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
uint64 setId) {
|
||||||
|
const auto &sets = session->data().stickers().sets();
|
||||||
|
const auto it = sets.find(setId);
|
||||||
|
if (it == sets.cend()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const auto set = it->second.get();
|
||||||
|
const auto text = tr::lng_stickers_remove_pack(
|
||||||
|
tr::now,
|
||||||
|
lt_sticker_pack,
|
||||||
|
set->title);
|
||||||
|
return Ui::MakeConfirmBox({
|
||||||
|
.text = text,
|
||||||
|
.confirmed = [=](Fn<void()> &&close) {
|
||||||
|
close();
|
||||||
|
const auto &sets = session->data().stickers().sets();
|
||||||
|
const auto it = sets.find(setId);
|
||||||
|
if (it != sets.cend()) {
|
||||||
|
const auto set = it->second.get();
|
||||||
|
if (set->id && set->accessHash) {
|
||||||
|
session->api().request(MTPmessages_UninstallStickerSet(
|
||||||
|
MTP_inputStickerSetID(
|
||||||
|
MTP_long(set->id),
|
||||||
|
MTP_long(set->accessHash)))
|
||||||
|
).send();
|
||||||
|
} else if (!set->shortName.isEmpty()) {
|
||||||
|
session->api().request(MTPmessages_UninstallStickerSet(
|
||||||
|
MTP_inputStickerSetShortName(
|
||||||
|
MTP_string(set->shortName)))
|
||||||
|
).send();
|
||||||
|
}
|
||||||
|
auto writeRecent = false;
|
||||||
|
auto &recent = session->data().stickers().getRecentPack();
|
||||||
|
for (auto i = recent.begin(); i != recent.cend();) {
|
||||||
|
if (set->stickers.indexOf(i->first) >= 0) {
|
||||||
|
i = recent.erase(i);
|
||||||
|
writeRecent = true;
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set->flags &= ~SetFlag::Installed;
|
||||||
|
set->installDate = TimeId(0);
|
||||||
|
//
|
||||||
|
// Set can be in search results.
|
||||||
|
//
|
||||||
|
//if (!(set->flags & SetFlag::Featured)
|
||||||
|
// && !(set->flags & SetFlag::Special)) {
|
||||||
|
// sets.erase(it);
|
||||||
|
//}
|
||||||
|
auto &orderRef = (set->flags & SetFlag::Emoji)
|
||||||
|
? session->data().stickers().emojiSetsOrderRef()
|
||||||
|
: (set->flags & SetFlag::Masks)
|
||||||
|
? session->data().stickers().maskSetsOrderRef()
|
||||||
|
: session->data().stickers().setsOrderRef();
|
||||||
|
const auto removeIndex = orderRef.indexOf(setId);
|
||||||
|
if (removeIndex >= 0) {
|
||||||
|
orderRef.removeAt(removeIndex);
|
||||||
|
}
|
||||||
|
if (set->flags & SetFlag::Masks) {
|
||||||
|
session->local().writeInstalledMasks();
|
||||||
|
} else {
|
||||||
|
session->local().writeInstalledStickers();
|
||||||
|
}
|
||||||
|
if (writeRecent) {
|
||||||
|
session->saveSettings();
|
||||||
|
}
|
||||||
|
session->data().stickers().notifyUpdated();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.cancelled = [=](Fn<void()> &&close) {
|
||||||
|
close();
|
||||||
|
},
|
||||||
|
.confirmText = tr::lng_stickers_remove_pack_confirm(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ChatHelpers
|
} // namespace ChatHelpers
|
||||||
|
|
|
@ -55,11 +55,8 @@ public:
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
bool masks = false);
|
bool masks = false);
|
||||||
|
|
||||||
Main::Session &session() const;
|
|
||||||
|
|
||||||
rpl::producer<TabbedSelector::FileChosen> chosen() const;
|
rpl::producer<TabbedSelector::FileChosen> chosen() const;
|
||||||
rpl::producer<> scrollUpdated() const;
|
rpl::producer<> scrollUpdated() const;
|
||||||
rpl::producer<> checkForHide() const;
|
|
||||||
rpl::producer<TabbedSelector::Action> choosingUpdated() const;
|
rpl::producer<TabbedSelector::Action> choosingUpdated() const;
|
||||||
|
|
||||||
void refreshRecent() override;
|
void refreshRecent() override;
|
||||||
|
@ -76,7 +73,6 @@ public:
|
||||||
void refreshStickers();
|
void refreshStickers();
|
||||||
|
|
||||||
std::vector<StickerIcon> fillIcons();
|
std::vector<StickerIcon> fillIcons();
|
||||||
bool preventAutoHide();
|
|
||||||
|
|
||||||
uint64 currentSet(int yOffset) const;
|
uint64 currentSet(int yOffset) const;
|
||||||
|
|
||||||
|
@ -205,7 +201,6 @@ private:
|
||||||
|
|
||||||
void setSection(Section section);
|
void setSection(Section section);
|
||||||
void displaySet(uint64 setId);
|
void displaySet(uint64 setId);
|
||||||
void checkHideWithBox(QPointer<Ui::BoxContent> box);
|
|
||||||
void installSet(uint64 setId);
|
void installSet(uint64 setId);
|
||||||
void removeMegagroupSet(bool locally);
|
void removeMegagroupSet(bool locally);
|
||||||
void removeSet(uint64 setId);
|
void removeSet(uint64 setId);
|
||||||
|
@ -367,7 +362,6 @@ private:
|
||||||
base::Timer _updateSetsTimer;
|
base::Timer _updateSetsTimer;
|
||||||
base::flat_set<uint64> _repaintSetsIds;
|
base::flat_set<uint64> _repaintSetsIds;
|
||||||
|
|
||||||
bool _displayingSet = false;
|
|
||||||
uint64 _removingSetId = 0;
|
uint64 _removingSetId = 0;
|
||||||
|
|
||||||
Footer *_footer = nullptr;
|
Footer *_footer = nullptr;
|
||||||
|
@ -405,9 +399,12 @@ private:
|
||||||
|
|
||||||
rpl::event_stream<TabbedSelector::FileChosen> _chosen;
|
rpl::event_stream<TabbedSelector::FileChosen> _chosen;
|
||||||
rpl::event_stream<> _scrollUpdated;
|
rpl::event_stream<> _scrollUpdated;
|
||||||
rpl::event_stream<> _checkForHide;
|
|
||||||
rpl::event_stream<TabbedSelector::Action> _choosingUpdated;
|
rpl::event_stream<TabbedSelector::Action> _choosingUpdated;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
uint64 setId);
|
||||||
|
|
||||||
} // namespace ChatHelpers
|
} // namespace ChatHelpers
|
||||||
|
|
|
@ -280,8 +280,9 @@ void TabbedPanel::opacityAnimationCallback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabbedPanel::hideByTimerOrLeave() {
|
void TabbedPanel::hideByTimerOrLeave() {
|
||||||
if (isHidden() || preventAutoHide()) return;
|
if (isHidden() || preventAutoHide()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
hideAnimated();
|
hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/widgets/discrete_sliders.h"
|
#include "ui/widgets/discrete_sliders.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
#include "ui/layers/box_content.h"
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
#include "ui/cached_round_corners.h"
|
#include "ui/cached_round_corners.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
@ -509,7 +510,8 @@ rpl::producer<> TabbedSelector::checkForHide() const {
|
||||||
auto never = rpl::never<>();
|
auto never = rpl::never<>();
|
||||||
return rpl::merge(
|
return rpl::merge(
|
||||||
hasStickersTab() ? stickers()->checkForHide() : never,
|
hasStickersTab() ? stickers()->checkForHide() : never,
|
||||||
hasMasksTab() ? masks()->checkForHide() : never);
|
hasMasksTab() ? masks()->checkForHide() : never,
|
||||||
|
hasEmojiTab() ? emoji()->checkForHide() : never);
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<> TabbedSelector::slideFinished() const {
|
rpl::producer<> TabbedSelector::slideFinished() const {
|
||||||
|
@ -723,8 +725,9 @@ void TabbedSelector::refreshStickers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TabbedSelector::preventAutoHide() const {
|
bool TabbedSelector::preventAutoHide() const {
|
||||||
return (hasStickersTab() ? stickers()->preventAutoHide() : false)
|
return (hasStickersTab() && stickers()->preventAutoHide())
|
||||||
|| (hasMasksTab() ? masks()->preventAutoHide() : false)
|
|| (hasMasksTab() && masks()->preventAutoHide())
|
||||||
|
|| (hasEmojiTab() && emoji()->preventAutoHide())
|
||||||
|| hasMenu();
|
|| hasMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,6 +1136,10 @@ TabbedSelector::Inner::Inner(
|
||||||
, _controller(controller) {
|
, _controller(controller) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Main::Session &TabbedSelector::Inner::session() const {
|
||||||
|
return controller()->session();
|
||||||
|
}
|
||||||
|
|
||||||
rpl::producer<int> TabbedSelector::Inner::scrollToRequests() const {
|
rpl::producer<int> TabbedSelector::Inner::scrollToRequests() const {
|
||||||
return _scrollToRequests.events();
|
return _scrollToRequests.events();
|
||||||
}
|
}
|
||||||
|
@ -1149,6 +1156,17 @@ void TabbedSelector::Inner::disableScroll(bool disabled) {
|
||||||
_disableScrollRequests.fire_copy(disabled);
|
_disableScrollRequests.fire_copy(disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabbedSelector::Inner::checkHideWithBox(QPointer<Ui::BoxContent> box) {
|
||||||
|
if (!box) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_preventHideWithBox = true;
|
||||||
|
connect(box, &QObject::destroyed, this, [=] {
|
||||||
|
_preventHideWithBox = false;
|
||||||
|
_checkForHide.fire({});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void TabbedSelector::Inner::visibleTopBottomUpdated(
|
void TabbedSelector::Inner::visibleTopBottomUpdated(
|
||||||
int visibleTop,
|
int visibleTop,
|
||||||
int visibleBottom) {
|
int visibleBottom) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ class PopupMenu;
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
class SettingsSlider;
|
class SettingsSlider;
|
||||||
class FlatLabel;
|
class FlatLabel;
|
||||||
|
class BoxContent;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
@ -259,18 +260,26 @@ class TabbedSelector::Inner : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
Inner(QWidget *parent, not_null<Window::SessionController*> controller);
|
Inner(QWidget *parent, not_null<Window::SessionController*> controller);
|
||||||
|
|
||||||
not_null<Window::SessionController*> controller() const {
|
[[nodiscard]] not_null<Window::SessionController*> controller() const {
|
||||||
return _controller;
|
return _controller;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
|
||||||
int getVisibleTop() const {
|
[[nodiscard]] int getVisibleTop() const {
|
||||||
return _visibleTop;
|
return _visibleTop;
|
||||||
}
|
}
|
||||||
int getVisibleBottom() const {
|
[[nodiscard]] int getVisibleBottom() const {
|
||||||
return _visibleBottom;
|
return _visibleBottom;
|
||||||
}
|
}
|
||||||
void setMinimalHeight(int newWidth, int newMinimalHeight);
|
void setMinimalHeight(int newWidth, int newMinimalHeight);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<> checkForHide() const {
|
||||||
|
return _checkForHide.events();
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool preventAutoHide() const {
|
||||||
|
return _preventHideWithBox;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void refreshRecent() = 0;
|
virtual void refreshRecent() = 0;
|
||||||
virtual void preloadImages() {
|
virtual void preloadImages() {
|
||||||
}
|
}
|
||||||
|
@ -309,6 +318,8 @@ protected:
|
||||||
void scrollTo(int y);
|
void scrollTo(int y);
|
||||||
void disableScroll(bool disabled);
|
void disableScroll(bool disabled);
|
||||||
|
|
||||||
|
void checkHideWithBox(QPointer<Ui::BoxContent> box);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
not_null<Window::SessionController*> _controller;
|
not_null<Window::SessionController*> _controller;
|
||||||
|
|
||||||
|
@ -318,6 +329,9 @@ private:
|
||||||
|
|
||||||
rpl::event_stream<int> _scrollToRequests;
|
rpl::event_stream<int> _scrollToRequests;
|
||||||
rpl::event_stream<bool> _disableScrollRequests;
|
rpl::event_stream<bool> _disableScrollRequests;
|
||||||
|
rpl::event_stream<> _checkForHide;
|
||||||
|
|
||||||
|
bool _preventHideWithBox = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue