mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 14:50:24 +00:00
Allow viewing emoji sets used in a message.
This commit is contained in:
parent
fce4452af5
commit
bb7249f280
@ -1821,7 +1821,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_stickers_count#other" = "{count} stickers";
|
||||
"lng_masks_count#one" = "{count} mask";
|
||||
"lng_masks_count#other" = "{count} masks";
|
||||
"lng_custom_emoji_count#one" = "{count} emoji";
|
||||
"lng_custom_emoji_count#other" = "{count} emoji";
|
||||
"lng_stickers_attached_sets" = "Sets of attached stickers";
|
||||
"lng_custom_emoji_used_sets" = "Sets of used emoji";
|
||||
"lng_stickers_group_set" = "Group sticker set";
|
||||
"lng_stickers_remove_group_set" = "Remove group sticker set?";
|
||||
"lng_stickers_group_from_your" = "Choose from your stickers";
|
||||
@ -2147,8 +2150,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_delete_all_files" = "Delete all files";
|
||||
"lng_context_save_custom_sound" = "Save for notifications";
|
||||
|
||||
"lng_context_animated_emoji" = "This message contains emoji from {name} pack.";
|
||||
"lng_context_animated_emoji_many" = "This message contains emoji from {name} packs.";
|
||||
"lng_context_animated_emoji" = "This message contains emoji from **{name} pack**.";
|
||||
"lng_context_animated_emoji_many#one" = "This message contains emoji from **{count} pack**.";
|
||||
"lng_context_animated_emoji_many#other" = "This message contains emoji from **{count} packs**.";
|
||||
|
||||
"lng_downloads_section" = "Downloads";
|
||||
"lng_downloads_view_in_chat" = "View in chat";
|
||||
|
@ -152,6 +152,7 @@ private:
|
||||
|
||||
bool isRecentSet() const;
|
||||
bool isMasksSet() const;
|
||||
bool isEmojiSet() const;
|
||||
bool isWebm() const;
|
||||
bool isInstalled() const;
|
||||
bool isUnread() const;
|
||||
@ -419,32 +420,56 @@ StickersBox::StickersBox(
|
||||
, _section(Section::Attached)
|
||||
, _isMasks(false)
|
||||
, _attached(0, this, controller, Section::Attached)
|
||||
, _attachedType(Data::StickersType::Stickers)
|
||||
, _attachedSets(attachedSets) {
|
||||
}
|
||||
|
||||
StickersBox::StickersBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const std::vector<StickerSetIdentifier> &emojiSets)
|
||||
: _controller(controller)
|
||||
, _api(&controller->session().mtp())
|
||||
, _section(Section::Attached)
|
||||
, _isMasks(false)
|
||||
, _attached(0, this, controller, Section::Attached)
|
||||
, _attachedType(Data::StickersType::Emoji)
|
||||
, _emojiSets(emojiSets) {
|
||||
}
|
||||
|
||||
Main::Session &StickersBox::session() const {
|
||||
return _controller->session();
|
||||
}
|
||||
|
||||
void StickersBox::showAttachedStickers() {
|
||||
const auto stickers = &session().data().stickers();
|
||||
|
||||
auto addedSet = false;
|
||||
const auto add = [&](not_null<StickersSet*> set) {
|
||||
if (_attached.widget()->appendSet(set)) {
|
||||
addedSet = true;
|
||||
if (set->stickers.isEmpty()
|
||||
|| (set->flags & SetFlag::NotLoaded)) {
|
||||
session().api().scheduleStickerSetRequest(
|
||||
set->id,
|
||||
set->accessHash);
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const auto &stickerSet : _attachedSets.v) {
|
||||
const auto setData = stickerSet.match([&](const auto &data) {
|
||||
return data.vset().match([&](const MTPDstickerSet &data) {
|
||||
return &data;
|
||||
});
|
||||
});
|
||||
|
||||
if (const auto set = session().data().stickers().feedSet(*setData)) {
|
||||
if (_attached.widget()->appendSet(set)) {
|
||||
addedSet = true;
|
||||
if (set->stickers.isEmpty()
|
||||
|| (set->flags & SetFlag::NotLoaded)) {
|
||||
session().api().scheduleStickerSetRequest(
|
||||
set->id,
|
||||
set->accessHash);
|
||||
}
|
||||
}
|
||||
if (const auto set = stickers->feedSet(*setData)) {
|
||||
add(set);
|
||||
}
|
||||
}
|
||||
for (const auto &setId : _emojiSets) {
|
||||
const auto i = stickers->sets().find(setId.id);
|
||||
if (i != end(stickers->sets())) {
|
||||
add(i->second.get());
|
||||
}
|
||||
}
|
||||
if (addedSet) {
|
||||
@ -547,7 +572,9 @@ void StickersBox::prepare() {
|
||||
} else if (_section == Section::Archived) {
|
||||
requestArchivedSets();
|
||||
} else if (_section == Section::Attached) {
|
||||
setTitle(tr::lng_stickers_attached_sets());
|
||||
setTitle(_attachedType == Data::StickersType::Emoji
|
||||
? tr::lng_custom_emoji_used_sets()
|
||||
: tr::lng_stickers_attached_sets());
|
||||
}
|
||||
if (_tabs) {
|
||||
if (archivedSetsOrder().isEmpty()) {
|
||||
@ -1063,6 +1090,10 @@ bool StickersBox::Inner::Row::isMasksSet() const {
|
||||
return (set->flags & SetFlag::Masks);
|
||||
}
|
||||
|
||||
bool StickersBox::Inner::Row::isEmojiSet() const {
|
||||
return (set->flags & SetFlag::Emoji);
|
||||
}
|
||||
|
||||
bool StickersBox::Inner::Row::isWebm() const {
|
||||
return (set->flags & SetFlag::Webm);
|
||||
}
|
||||
@ -1331,6 +1362,8 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
|
||||
|
||||
const auto statusText = (row->count == 0)
|
||||
? tr::lng_contacts_loading(tr::now)
|
||||
: row->isEmojiSet()
|
||||
? tr::lng_custom_emoji_count(tr::now, lt_count, row->count)
|
||||
: row->isMasksSet()
|
||||
? tr::lng_masks_count(tr::now, lt_count, row->count)
|
||||
: tr::lng_stickers_count(tr::now, lt_count, row->count);
|
||||
|
@ -37,6 +37,7 @@ class Session;
|
||||
|
||||
namespace Data {
|
||||
class DocumentMedia;
|
||||
enum class StickersType : uchar;
|
||||
} // namespace Data
|
||||
|
||||
namespace Lottie {
|
||||
@ -70,6 +71,10 @@ public:
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const MTPVector<MTPStickerSetCovered> &attachedSets);
|
||||
StickersBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const std::vector<StickerSetIdentifier> &emojiSets);
|
||||
~StickersBox();
|
||||
|
||||
[[nodiscard]] Main::Session &session() const;
|
||||
@ -157,7 +162,9 @@ private:
|
||||
Tab _attached;
|
||||
Tab *_tab = nullptr;
|
||||
|
||||
const Data::StickersType _attachedType = {};
|
||||
const MTPVector<MTPStickerSetCovered> _attachedSets;
|
||||
const std::vector<StickerSetIdentifier> _emojiSets;
|
||||
|
||||
ChannelData *_megagroupSet = nullptr;
|
||||
|
||||
|
@ -415,6 +415,12 @@ std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||
return result;
|
||||
}
|
||||
|
||||
QString CustomEmojiManager::lookupSetName(uint64 setId) {
|
||||
const auto &sets = _owner->stickers().sets();
|
||||
const auto i = sets.find(setId);
|
||||
return (i != end(sets)) ? i->second->title : QString();
|
||||
}
|
||||
|
||||
void CustomEmojiManager::request() {
|
||||
auto ids = QVector<MTPlong>();
|
||||
ids.reserve(std::min(kMaxPerRequest, int(_pendingForRequest.size())));
|
||||
@ -440,6 +446,7 @@ void CustomEmojiManager::request() {
|
||||
}
|
||||
}
|
||||
}
|
||||
requestSetFor(document);
|
||||
}
|
||||
requestFinished();
|
||||
}).fail([=] {
|
||||
@ -448,6 +455,30 @@ void CustomEmojiManager::request() {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void CustomEmojiManager::requestSetFor(not_null<DocumentData*> document) {
|
||||
const auto sticker = document->sticker();
|
||||
if (!sticker || !sticker->set.id) {
|
||||
return;
|
||||
}
|
||||
const auto &sets = document->owner().stickers().sets();
|
||||
const auto i = sets.find(sticker->set.id);
|
||||
if (i != end(sets)) {
|
||||
return;
|
||||
}
|
||||
const auto session = &document->session();
|
||||
session->api().scheduleStickerSetRequest(
|
||||
sticker->set.id,
|
||||
sticker->set.accessHash);
|
||||
if (_requestSetsScheduled) {
|
||||
return;
|
||||
}
|
||||
_requestSetsScheduled = true;
|
||||
crl::on_main(this, [=] {
|
||||
_requestSetsScheduled = false;
|
||||
session->api().requestStickerSets();
|
||||
});
|
||||
}
|
||||
|
||||
void CustomEmojiManager::requestFinished() {
|
||||
_requestId = 0;
|
||||
if (!_pendingForRequest.empty()) {
|
||||
|
@ -49,6 +49,8 @@ public:
|
||||
DocumentId documentId,
|
||||
SizeTag tag);
|
||||
|
||||
[[nodiscard]] QString lookupSetName(uint64 setId);
|
||||
|
||||
[[nodiscard]] Main::Session &session() const;
|
||||
[[nodiscard]] Session &owner() const;
|
||||
|
||||
@ -65,6 +67,7 @@ private:
|
||||
Ui::CustomEmoji::RepaintRequest request);
|
||||
void scheduleRepaintTimer();
|
||||
void invokeRepaints();
|
||||
void requestSetFor(not_null<DocumentData*> document);
|
||||
|
||||
const not_null<Session*> _owner;
|
||||
|
||||
@ -81,6 +84,7 @@ private:
|
||||
crl::time _repaintNext = 0;
|
||||
base::Timer _repaintTimer;
|
||||
bool _repaintTimerScheduled = false;
|
||||
bool _requestSetsScheduled = false;
|
||||
|
||||
};
|
||||
|
||||
|
@ -1410,13 +1410,18 @@ StickersSet *Stickers::feedSetFull(const MTPDmessages_stickerSet &d) {
|
||||
}
|
||||
}
|
||||
|
||||
const auto isEmoji = !!(set->flags & SetFlag::Emoji);
|
||||
const auto isMasks = !!(set->flags & SetFlag::Masks);
|
||||
if (pack.isEmpty()) {
|
||||
const auto removeIndex = (isMasks
|
||||
const auto removeIndex = (isEmoji
|
||||
? emojiSetsOrder()
|
||||
: isMasks
|
||||
? maskSetsOrder()
|
||||
: setsOrder()).indexOf(set->id);
|
||||
if (removeIndex >= 0) {
|
||||
(isMasks
|
||||
(isEmoji
|
||||
? emojiSetsOrderRef()
|
||||
: isMasks
|
||||
? maskSetsOrderRef()
|
||||
: setsOrderRef()).removeAt(removeIndex);
|
||||
}
|
||||
@ -1453,10 +1458,12 @@ StickersSet *Stickers::feedSetFull(const MTPDmessages_stickerSet &d) {
|
||||
|
||||
if (set) {
|
||||
const auto isArchived = !!(set->flags & SetFlag::Archived);
|
||||
if (isMasks) {
|
||||
session().local().writeInstalledMasks();
|
||||
} else if (set->flags & SetFlag::Installed) {
|
||||
if (!isArchived) {
|
||||
if ((set->flags & SetFlag::Installed) && !isArchived) {
|
||||
if (isEmoji) {
|
||||
session().local().writeInstalledCustomEmoji();
|
||||
} else if (isMasks) {
|
||||
session().local().writeInstalledMasks();
|
||||
} else {
|
||||
session().local().writeInstalledStickers();
|
||||
}
|
||||
}
|
||||
@ -1464,7 +1471,9 @@ StickersSet *Stickers::feedSetFull(const MTPDmessages_stickerSet &d) {
|
||||
session().local().writeFeaturedStickers();
|
||||
}
|
||||
if (wasArchived != isArchived) {
|
||||
if (isMasks) {
|
||||
if (isEmoji) {
|
||||
|
||||
} else if (isMasks) {
|
||||
session().local().writeArchivedMasks();
|
||||
} else {
|
||||
session().local().writeArchivedStickers();
|
||||
|
@ -2412,6 +2412,16 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
}
|
||||
}
|
||||
|
||||
auto emojiPackIds = _dragStateItem
|
||||
? HistoryView::CollectEmojiPacks(_dragStateItem)
|
||||
: std::vector<StickerSetIdentifier>();
|
||||
if (!emojiPackIds.empty()) {
|
||||
HistoryView::AddEmojiPacksAction(
|
||||
_menu,
|
||||
this,
|
||||
std::move(emojiPackIds),
|
||||
_controller);
|
||||
}
|
||||
if (hasWhoReactedItem) {
|
||||
HistoryView::AddWhoReactedAction(
|
||||
_menu,
|
||||
|
@ -26,8 +26,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/media/history_view_web_page.h"
|
||||
#include "history/view/reactions/message_reactions_list.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/menu/menu_item_base.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/controls/delete_message_context_action.h"
|
||||
#include "ui/controls/who_reacted_context_action.h"
|
||||
#include "ui/boxes/report_box.h"
|
||||
@ -37,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/delete_messages_box.h"
|
||||
#include "boxes/report_messages_box.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_document.h"
|
||||
@ -48,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
@ -1210,4 +1214,121 @@ void ShowWhoReactedMenu(
|
||||
}, lifetime);
|
||||
}
|
||||
|
||||
std::vector<StickerSetIdentifier> CollectEmojiPacks(
|
||||
not_null<HistoryItem*> item) {
|
||||
auto result = std::vector<StickerSetIdentifier>();
|
||||
const auto owner = &item->history()->owner();
|
||||
for (const auto &entity : item->originalText().entities) {
|
||||
if (entity.type() == EntityType::CustomEmoji) {
|
||||
const auto data = Data::ParseCustomEmojiData(entity.data());
|
||||
if (const auto set = owner->document(data.id)->sticker()) {
|
||||
if (set->set.id
|
||||
&& !ranges::contains(
|
||||
result,
|
||||
set->set.id,
|
||||
&StickerSetIdentifier::id)) {
|
||||
result.push_back(set->set);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void AddEmojiPacksAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<QWidget*> context,
|
||||
std::vector<StickerSetIdentifier> packIds,
|
||||
not_null<Window::SessionController*> controller) {
|
||||
class Item final : public Ui::Menu::ItemBase {
|
||||
public:
|
||||
Item(
|
||||
not_null<RpWidget*> parent,
|
||||
const style::Menu &st,
|
||||
TextWithEntities &&about)
|
||||
: Ui::Menu::ItemBase(parent, st)
|
||||
, _st(st)
|
||||
, _text(base::make_unique_q<Ui::FlatLabel>(
|
||||
this,
|
||||
rpl::single(std::move(about)),
|
||||
st::historyHasCustomEmoji))
|
||||
, _dummyAction(new QAction(parent)) {
|
||||
enableMouseSelecting();
|
||||
_text->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
parent->widthValue() | rpl::start_with_next([=](int width) {
|
||||
const auto top = st::historyHasCustomEmojiPosition.y();
|
||||
const auto skip = st::historyHasCustomEmojiPosition.x();
|
||||
_text->resizeToWidth(width - 2 * skip);
|
||||
_text->moveToLeft(skip, top);
|
||||
resize(width, contentHeight());
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
not_null<QAction*> action() const override {
|
||||
return _dummyAction;
|
||||
}
|
||||
|
||||
bool isEnabled() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
int contentHeight() const override {
|
||||
const auto skip = st::historyHasCustomEmojiPosition.y();
|
||||
return skip + _text->height() + skip;
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent *e) override {
|
||||
auto p = QPainter(this);
|
||||
const auto selected = isSelected();
|
||||
p.fillRect(rect(), selected ? _st.itemBgOver : _st.itemBg);
|
||||
RippleButton::paintRipple(p, 0, 0);
|
||||
}
|
||||
|
||||
const style::Menu &_st;
|
||||
const base::unique_qptr<Ui::FlatLabel> _text;
|
||||
const not_null<QAction*> _dummyAction;
|
||||
|
||||
};
|
||||
|
||||
const auto count = int(packIds.size());
|
||||
const auto manager = &controller->session().data().customEmojiManager();
|
||||
const auto name = (count == 1)
|
||||
? TextWithEntities{ manager->lookupSetName(packIds[0].id) }
|
||||
: TextWithEntities();
|
||||
if (!menu->empty()) {
|
||||
menu->addSeparator();
|
||||
}
|
||||
auto button = base::make_unique_q<Item>(
|
||||
menu,
|
||||
menu->st().menu,
|
||||
(name.text.isEmpty()
|
||||
? tr::lng_context_animated_emoji_many(
|
||||
tr::now,
|
||||
lt_count,
|
||||
count,
|
||||
Ui::Text::RichLangValue)
|
||||
: tr::lng_context_animated_emoji(
|
||||
tr::now,
|
||||
lt_name,
|
||||
TextWithEntities{ name },
|
||||
Ui::Text::RichLangValue)));
|
||||
const auto weak = base::make_weak(controller.get());
|
||||
button->setClickedCallback([=] {
|
||||
const auto strong = weak.get();
|
||||
if (!strong) {
|
||||
return;
|
||||
} else if (packIds.size() > 1) {
|
||||
strong->show(Box<StickersBox>(strong, packIds));
|
||||
return;
|
||||
}
|
||||
// Single used emoji pack.
|
||||
strong->show(
|
||||
Box<StickerSetBox>(strong, packIds.front()),
|
||||
Ui::LayerOption::KeepOther);
|
||||
|
||||
});
|
||||
menu->addAction(std::move(button));
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
@ -79,4 +79,12 @@ void ShowWhoReactedMenu(
|
||||
not_null<Window::SessionController*> controller,
|
||||
rpl::lifetime &lifetime);
|
||||
|
||||
[[nodiscard]] std::vector<StickerSetIdentifier> CollectEmojiPacks(
|
||||
not_null<HistoryItem*> item);
|
||||
void AddEmojiPacksAction(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<QWidget*> context,
|
||||
std::vector<StickerSetIdentifier> packIds,
|
||||
not_null<Window::SessionController*> controller);
|
||||
|
||||
} // namespace HistoryView
|
||||
|
@ -2128,7 +2128,14 @@ void Account::writeInstalledCustomEmoji() {
|
||||
using SetFlag = Data::StickersSetFlag;
|
||||
|
||||
writeStickerSets(_installedCustomEmojiKey, [](const Data::StickersSet &set) {
|
||||
if (!(set.flags & SetFlag::Emoji) || set.stickers.isEmpty()) {
|
||||
if (!(set.flags & SetFlag::Emoji)) {
|
||||
return StickerSetCheckResult::Skip;
|
||||
} else if (set.flags & SetFlag::NotLoaded) {
|
||||
// waiting to receive
|
||||
return StickerSetCheckResult::Abort;
|
||||
} else if (!(set.flags & SetFlag::Installed)
|
||||
|| (set.flags & SetFlag::Archived)
|
||||
|| set.stickers.isEmpty()) {
|
||||
return StickerSetCheckResult::Skip;
|
||||
}
|
||||
return StickerSetCheckResult::Write;
|
||||
|
@ -1087,3 +1087,13 @@ msgServiceGiftBoxButtonPadding: margins(0px, 17px, 0px, 17px);
|
||||
msgServiceGiftBoxTitlePadding: margins(0px, 126px, 0px, 2px);
|
||||
msgServiceGiftBoxStickerTop: -30px;
|
||||
msgServiceGiftBoxStickerSize: size(150px, 150px);
|
||||
|
||||
historyHasCustomEmoji: FlatLabel(defaultFlatLabel) {
|
||||
style: TextStyle(defaultTextStyle) {
|
||||
font: font(12px);
|
||||
linkFont: font(12px underline);
|
||||
linkFontOver: font(12px underline);
|
||||
}
|
||||
minWidth: 80px;
|
||||
}
|
||||
historyHasCustomEmojiPosition: point(12px, 4px);
|
||||
|
Loading…
Reference in New Issue
Block a user