mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-24 01:06:59 +00:00
Move recent emoji and variants to common settings.
Fixes #16163, fixes #4018, partially fixes #10123.
This commit is contained in:
parent
68e35b232d
commit
5bb73d8d3d
@ -399,7 +399,7 @@ EmojiListWidget::EmojiListWidget(
|
||||
for (auto i = 0; i != kEmojiSectionCount; ++i) {
|
||||
const auto section = static_cast<Section>(i);
|
||||
_counts[i] = (section == Section::Recent)
|
||||
? GetRecentEmoji().size()
|
||||
? int(Core::App().settings().recentEmoji().size())
|
||||
: Ui::Emoji::GetSectionCount(section);
|
||||
}
|
||||
|
||||
@ -500,17 +500,18 @@ void EmojiListWidget::ensureLoaded(int section) {
|
||||
return;
|
||||
}
|
||||
_emoji[section] = (static_cast<Section>(section) == Section::Recent)
|
||||
? GetRecentEmojiSection()
|
||||
? Core::App().settings().recentEmojiSection()
|
||||
: Ui::Emoji::GetSection(static_cast<Section>(section));
|
||||
_counts[section] = _emoji[section].size();
|
||||
if (static_cast<Section>(section) == Section::Recent) {
|
||||
return;
|
||||
}
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
for (auto &emoji : _emoji[section]) {
|
||||
if (emoji->hasVariants()) {
|
||||
auto j = cEmojiVariants().constFind(emoji->nonColoredId());
|
||||
if (j != cEmojiVariants().cend()) {
|
||||
emoji = emoji->variant(j.value());
|
||||
const auto j = variants.find(emoji->nonColoredId());
|
||||
if (j != end(variants)) {
|
||||
emoji = emoji->variant(j->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -594,10 +595,13 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
||||
if (_selected >= 0) {
|
||||
auto section = (_selected / MatrixRowShift);
|
||||
auto sel = _selected % MatrixRowShift;
|
||||
if (section < kEmojiSectionCount && sel < _emoji[section].size() && _emoji[section][sel]->hasVariants()) {
|
||||
if (section < kEmojiSectionCount
|
||||
&& sel < _emoji[section].size()
|
||||
&& _emoji[section][sel]->hasVariants()) {
|
||||
_pickerSel = _selected;
|
||||
setCursor(style::cur_default);
|
||||
if (!cEmojiVariants().contains(_emoji[section][sel]->nonColoredId())) {
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
if (!variants.contains(_emoji[section][sel]->nonColoredId())) {
|
||||
showPicker();
|
||||
} else {
|
||||
_showPickerTimer.callOnce(500);
|
||||
@ -617,8 +621,11 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
} else if (_pickerSel >= 0) {
|
||||
auto section = (_pickerSel / MatrixRowShift);
|
||||
auto sel = _pickerSel % MatrixRowShift;
|
||||
if (section < kEmojiSectionCount && sel < _emoji[section].size() && _emoji[section][sel]->hasVariants()) {
|
||||
if (cEmojiVariants().contains(_emoji[section][sel]->nonColoredId())) {
|
||||
if (section < kEmojiSectionCount
|
||||
&& sel < _emoji[section].size()
|
||||
&& _emoji[section][sel]->hasVariants()) {
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
if (variants.contains(_emoji[section][sel]->nonColoredId())) {
|
||||
_picker->hideAnimated();
|
||||
_pickerSel = -1;
|
||||
}
|
||||
@ -650,7 +657,7 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
}
|
||||
|
||||
void EmojiListWidget::selectEmoji(EmojiPtr emoji) {
|
||||
AddRecentEmoji(emoji);
|
||||
Core::App().settings().incrementRecentEmoji(emoji);
|
||||
_chosen.fire_copy(emoji);
|
||||
}
|
||||
|
||||
@ -698,10 +705,7 @@ QRect EmojiListWidget::emojiRect(int section, int sel) {
|
||||
|
||||
void EmojiListWidget::colorChosen(EmojiPtr emoji) {
|
||||
if (emoji->hasVariants()) {
|
||||
cRefEmojiVariants().insert(
|
||||
emoji->nonColoredId(),
|
||||
emoji->variantIndex(emoji));
|
||||
controller()->session().saveSettingsDelayed();
|
||||
Core::App().settings().saveEmojiVariant(emoji);
|
||||
}
|
||||
if (_pickerSel >= 0) {
|
||||
auto section = (_pickerSel / MatrixRowShift);
|
||||
@ -790,7 +794,7 @@ void EmojiListWidget::processHideFinished() {
|
||||
|
||||
void EmojiListWidget::refreshRecent() {
|
||||
clearSelection();
|
||||
_emoji[0] = GetRecentEmojiSection();
|
||||
_emoji[0] = Core::App().settings().recentEmojiSection();
|
||||
_counts[0] = _emoji[0].size();
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
@ -116,11 +116,11 @@ auto SuggestionsWidget::getRowsByQuery() const -> std::vector<Row> {
|
||||
}) | ranges::to_vector;
|
||||
|
||||
auto lastRecent = begin(result);
|
||||
const auto &recent = GetRecentEmoji();
|
||||
const auto &recent = Core::App().settings().recentEmoji();
|
||||
for (const auto &item : recent) {
|
||||
const auto emoji = item.first->original()
|
||||
? item.first->original()
|
||||
: item.first;
|
||||
const auto emoji = item.emoji->original()
|
||||
? item.emoji->original()
|
||||
: item.emoji;
|
||||
const auto it = ranges::find(result, emoji, [](const Row &row) {
|
||||
return row.emoji.get();
|
||||
});
|
||||
@ -133,12 +133,12 @@ auto SuggestionsWidget::getRowsByQuery() const -> std::vector<Row> {
|
||||
for (auto &item : result) {
|
||||
item.emoji = [&] {
|
||||
const auto result = item.emoji;
|
||||
const auto &variants = cEmojiVariants();
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
const auto i = result->hasVariants()
|
||||
? variants.constFind(result->nonColoredId())
|
||||
: variants.cend();
|
||||
return (i != variants.cend())
|
||||
? result->variant(i.value())
|
||||
? variants.find(result->nonColoredId())
|
||||
: end(variants);
|
||||
return (i != end(variants))
|
||||
? result->variant(i->second)
|
||||
: result.get();
|
||||
}();
|
||||
}
|
||||
|
@ -535,6 +535,9 @@ void Application::badMtprotoConfigurationError() {
|
||||
void Application::startLocalStorage() {
|
||||
Local::start();
|
||||
_saveSettingsTimer.emplace([=] { saveSettings(); });
|
||||
_settings.saveDelayedRequests() | rpl::start_with_next([=] {
|
||||
saveSettingsDelayed();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void Application::startEmojiImageLoader() {
|
||||
|
@ -19,6 +19,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Core {
|
||||
namespace {
|
||||
|
||||
constexpr auto kRecentEmojiLimit = 42;
|
||||
|
||||
[[nodiscard]] WindowPosition Deserialize(const QByteArray &data) {
|
||||
QDataStream stream(data);
|
||||
stream.setVersion(QDataStream::Qt_5_1);
|
||||
@ -75,6 +77,17 @@ QByteArray Settings::serialize() const {
|
||||
const auto themesAccentColors = _themesAccentColors.serialize();
|
||||
const auto windowPosition = Serialize(_windowPosition);
|
||||
|
||||
auto recentEmojiPreloadGenerated = std::vector<RecentEmojiId>();
|
||||
if (_recentEmojiPreload.empty()) {
|
||||
recentEmojiPreloadGenerated.reserve(_recentEmoji.size());
|
||||
for (const auto [emoji, rating] : _recentEmoji) {
|
||||
recentEmojiPreloadGenerated.push_back({ emoji->id(), rating });
|
||||
}
|
||||
}
|
||||
const auto &recentEmojiPreloadData = _recentEmojiPreload.empty()
|
||||
? recentEmojiPreloadGenerated
|
||||
: _recentEmojiPreload;
|
||||
|
||||
auto size = Serialize::bytearraySize(themesAccentColors)
|
||||
+ sizeof(qint32) * 5
|
||||
+ Serialize::stringSize(_downloadPath.current())
|
||||
@ -83,10 +96,16 @@ QByteArray Settings::serialize() const {
|
||||
+ Serialize::stringSize(_callOutputDeviceId)
|
||||
+ Serialize::stringSize(_callInputDeviceId)
|
||||
+ Serialize::stringSize(_callVideoInputDeviceId)
|
||||
+ sizeof(qint32) * 3;
|
||||
+ sizeof(qint32) * 5;
|
||||
for (const auto &[key, value] : _soundOverrides) {
|
||||
size += Serialize::stringSize(key) + Serialize::stringSize(value);
|
||||
}
|
||||
for (const auto &[id, rating] : recentEmojiPreloadData) {
|
||||
size += Serialize::stringSize(id) + sizeof(quint16);
|
||||
}
|
||||
for (const auto &[id, variant] : _emojiVariants) {
|
||||
size += Serialize::stringSize(id) + sizeof(quint8);
|
||||
}
|
||||
size += Serialize::bytearraySize(_videoPipGeometry);
|
||||
size += Serialize::bytearraySize(windowPosition);
|
||||
|
||||
@ -165,7 +184,16 @@ QByteArray Settings::serialize() const {
|
||||
<< qint64(_groupCallPushToTalkDelay)
|
||||
<< qint32(0) // Call audio backend
|
||||
<< qint32(_disableCalls ? 1 : 0)
|
||||
<< windowPosition;
|
||||
<< windowPosition
|
||||
<< qint32(recentEmojiPreloadData.size());
|
||||
for (const auto &[id, rating] : recentEmojiPreloadData) {
|
||||
stream << id << quint16(rating);
|
||||
}
|
||||
stream
|
||||
<< qint32(_emojiVariants.size());
|
||||
for (const auto &[id, variant] : _emojiVariants) {
|
||||
stream << id << quint8(variant);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -239,6 +267,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
qint32 callAudioBackend = 0;
|
||||
qint32 disableCalls = _disableCalls ? 1 : 0;
|
||||
QByteArray windowPosition;
|
||||
std::vector<RecentEmojiId> recentEmojiPreload;
|
||||
base::flat_map<QString, uint8> emojiVariants;
|
||||
|
||||
stream >> themesAccentColors;
|
||||
if (!stream.atEnd()) {
|
||||
@ -343,6 +373,30 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
if (!stream.atEnd()) {
|
||||
stream >> windowPosition;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
auto recentCount = qint32(0);
|
||||
stream >> recentCount;
|
||||
if (recentCount > 0 && recentCount < 10000) {
|
||||
recentEmojiPreload.reserve(recentCount);
|
||||
for (auto i = 0; i != recentCount; ++i) {
|
||||
auto id = QString();
|
||||
auto rating = quint16();
|
||||
stream >> id >> rating;
|
||||
recentEmojiPreload.push_back({ id, rating });
|
||||
}
|
||||
}
|
||||
auto variantsCount = qint32(0);
|
||||
stream >> variantsCount;
|
||||
if (variantsCount > 0 && variantsCount < 10000) {
|
||||
emojiVariants.reserve(variantsCount);
|
||||
for (auto i = 0; i != variantsCount; ++i) {
|
||||
auto id = QString();
|
||||
auto variant = quint8();
|
||||
stream >> id >> variant;
|
||||
emojiVariants.emplace(id, variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for Core::Settings::constructFromSerialized()"));
|
||||
@ -446,6 +500,8 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
if (!windowPosition.isEmpty()) {
|
||||
_windowPosition = Deserialize(windowPosition);
|
||||
}
|
||||
_recentEmojiPreload = std::move(recentEmojiPreload);
|
||||
_emojiVariants = std::move(emojiVariants);
|
||||
}
|
||||
|
||||
bool Settings::chatWide() const {
|
||||
@ -525,6 +581,118 @@ rpl::producer<int> Settings::thirdColumnWidthChanges() const {
|
||||
return _thirdColumnWidth.changes();
|
||||
}
|
||||
|
||||
const std::vector<Settings::RecentEmoji> &Settings::recentEmoji() const {
|
||||
if (_recentEmoji.empty()) {
|
||||
resolveRecentEmoji();
|
||||
}
|
||||
return _recentEmoji;
|
||||
}
|
||||
|
||||
void Settings::resolveRecentEmoji() const {
|
||||
const auto haveAlready = [&](EmojiPtr emoji) {
|
||||
return ranges::contains(
|
||||
_recentEmoji,
|
||||
emoji->id(),
|
||||
[](const RecentEmoji &data) { return data.emoji->id(); });
|
||||
};
|
||||
if (!_recentEmojiPreload.empty()) {
|
||||
_recentEmoji.reserve(_recentEmojiPreload.size());
|
||||
for (const auto &[id, rating] : base::take(_recentEmojiPreload)) {
|
||||
if (const auto emoji = Ui::Emoji::Find(id)) {
|
||||
if (!haveAlready(emoji)) {
|
||||
_recentEmoji.push_back({ emoji, rating });
|
||||
}
|
||||
}
|
||||
}
|
||||
_recentEmojiPreload.clear();
|
||||
}
|
||||
for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
|
||||
if (_recentEmoji.size() >= kRecentEmojiLimit) {
|
||||
break;
|
||||
} else if (!haveAlready(emoji)) {
|
||||
_recentEmoji.push_back({ emoji, 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmojiPack Settings::recentEmojiSection() const {
|
||||
const auto &recent = recentEmoji();
|
||||
|
||||
auto result = EmojiPack();
|
||||
result.reserve(recent.size());
|
||||
for (const auto [emoji, rating] : recent) {
|
||||
result.push_back(emoji);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Settings::incrementRecentEmoji(EmojiPtr emoji) {
|
||||
resolveRecentEmoji();
|
||||
|
||||
auto i = _recentEmoji.begin(), e = _recentEmoji.end();
|
||||
for (; i != e; ++i) {
|
||||
if (i->emoji == emoji) {
|
||||
++i->rating;
|
||||
if (i->rating > 0x8000) {
|
||||
for (auto j = _recentEmoji.begin(); j != e; ++j) {
|
||||
if (j->rating > 1) {
|
||||
j->rating /= 2;
|
||||
} else {
|
||||
j->rating = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i != _recentEmoji.begin(); --i) {
|
||||
if ((i - 1)->rating > i->rating) {
|
||||
break;
|
||||
}
|
||||
std::swap(*i, *(i - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == e) {
|
||||
while (_recentEmoji.size() >= kRecentEmojiLimit) {
|
||||
_recentEmoji.pop_back();
|
||||
}
|
||||
_recentEmoji.push_back({ emoji, 1 });
|
||||
for (i = _recentEmoji.end() - 1; i != _recentEmoji.begin(); --i) {
|
||||
if ((i - 1)->rating > i->rating) {
|
||||
break;
|
||||
}
|
||||
std::swap(*i, *(i - 1));
|
||||
}
|
||||
}
|
||||
_recentEmojiUpdated.fire({});
|
||||
_saveDelayed.fire({});
|
||||
}
|
||||
|
||||
void Settings::setLegacyRecentEmojiPreload(
|
||||
QVector<QPair<QString, ushort>> data) {
|
||||
if (!_recentEmojiPreload.empty() || data.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
_recentEmojiPreload.reserve(data.size());
|
||||
for (const auto &[id, rating] : data) {
|
||||
_recentEmojiPreload.push_back({ id, rating });
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::saveEmojiVariant(EmojiPtr emoji) {
|
||||
_emojiVariants[emoji->nonColoredId()] = emoji->variantIndex(emoji);
|
||||
_saveDelayed.fire({});
|
||||
}
|
||||
|
||||
void Settings::setLegacyEmojiVariants(QMap<QString, int> data) {
|
||||
if (!_emojiVariants.empty() || data.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
_emojiVariants.reserve(data.size());
|
||||
for (auto i = data.begin(), e = data.end(); i != e; ++i) {
|
||||
_emojiVariants.emplace(i.key(), i.value());
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::resetOnLastLogout() {
|
||||
_adaptiveForWide = true;
|
||||
_moderateModeEnabled = false;
|
||||
@ -592,6 +760,10 @@ void Settings::resetOnLastLogout() {
|
||||
_notifyFromAll = true;
|
||||
_tabbedReplacedWithInfo = false; // per-window
|
||||
_systemDarkModeEnabled = false;
|
||||
|
||||
_recentEmojiPreload.clear();
|
||||
_recentEmoji.clear();
|
||||
_emojiVariants.clear();
|
||||
}
|
||||
|
||||
bool Settings::ThirdColumnByDefault() {
|
||||
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/themes/window_themes_embedded.h"
|
||||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "emoji.h"
|
||||
|
||||
enum class RectPart;
|
||||
|
||||
@ -52,6 +53,10 @@ public:
|
||||
|
||||
Settings();
|
||||
|
||||
[[nodiscard]] rpl::producer<> saveDelayedRequests() const {
|
||||
return _saveDelayed.events();
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool IsLeftCorner(ScreenCorner corner) {
|
||||
return (corner == ScreenCorner::TopLeft)
|
||||
|| (corner == ScreenCorner::BottomLeft);
|
||||
@ -509,8 +514,26 @@ public:
|
||||
_windowPosition = position;
|
||||
}
|
||||
|
||||
struct RecentEmoji {
|
||||
EmojiPtr emoji = nullptr;
|
||||
ushort rating = 0;
|
||||
};
|
||||
[[nodiscard]] const std::vector<RecentEmoji> &recentEmoji() const;
|
||||
[[nodiscard]] EmojiPack recentEmojiSection() const;
|
||||
void incrementRecentEmoji(EmojiPtr emoji);
|
||||
void setLegacyRecentEmojiPreload(QVector<QPair<QString, ushort>> data);
|
||||
[[nodiscard]] rpl::producer<> recentEmojiUpdated() const {
|
||||
return _recentEmojiUpdated.events();
|
||||
}
|
||||
|
||||
[[nodiscard]] const base::flat_map<QString, uint8> &emojiVariants() const {
|
||||
return _emojiVariants;
|
||||
}
|
||||
void saveEmojiVariant(EmojiPtr emoji);
|
||||
void setLegacyEmojiVariants(QMap<QString, int> data);
|
||||
|
||||
[[nodiscard]] static bool ThirdColumnByDefault();
|
||||
[[nodiscard]] float64 DefaultDialogsWidthRatio();
|
||||
[[nodiscard]] static float64 DefaultDialogsWidthRatio();
|
||||
[[nodiscard]] static qint32 SerializePlaybackSpeed(float64 speed) {
|
||||
return int(std::round(std::clamp(speed, 0.5, 2.0) * 100));
|
||||
}
|
||||
@ -526,10 +549,17 @@ public:
|
||||
void resetOnLastLogout();
|
||||
|
||||
private:
|
||||
void resolveRecentEmoji() const;
|
||||
|
||||
static constexpr auto kDefaultThirdColumnWidth = 0;
|
||||
static constexpr auto kDefaultDialogsWidthRatio = 5. / 14;
|
||||
static constexpr auto kDefaultBigDialogsWidthRatio = 0.275;
|
||||
|
||||
struct RecentEmojiId {
|
||||
QString emoji;
|
||||
ushort rating = 0;
|
||||
};
|
||||
|
||||
bool _adaptiveForWide = true;
|
||||
bool _moderateModeEnabled = false;
|
||||
rpl::variable<float64> _songVolume = kDefaultVolume;
|
||||
@ -577,6 +607,10 @@ private:
|
||||
rpl::variable<std::vector<int>> _dictionariesEnabled;
|
||||
rpl::variable<bool> _autoDownloadDictionaries = true;
|
||||
rpl::variable<bool> _mainMenuAccountsShown = true;
|
||||
mutable std::vector<RecentEmojiId> _recentEmojiPreload;
|
||||
mutable std::vector<RecentEmoji> _recentEmoji;
|
||||
base::flat_map<QString, uint8> _emojiVariants;
|
||||
rpl::event_stream<> _recentEmojiUpdated;
|
||||
bool _tabbedSelectorSectionEnabled = false; // per-window
|
||||
Window::Column _floatPlayerColumn = Window::Column(); // per-window
|
||||
RectPart _floatPlayerCorner = RectPart(); // per-window
|
||||
@ -594,6 +628,7 @@ private:
|
||||
bool _tabbedReplacedWithInfo = false; // per-window
|
||||
rpl::event_stream<bool> _tabbedReplacedWithInfoValue; // per-window
|
||||
|
||||
rpl::event_stream<> _saveDelayed;
|
||||
float64 _rememberedSongVolume = kDefaultVolume;
|
||||
bool _rememberedSoundNotifyFromTray = false;
|
||||
bool _rememberedFlashBounceNotifyFromTray = false;
|
||||
|
@ -234,11 +234,12 @@ const Ui::Emoji::One *UiIntegration::defaultEmojiVariant(
|
||||
return emoji;
|
||||
}
|
||||
const auto nonColored = emoji->nonColoredId();
|
||||
const auto it = cEmojiVariants().constFind(nonColored);
|
||||
const auto result = (it != cEmojiVariants().cend())
|
||||
? emoji->variant(it.value())
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
const auto i = variants.find(nonColored);
|
||||
const auto result = (i != end(variants))
|
||||
? emoji->variant(i->second)
|
||||
: emoji;
|
||||
AddRecentEmoji(result);
|
||||
Core::App().settings().incrementRecentEmoji(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "chat_helpers/emoji_list_widget.h"
|
||||
#include "core/sandbox.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_file_origin.h"
|
||||
@ -265,7 +267,7 @@ void AppendEmojiPacks(
|
||||
for (auto i = 0; i != ChatHelpers::kEmojiSectionCount; ++i) {
|
||||
const auto section = static_cast<Ui::Emoji::Section>(i);
|
||||
const auto list = (section == Ui::Emoji::Section::Recent)
|
||||
? GetRecentEmojiSection()
|
||||
? Core::App().settings().recentEmojiSection()
|
||||
: Ui::Emoji::GetSection(section);
|
||||
const auto title = (section == Ui::Emoji::Section::Recent)
|
||||
? TitleRecentlyUsed(sets)
|
||||
@ -473,7 +475,7 @@ void AppendEmojiPacks(
|
||||
if (const auto inputField = qobject_cast<QTextEdit*>(
|
||||
QApplication::focusWidget())) {
|
||||
Ui::InsertEmojiAtCursor(inputField->textCursor(), emoji);
|
||||
AddRecentEmoji(emoji);
|
||||
Core::App().settings().incrementRecentEmoji(emoji);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -567,7 +569,7 @@ void AppendEmojiPacks(
|
||||
_session->data().stickers().recentUpdated()
|
||||
) | rpl::map_to(ScrubberItemType::Sticker),
|
||||
rpl::merge(
|
||||
UpdatedRecentEmoji(),
|
||||
Core::App().settings().recentEmojiUpdated(),
|
||||
Ui::Emoji::Updated()
|
||||
) | rpl::map_to(ScrubberItemType::Emoji)
|
||||
) | rpl::start_with_next([=](ScrubberItemType type) {
|
||||
|
@ -9,14 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "ui/emoji_config.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kRecentEmojiLimit = 42;
|
||||
|
||||
auto UpdatesRecentEmoji = rpl::event_stream<>();
|
||||
|
||||
} // namespace
|
||||
|
||||
Qt::LayoutDirection gLangDir = Qt::LeftToRight;
|
||||
|
||||
bool gInstallBetaVersion = AppBetaVersion;
|
||||
@ -56,10 +48,6 @@ int gConfigScale = style::kScaleAuto;
|
||||
|
||||
QString gTimeFormat = qsl("hh:mm");
|
||||
|
||||
RecentEmojiPack gRecentEmoji;
|
||||
RecentEmojiPreload gRecentEmojiPreload;
|
||||
EmojiColorVariants gEmojiVariants;
|
||||
|
||||
RecentStickerPreload gRecentStickersPreload;
|
||||
RecentStickerPack gRecentStickers;
|
||||
|
||||
@ -79,92 +67,3 @@ int gOtherOnline = 0;
|
||||
int32 gAutoDownloadPhoto = 0; // all auto download
|
||||
int32 gAutoDownloadAudio = 0;
|
||||
int32 gAutoDownloadGif = 0;
|
||||
|
||||
RecentEmojiPack &GetRecentEmoji() {
|
||||
if (cRecentEmoji().isEmpty()) {
|
||||
RecentEmojiPack result;
|
||||
auto haveAlready = [&result](EmojiPtr emoji) {
|
||||
for (auto &row : result) {
|
||||
if (row.first->id() == emoji->id()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (!cRecentEmojiPreload().isEmpty()) {
|
||||
auto preload = cRecentEmojiPreload();
|
||||
cSetRecentEmojiPreload(RecentEmojiPreload());
|
||||
result.reserve(preload.size());
|
||||
for (auto i = preload.cbegin(), e = preload.cend(); i != e; ++i) {
|
||||
if (auto emoji = Ui::Emoji::Find(i->first)) {
|
||||
if (!haveAlready(emoji)) {
|
||||
result.push_back(qMakePair(emoji, i->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
|
||||
if (result.size() >= kRecentEmojiLimit) break;
|
||||
|
||||
if (!haveAlready(emoji)) {
|
||||
result.push_back(qMakePair(emoji, 1));
|
||||
}
|
||||
}
|
||||
cSetRecentEmoji(result);
|
||||
}
|
||||
return cRefRecentEmoji();
|
||||
}
|
||||
|
||||
EmojiPack GetRecentEmojiSection() {
|
||||
const auto &recent = GetRecentEmoji();
|
||||
|
||||
auto result = EmojiPack();
|
||||
result.reserve(recent.size());
|
||||
for (const auto &item : recent) {
|
||||
result.push_back(item.first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void AddRecentEmoji(EmojiPtr emoji) {
|
||||
auto &recent = GetRecentEmoji();
|
||||
auto i = recent.begin(), e = recent.end();
|
||||
for (; i != e; ++i) {
|
||||
if (i->first == emoji) {
|
||||
++i->second;
|
||||
if (i->second > 0x8000) {
|
||||
for (auto j = recent.begin(); j != e; ++j) {
|
||||
if (j->second > 1) {
|
||||
j->second /= 2;
|
||||
} else {
|
||||
j->second = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i != recent.begin(); --i) {
|
||||
if ((i - 1)->second > i->second) {
|
||||
break;
|
||||
}
|
||||
std::swap(*i, *(i - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == e) {
|
||||
while (recent.size() >= kRecentEmojiLimit) {
|
||||
recent.pop_back();
|
||||
}
|
||||
recent.push_back(qMakePair(emoji, 1));
|
||||
for (i = recent.end() - 1; i != recent.begin(); --i) {
|
||||
if ((i - 1)->second > i->second) {
|
||||
break;
|
||||
}
|
||||
std::swap(*i, *(i - 1));
|
||||
}
|
||||
}
|
||||
UpdatesRecentEmoji.fire({});
|
||||
}
|
||||
|
||||
rpl::producer<> UpdatedRecentEmoji() {
|
||||
return UpdatesRecentEmoji.events();
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "ui/style/style_core.h"
|
||||
#include "emoji.h"
|
||||
|
||||
#define DeclareReadSetting(Type, Name) extern Type g##Name; \
|
||||
inline const Type &c##Name() { \
|
||||
@ -84,16 +83,6 @@ DeclareSetting(int, ScreenScale);
|
||||
DeclareSetting(int, ConfigScale);
|
||||
DeclareSetting(QString, TimeFormat);
|
||||
|
||||
using RecentEmojiPreloadOldOld = QVector<QPair<uint32, ushort>>;
|
||||
using RecentEmojiPreloadOld = QVector<QPair<uint64, ushort>>;
|
||||
using RecentEmojiPreload = QVector<QPair<QString, ushort>>;
|
||||
using RecentEmojiPack = QVector<QPair<EmojiPtr, ushort>>;
|
||||
using EmojiColorVariantsOld = QMap<uint32, uint64>;
|
||||
using EmojiColorVariants = QMap<QString, int>;
|
||||
DeclareRefSetting(RecentEmojiPack, RecentEmoji);
|
||||
DeclareSetting(RecentEmojiPreload, RecentEmojiPreload);
|
||||
DeclareRefSetting(EmojiColorVariants, EmojiVariants);
|
||||
|
||||
class DocumentData;
|
||||
|
||||
typedef QList<QPair<DocumentData*, int16>> RecentStickerPackOld;
|
||||
@ -124,11 +113,6 @@ inline void cChangeTimeFormat(const QString &newFormat) {
|
||||
if (!newFormat.isEmpty()) cSetTimeFormat(newFormat);
|
||||
}
|
||||
|
||||
RecentEmojiPack &GetRecentEmoji();
|
||||
QVector<EmojiPtr> GetRecentEmojiSection();
|
||||
void AddRecentEmoji(EmojiPtr emoji);
|
||||
[[nodiscard]] rpl::producer<> UpdatedRecentEmoji();
|
||||
|
||||
inline bool passcodeCanTry() {
|
||||
if (cPasscodeBadTries() < 3) return true;
|
||||
auto dt = crl::now() - cPasscodeLastTry();
|
||||
|
@ -944,13 +944,13 @@ bool ReadSetting(
|
||||
context.legacyRead = true;
|
||||
} break;
|
||||
|
||||
case dbiRecentEmojiOldOld: {
|
||||
RecentEmojiPreloadOldOld v;
|
||||
case dbiRecentEmojiOldOldOld: {
|
||||
auto v = QVector<QPair<uint32, ushort>>();
|
||||
stream >> v;
|
||||
if (!CheckStreamStatus(stream)) return false;
|
||||
|
||||
if (!v.isEmpty()) {
|
||||
RecentEmojiPreload p;
|
||||
auto p = QVector<QPair<QString, ushort>>();
|
||||
p.reserve(v.size());
|
||||
for (auto &item : v) {
|
||||
auto oldKey = uint64(item.first);
|
||||
@ -971,18 +971,18 @@ bool ReadSetting(
|
||||
p.push_back(qMakePair(id, item.second));
|
||||
}
|
||||
}
|
||||
cSetRecentEmojiPreload(p);
|
||||
Core::App().settings().setLegacyRecentEmojiPreload(std::move(p));
|
||||
}
|
||||
context.legacyRead = true;
|
||||
} break;
|
||||
|
||||
case dbiRecentEmojiOld: {
|
||||
RecentEmojiPreloadOld v;
|
||||
case dbiRecentEmojiOldOld: {
|
||||
auto v = QVector<QPair<uint64, ushort>>();
|
||||
stream >> v;
|
||||
if (!CheckStreamStatus(stream)) return false;
|
||||
|
||||
if (!v.isEmpty()) {
|
||||
RecentEmojiPreload p;
|
||||
auto p = QVector<QPair<QString, ushort>>();
|
||||
p.reserve(v.size());
|
||||
for (auto &item : v) {
|
||||
auto id = Ui::Emoji::IdFromOldKey(item.first);
|
||||
@ -990,17 +990,18 @@ bool ReadSetting(
|
||||
p.push_back(qMakePair(id, item.second));
|
||||
}
|
||||
}
|
||||
cSetRecentEmojiPreload(p);
|
||||
Core::App().settings().setLegacyRecentEmojiPreload(std::move(p));
|
||||
}
|
||||
context.legacyRead = true;
|
||||
} break;
|
||||
|
||||
case dbiRecentEmoji: {
|
||||
RecentEmojiPreload v;
|
||||
case dbiRecentEmojiOld: {
|
||||
auto v = QVector<QPair<QString, ushort>>();
|
||||
stream >> v;
|
||||
if (!CheckStreamStatus(stream)) return false;
|
||||
|
||||
cSetRecentEmojiPreload(v);
|
||||
Core::App().settings().setLegacyRecentEmojiPreload(std::move(v));
|
||||
context.legacyRead = true;
|
||||
} break;
|
||||
|
||||
case dbiRecentStickers: {
|
||||
@ -1011,12 +1012,12 @@ bool ReadSetting(
|
||||
cSetRecentStickersPreload(v);
|
||||
} break;
|
||||
|
||||
case dbiEmojiVariantsOld: {
|
||||
EmojiColorVariantsOld v;
|
||||
case dbiEmojiVariantsOldOld: {
|
||||
auto v = QMap<uint32, uint64>();
|
||||
stream >> v;
|
||||
if (!CheckStreamStatus(stream)) return false;
|
||||
|
||||
EmojiColorVariants variants;
|
||||
auto variants = QMap<QString, int>();
|
||||
for (auto i = v.cbegin(), e = v.cend(); i != e; ++i) {
|
||||
auto id = Ui::Emoji::IdFromOldKey(static_cast<uint64>(i.key()));
|
||||
if (!id.isEmpty()) {
|
||||
@ -1026,16 +1027,17 @@ bool ReadSetting(
|
||||
}
|
||||
}
|
||||
}
|
||||
cSetEmojiVariants(variants);
|
||||
Core::App().settings().setLegacyEmojiVariants(std::move(variants));
|
||||
context.legacyRead = true;
|
||||
} break;
|
||||
|
||||
case dbiEmojiVariants: {
|
||||
EmojiColorVariants v;
|
||||
case dbiEmojiVariantsOld: {
|
||||
auto v = QMap<QString, int>();
|
||||
stream >> v;
|
||||
if (!CheckStreamStatus(stream)) return false;
|
||||
|
||||
cSetEmojiVariants(v);
|
||||
Core::App().settings().setLegacyEmojiVariants(std::move(v));
|
||||
context.legacyRead = true;
|
||||
} break;
|
||||
|
||||
case dbiHiddenPinnedMessagesOld: {
|
||||
|
@ -101,7 +101,7 @@ enum {
|
||||
dbiDownloadPathOldOld = 0x15,
|
||||
dbiScaleOld = 0x16,
|
||||
dbiEmojiTabOld = 0x17,
|
||||
dbiRecentEmojiOldOld = 0x18,
|
||||
dbiRecentEmojiOldOldOld = 0x18,
|
||||
dbiLoggedPhoneNumberOld = 0x19,
|
||||
dbiMutedPeersOld = 0x1a,
|
||||
// 0x1b reserved
|
||||
@ -113,8 +113,8 @@ enum {
|
||||
dbiTileBackgroundOld = 0x21,
|
||||
dbiAutoLockOld = 0x22,
|
||||
dbiDialogLastPath = 0x23,
|
||||
dbiRecentEmojiOld = 0x24,
|
||||
dbiEmojiVariantsOld = 0x25,
|
||||
dbiRecentEmojiOldOld = 0x24,
|
||||
dbiEmojiVariantsOldOld = 0x25,
|
||||
dbiRecentStickers = 0x26,
|
||||
dbiDcOptionOld = 0x27,
|
||||
dbiTryIPv6 = 0x28,
|
||||
@ -129,8 +129,8 @@ enum {
|
||||
dbiAutoPlayOld = 0x37,
|
||||
dbiAdaptiveForWideOld = 0x38,
|
||||
dbiHiddenPinnedMessagesOld = 0x39,
|
||||
dbiRecentEmoji = 0x3a,
|
||||
dbiEmojiVariants = 0x3b,
|
||||
dbiRecentEmojiOld = 0x3a,
|
||||
dbiEmojiVariantsOld = 0x3b,
|
||||
dbiDialogsModeOld = 0x40,
|
||||
dbiModerateModeOld = 0x41,
|
||||
dbiVideoVolumeOld = 0x42,
|
||||
|
@ -734,13 +734,6 @@ void Account::writeSessionSettings(Main::SessionSettings *stored) {
|
||||
writeMapQueued();
|
||||
}
|
||||
|
||||
auto recentEmojiPreloadData = cRecentEmojiPreload();
|
||||
if (recentEmojiPreloadData.isEmpty()) {
|
||||
recentEmojiPreloadData.reserve(GetRecentEmoji().size());
|
||||
for (auto &item : GetRecentEmoji()) {
|
||||
recentEmojiPreloadData.push_back(qMakePair(item.first->id(), item.second));
|
||||
}
|
||||
}
|
||||
auto userDataInstance = stored
|
||||
? stored
|
||||
: _owner->getSessionSettings();
|
||||
@ -759,13 +752,6 @@ void Account::writeSessionSettings(Main::SessionSettings *stored) {
|
||||
|
||||
uint32 size = 24 * (sizeof(quint32) + sizeof(qint32));
|
||||
size += sizeof(quint32);
|
||||
|
||||
size += sizeof(quint32) + sizeof(qint32);
|
||||
for (auto &item : recentEmojiPreloadData) {
|
||||
size += Serialize::stringSize(item.first) + sizeof(item.second);
|
||||
}
|
||||
|
||||
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
|
||||
size += sizeof(quint32) + sizeof(qint32) + recentStickers.size() * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + 3 * sizeof(qint32);
|
||||
size += sizeof(quint32) + 2 * sizeof(qint32);
|
||||
@ -780,8 +766,6 @@ void Account::writeSessionSettings(Main::SessionSettings *stored) {
|
||||
if (!userData.isEmpty()) {
|
||||
data.stream << quint32(dbiSessionSettings) << userData;
|
||||
}
|
||||
data.stream << quint32(dbiRecentEmoji) << recentEmojiPreloadData;
|
||||
data.stream << quint32(dbiEmojiVariants) << cEmojiVariants();
|
||||
data.stream << quint32(dbiRecentStickers) << recentStickers;
|
||||
|
||||
FileWriteDescriptor file(_settingsKey, _basePath);
|
||||
|
Loading…
Reference in New Issue
Block a user