mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Add recent emoji context menu.
This commit is contained in:
parent
58d762f130
commit
23dbe4742a
7 changed files with 180 additions and 25 deletions
|
@ -1813,6 +1813,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_emoji_set_download" = "Download {size}";
|
||||
"lng_emoji_set_loading" = "{percent}, {progress}";
|
||||
"lng_emoji_color_all" = "Choose color for all emoji";
|
||||
"lng_emoji_copy" = "Copy emoji";
|
||||
"lng_emoji_view_pack" = "View pack";
|
||||
"lng_emoji_remove_recent" = "Remove from recents";
|
||||
"lng_emoji_reset_recent" = "Reset recents";
|
||||
"lng_emoji_reset_recent_sure" = "Do you want to reset recent emoji?";
|
||||
"lng_emoji_reset_recent_button" = "Reset";
|
||||
|
||||
"lng_recent_stickers" = "Frequently used";
|
||||
"lng_faved_stickers_add" = "Add to Favorites";
|
||||
|
|
|
@ -689,8 +689,6 @@ public:
|
|||
style::margins margins = {});
|
||||
|
||||
private:
|
||||
void subscribeToCustomDeviceModel();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
rpl::event_stream<uint64> _terminateRequests;
|
||||
|
@ -1054,18 +1052,6 @@ Main::Session &SessionsContent::ListController::session() const {
|
|||
return *_session;
|
||||
}
|
||||
|
||||
void SessionsContent::ListController::subscribeToCustomDeviceModel() {
|
||||
Core::App().settings().deviceModelChanges(
|
||||
) | rpl::start_with_next([=](const QString &model) {
|
||||
for (auto i = 0; i != delegate()->peerListFullRowsCount(); ++i) {
|
||||
const auto row = delegate()->peerListRowAt(i);
|
||||
if (!row->id()) {
|
||||
static_cast<Row*>(row.get())->updateName(model);
|
||||
}
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void SessionsContent::ListController::prepare() {
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/emoji_list_widget.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/controls/tabbed_search.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/widgets/menu/menu_add_action_callback.h"
|
||||
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
|
@ -41,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "settings/settings_premium.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
|
||||
namespace ChatHelpers {
|
||||
namespace {
|
||||
|
@ -1035,7 +1039,7 @@ void EmojiListWidget::fillRecentFrom(const std::vector<DocumentId> &list) {
|
|||
|
||||
base::unique_qptr<Ui::PopupMenu> EmojiListWidget::fillContextMenu(
|
||||
SendMenu::Type type) {
|
||||
if (_mode != Mode::EmojiStatus || v::is_null(_selected)) {
|
||||
if (v::is_null(_selected)) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto over = std::get_if<OverEmoji>(&_selected);
|
||||
|
@ -1044,13 +1048,99 @@ base::unique_qptr<Ui::PopupMenu> EmojiListWidget::fillContextMenu(
|
|||
}
|
||||
const auto section = over->section;
|
||||
const auto index = over->index;
|
||||
const auto chosen = lookupCustomEmoji(index, section);
|
||||
if (!chosen) {
|
||||
return nullptr;
|
||||
}
|
||||
auto menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
this,
|
||||
st::defaultPopupMenu);
|
||||
(_mode == Mode::Full
|
||||
? st::popupMenuWithIcons
|
||||
: st::defaultPopupMenu));
|
||||
if (_mode == Mode::Full) {
|
||||
fillRecentMenu(menu, section, index);
|
||||
} else if (_mode == Mode::EmojiStatus) {
|
||||
fillEmojiStatusMenu(menu, section, index);
|
||||
}
|
||||
if (menu->empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
void EmojiListWidget::fillRecentMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
int section,
|
||||
int index) {
|
||||
if (section != int(Section::Recent)) {
|
||||
return;
|
||||
}
|
||||
const auto addAction = Ui::Menu::CreateAddActionCallback(menu);
|
||||
const auto over = OverEmoji{ section, index };
|
||||
const auto emoji = lookupOverEmoji(&over);
|
||||
const auto custom = lookupCustomEmoji(index, section);
|
||||
if (custom && custom->sticker()) {
|
||||
const auto sticker = custom->sticker();
|
||||
const auto emoji = sticker->alt;
|
||||
const auto setId = sticker->set.id;
|
||||
if (!emoji.isEmpty()) {
|
||||
auto data = TextForMimeData{ emoji, { emoji } };
|
||||
data.rich.entities.push_back({
|
||||
EntityType::CustomEmoji,
|
||||
0,
|
||||
emoji.size(),
|
||||
Data::SerializeCustomEmojiId(custom)
|
||||
});
|
||||
addAction(tr::lng_emoji_copy(tr::now), [=] {
|
||||
TextUtilities::SetClipboardText(data);
|
||||
}, &st::menuIconCopy);
|
||||
}
|
||||
if (setId && _features.openStickerSets) {
|
||||
addAction(
|
||||
tr::lng_emoji_view_pack(tr::now),
|
||||
crl::guard(this, [=] { displaySet(setId); }),
|
||||
&st::menuIconShowAll);
|
||||
}
|
||||
}
|
||||
auto id = RecentEmojiId{ emoji };
|
||||
if (custom) {
|
||||
id.data = RecentEmojiDocument{
|
||||
.id = custom->id,
|
||||
.test = custom->session().isTestMode(),
|
||||
};
|
||||
}
|
||||
addAction(tr::lng_emoji_remove_recent(tr::now), crl::guard(this, [=] {
|
||||
Core::App().settings().hideRecentEmoji(id);
|
||||
refreshRecent();
|
||||
}), &st::menuIconCancel);
|
||||
|
||||
menu->addSeparator(&st().expandedSeparator);
|
||||
|
||||
const auto resetRecent = [=] {
|
||||
const auto sure = [=](Fn<void()> &&close) {
|
||||
Core::App().settings().resetRecentEmoji();
|
||||
refreshRecent();
|
||||
close();
|
||||
};
|
||||
checkHideWithBox(Ui::MakeConfirmBox({
|
||||
.text = tr::lng_emoji_reset_recent_sure(),
|
||||
.confirmed = crl::guard(this, sure),
|
||||
.confirmText = tr::lng_emoji_reset_recent_button(tr::now),
|
||||
.labelStyle = &st().boxLabel,
|
||||
}));
|
||||
};
|
||||
addAction({
|
||||
.text = tr::lng_emoji_reset_recent(tr::now),
|
||||
.handler = crl::guard(this, resetRecent),
|
||||
.icon = &st::menuIconRestoreAttention,
|
||||
.isAttention = true,
|
||||
});
|
||||
}
|
||||
|
||||
void EmojiListWidget::fillEmojiStatusMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
int section,
|
||||
int index) {
|
||||
const auto chosen = lookupCustomEmoji(index, section);
|
||||
if (!chosen) {
|
||||
return;
|
||||
}
|
||||
const auto selectWith = [=](TimeId scheduled) {
|
||||
selectCustom(
|
||||
lookupChosen(chosen, nullptr, { .scheduled = scheduled }));
|
||||
|
@ -1068,7 +1158,6 @@ base::unique_qptr<Ui::PopupMenu> EmojiListWidget::fillContextMenu(
|
|||
tr::lng_manage_messages_ttl_after_custom(tr::now),
|
||||
crl::guard(this, [=] { selectWith(
|
||||
TabbedSelector::kPickCustomTimeId); }));
|
||||
return menu;
|
||||
}
|
||||
|
||||
void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||
|
@ -1884,6 +1973,7 @@ void EmojiListWidget::refreshRecent() {
|
|||
clearSelection();
|
||||
fillRecent();
|
||||
resizeToWidth(width());
|
||||
update();
|
||||
}
|
||||
|
||||
void EmojiListWidget::refreshCustom() {
|
||||
|
|
|
@ -266,6 +266,15 @@ private:
|
|||
void setSelected(OverState newSelected);
|
||||
void setPressed(OverState newPressed);
|
||||
|
||||
void fillRecentMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
int section,
|
||||
int index);
|
||||
void fillEmojiStatusMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
int section,
|
||||
int index);
|
||||
|
||||
[[nodiscard]] EmojiPtr lookupOverEmoji(const OverEmoji *over) const;
|
||||
[[nodiscard]] DocumentData *lookupCustomEmoji(
|
||||
int index,
|
||||
|
|
|
@ -201,7 +201,10 @@ QByteArray Settings::serialize() const {
|
|||
+ Serialize::bytearraySize(mediaViewPosition)
|
||||
+ sizeof(qint32)
|
||||
+ sizeof(quint64)
|
||||
+ sizeof(qint32);
|
||||
+ sizeof(qint32) * 2;
|
||||
for (const auto &id : _recentEmojiSkip) {
|
||||
size += Serialize::stringSize(id);
|
||||
}
|
||||
|
||||
auto result = QByteArray();
|
||||
result.reserve(size);
|
||||
|
@ -336,7 +339,11 @@ QByteArray Settings::serialize() const {
|
|||
<< mediaViewPosition
|
||||
<< qint32(_ignoreBatterySaving.current() ? 1 : 0)
|
||||
<< quint64(_macRoundIconDigest.value_or(0))
|
||||
<< qint32(_storiesClickTooltipHidden.current() ? 1 : 0);
|
||||
<< qint32(_storiesClickTooltipHidden.current() ? 1 : 0)
|
||||
<< qint32(_recentEmojiSkip.size());
|
||||
for (const auto &id : _recentEmojiSkip) {
|
||||
stream << id;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -443,6 +450,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
|||
qint32 ignoreBatterySaving = _ignoreBatterySaving.current() ? 1 : 0;
|
||||
quint64 macRoundIconDigest = _macRoundIconDigest.value_or(0);
|
||||
qint32 storiesClickTooltipHidden = _storiesClickTooltipHidden.current() ? 1 : 0;
|
||||
base::flat_set<QString> recentEmojiSkip;
|
||||
|
||||
stream >> themesAccentColors;
|
||||
if (!stream.atEnd()) {
|
||||
|
@ -680,6 +688,19 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
|||
if (!stream.atEnd()) {
|
||||
stream >> storiesClickTooltipHidden;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
auto count = qint32();
|
||||
stream >> count;
|
||||
if (stream.status() == QDataStream::Ok) {
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
auto id = QString();
|
||||
stream >> id;
|
||||
if (stream.status() == QDataStream::Ok) {
|
||||
recentEmojiSkip.emplace(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for Core::Settings::constructFromSerialized()"));
|
||||
|
@ -872,6 +893,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
|||
_ignoreBatterySaving = (ignoreBatterySaving == 1);
|
||||
_macRoundIconDigest = macRoundIconDigest ? macRoundIconDigest : std::optional<uint64>();
|
||||
_storiesClickTooltipHidden = (storiesClickTooltipHidden == 1);
|
||||
_recentEmojiSkip = std::move(recentEmojiSkip);
|
||||
}
|
||||
|
||||
QString Settings::getSoundPath(const QString &key) const {
|
||||
|
@ -964,7 +986,8 @@ rpl::producer<int> Settings::thirdColumnWidthChanges() const {
|
|||
}
|
||||
|
||||
const std::vector<RecentEmoji> &Settings::recentEmoji() const {
|
||||
if (_recentEmoji.empty()) {
|
||||
if (!_recentEmojiResolved) {
|
||||
_recentEmojiResolved = true;
|
||||
resolveRecentEmoji();
|
||||
}
|
||||
return _recentEmoji;
|
||||
|
@ -1005,6 +1028,8 @@ void Settings::resolveRecentEmoji() const {
|
|||
for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
|
||||
if (_recentEmoji.size() >= specialCount + kRecentEmojiLimit) {
|
||||
break;
|
||||
} else if (_recentEmojiSkip.contains(emoji->id())) {
|
||||
continue;
|
||||
} else if (!haveAlready({ emoji })) {
|
||||
_recentEmoji.push_back({ { emoji }, 1 });
|
||||
}
|
||||
|
@ -1014,6 +1039,9 @@ void Settings::resolveRecentEmoji() const {
|
|||
void Settings::incrementRecentEmoji(RecentEmojiId id) {
|
||||
resolveRecentEmoji();
|
||||
|
||||
if (const auto emoji = std::get_if<EmojiPtr>(&id.data)) {
|
||||
_recentEmojiSkip.remove((*emoji)->id());
|
||||
}
|
||||
auto i = _recentEmoji.begin(), e = _recentEmoji.end();
|
||||
for (; i != e; ++i) {
|
||||
if (i->id == id) {
|
||||
|
@ -1065,6 +1093,36 @@ void Settings::incrementRecentEmoji(RecentEmojiId id) {
|
|||
_saveDelayed.fire({});
|
||||
}
|
||||
|
||||
void Settings::hideRecentEmoji(RecentEmojiId id) {
|
||||
resolveRecentEmoji();
|
||||
|
||||
_recentEmoji.erase(
|
||||
ranges::remove(_recentEmoji, id, &RecentEmoji::id),
|
||||
end(_recentEmoji));
|
||||
if (const auto emoji = std::get_if<EmojiPtr>(&id.data)) {
|
||||
for (const auto always : Ui::Emoji::GetDefaultRecent()) {
|
||||
if (always == *emoji) {
|
||||
_recentEmojiSkip.emplace(always->id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_recentEmojiUpdated.fire({});
|
||||
_saveDelayed.fire({});
|
||||
}
|
||||
|
||||
void Settings::resetRecentEmoji() {
|
||||
resolveRecentEmoji();
|
||||
|
||||
_recentEmoji.clear();
|
||||
_recentEmojiSkip.clear();
|
||||
_recentEmojiPreload.clear();
|
||||
_recentEmojiResolved = false;
|
||||
|
||||
_recentEmojiUpdated.fire({});
|
||||
_saveDelayed.fire({});
|
||||
}
|
||||
|
||||
void Settings::setLegacyRecentEmojiPreload(
|
||||
QVector<QPair<QString, ushort>> data) {
|
||||
if (!_recentEmojiPreload.empty() || data.isEmpty()) {
|
||||
|
|
|
@ -72,7 +72,7 @@ struct WindowTitleContent {
|
|||
WindowTitleContent) = default;
|
||||
};
|
||||
|
||||
constexpr auto kRecentEmojiLimit = 42;
|
||||
constexpr auto kRecentEmojiLimit = 54;
|
||||
|
||||
struct RecentEmojiDocument {
|
||||
DocumentId id = 0;
|
||||
|
@ -660,6 +660,8 @@ public:
|
|||
|
||||
[[nodiscard]] const std::vector<RecentEmoji> &recentEmoji() const;
|
||||
void incrementRecentEmoji(RecentEmojiId id);
|
||||
void hideRecentEmoji(RecentEmojiId id);
|
||||
void resetRecentEmoji();
|
||||
void setLegacyRecentEmojiPreload(QVector<QPair<QString, ushort>> data);
|
||||
[[nodiscard]] rpl::producer<> recentEmojiUpdated() const {
|
||||
return _recentEmojiUpdated.events();
|
||||
|
@ -894,6 +896,8 @@ private:
|
|||
rpl::variable<bool> _mainMenuAccountsShown = true;
|
||||
mutable std::vector<RecentEmojiPreload> _recentEmojiPreload;
|
||||
mutable std::vector<RecentEmoji> _recentEmoji;
|
||||
base::flat_set<QString> _recentEmojiSkip;
|
||||
mutable bool _recentEmojiResolved = false;
|
||||
base::flat_map<QString, uint8> _emojiVariants;
|
||||
rpl::event_stream<> _recentEmojiUpdated;
|
||||
bool _tabbedSelectorSectionEnabled = false; // per-window
|
||||
|
|
|
@ -137,6 +137,7 @@ menuIconBotCommands: icon {{ "menu/bot_commands", menuIconColor }};
|
|||
menuIconPremium: icon {{ "menu/premium", menuIconColor }};
|
||||
menuIconIpAddress: icon {{ "menu/ip_address", menuIconColor }};
|
||||
menuIconAddress: icon {{ "menu/payment_address", menuIconColor }};
|
||||
menuIconShowAll: icon {{ "menu/all_media", menuIconColor }};
|
||||
|
||||
menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }};
|
||||
menuIconTTLAnyTextPosition: point(11px, 22px);
|
||||
|
@ -169,6 +170,7 @@ menuIconDeleteAttention: icon {{ "menu/delete", menuIconAttentionColor }};
|
|||
menuIconLeaveAttention: icon {{ "menu/leave", menuIconAttentionColor }};
|
||||
menuIconDisableAttention: icon {{ "menu/disable", menuIconAttentionColor }};
|
||||
menuIconReportAttention: icon {{ "menu/report", menuIconAttentionColor }};
|
||||
menuIconRestoreAttention: icon {{ "menu/restore", menuIconAttentionColor }};
|
||||
|
||||
menuIconBlockSettings: icon {{ "menu/block", windowBgActive }};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue