Check test/production DC in recent emoji.

This commit is contained in:
John Preston 2022-07-15 20:56:25 +04:00
parent 323c2a6aa5
commit 240b47da86
6 changed files with 127 additions and 52 deletions

View file

@ -40,6 +40,9 @@ namespace {
constexpr auto kFakeEmojiDocumentIdBase = 0x7777'FFFF'FFFF'0000ULL; constexpr auto kFakeEmojiDocumentIdBase = 0x7777'FFFF'FFFF'0000ULL;
using Core::RecentEmojiId;
using Core::RecentEmojiDocument;
[[nodiscard]] DocumentId FakeEmojiDocumentId(EmojiPtr emoji) { [[nodiscard]] DocumentId FakeEmojiDocumentId(EmojiPtr emoji) {
return kFakeEmojiDocumentIdBase + emoji->index(); return kFakeEmojiDocumentIdBase + emoji->index();
} }
@ -177,6 +180,11 @@ struct EmojiListWidget::CustomInstance {
bool recentOnly = false; bool recentOnly = false;
}; };
struct EmojiListWidget::RecentOne {
not_null<CustomInstance*> instance;
RecentEmojiId id;
};
EmojiListWidget::CustomInstance::CustomInstance( EmojiListWidget::CustomInstance::CustomInstance(
std::unique_ptr<Ui::CustomEmoji::Loader> loader, std::unique_ptr<Ui::CustomEmoji::Loader> loader,
Fn<void( Fn<void(
@ -435,11 +443,9 @@ EmojiListWidget::EmojiListWidget(
_esize = Ui::Emoji::GetSizeLarge(); _esize = Ui::Emoji::GetSizeLarge();
for (auto i = 0; i != kEmojiSectionCount; ++i) { for (auto i = 1; i != kEmojiSectionCount; ++i) {
const auto section = static_cast<Section>(i); const auto section = static_cast<Section>(i);
_counts[i] = (section == Section::Recent) _counts[i] = Ui::Emoji::GetSectionCount(section);
? int(Core::App().settings().recentEmoji().size())
: Ui::Emoji::GetSectionCount(section);
} }
_picker->chosen( _picker->chosen(
@ -646,7 +652,7 @@ bool EmojiListWidget::enumerateSections(Callback callback) const {
}; };
for (; i != kEmojiSectionCount; ++i) { for (; i != kEmojiSectionCount; ++i) {
info.section = i; info.section = i;
info.count = _counts[i]; info.count = i ? _counts[i] : _recent.size();
if (!next()) { if (!next()) {
return false; return false;
} }
@ -752,17 +758,24 @@ void EmojiListWidget::fillRecent() {
_recentCustomIds.clear(); _recentCustomIds.clear();
const auto &list = Core::App().settings().recentEmoji(); const auto &list = Core::App().settings().recentEmoji();
_recent.reserve(list.size()); _recent.reserve(std::min(int(list.size()), Core::kRecentEmojiLimit));
const auto test = controller()->session().isTestMode();
for (const auto &one : list) { for (const auto &one : list) {
const auto document = std::get_if<RecentEmojiDocument>(&one.id.data);
if (document && document->test != test) {
continue;
}
_recent.push_back({ _recent.push_back({
.instance = resolveCustomInstance(one.id.data), .instance = resolveCustomInstance(one.id),
.id = one.id.data, .id = one.id,
}); });
if (const auto documentId = std::get_if<DocumentId>(&one.id.data)) { if (document) {
_recentCustomIds.emplace(*documentId); _recentCustomIds.emplace(document->id);
}
if (_recent.size() >= Core::kRecentEmojiLimit) {
break;
} }
} }
_counts[0] = _recent.size();
} }
void EmojiListWidget::paintEvent(QPaintEvent *e) { void EmojiListWidget::paintEvent(QPaintEvent *e) {
@ -962,8 +975,8 @@ EmojiPtr EmojiListWidget::lookupOverEmoji(const OverEmoji *over) const {
const auto index = over ? over->index : -1; const auto index = over ? over->index : -1;
return (section == int(Section::Recent) return (section == int(Section::Recent)
&& index < _recent.size() && index < _recent.size()
&& v::is<EmojiPtr>(_recent[index].id)) && v::is<EmojiPtr>(_recent[index].id.data))
? v::get<EmojiPtr>(_recent[index].id) ? v::get<EmojiPtr>(_recent[index].id.data)
: (section > int(Section::Recent) : (section > int(Section::Recent)
&& section < kEmojiSectionCount && section < kEmojiSectionCount
&& index < _emoji[section].size()) && index < _emoji[section].size())
@ -1033,12 +1046,13 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
selectEmoji(emoji); selectEmoji(emoji);
} else if (section == int(Section::Recent) } else if (section == int(Section::Recent)
&& index < _recent.size()) { && index < _recent.size()) {
const auto id = std::get_if<DocumentId>(&_recent[index].id); const auto document = std::get_if<RecentEmojiDocument>(
const auto document = id &_recent[index].id.data);
? session().data().document(*id).get() const auto custom = document
? session().data().document(document->id).get()
: nullptr; : nullptr;
if (document && document->sticker()) { if (custom && custom->sticker()) {
selectCustom(document); selectCustom(custom);
} }
} else if (section >= kEmojiSectionCount } else if (section >= kEmojiSectionCount
&& index < _custom[section - kEmojiSectionCount].list.size()) { && index < _custom[section - kEmojiSectionCount].list.size()) {
@ -1086,7 +1100,10 @@ void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
PremiumPreview::AnimatedEmoji); PremiumPreview::AnimatedEmoji);
return; return;
} }
Core::App().settings().incrementRecentEmoji({ document->id }); Core::App().settings().incrementRecentEmoji({ RecentEmojiDocument{
document->id,
document->session().isTestMode(),
} });
_customChosen.fire({ .document = document }); _customChosen.fire({ .document = document });
} }
@ -1381,11 +1398,12 @@ auto EmojiListWidget::resolveCustomInstance(
} }
auto EmojiListWidget::resolveCustomInstance( auto EmojiListWidget::resolveCustomInstance(
std::variant<EmojiPtr, DocumentId> customId) RecentEmojiId customId)
-> not_null<CustomInstance*> { -> not_null<CustomInstance*> {
if (const auto documentId = std::get_if<DocumentId>(&customId)) { const auto &data = customId.data;
return resolveCustomInstance(*documentId); if (const auto document = std::get_if<RecentEmojiDocument>(&data)) {
} else if (const auto emoji = std::get_if<EmojiPtr>(&customId)) { return resolveCustomInstance(document->id);
} else if (const auto emoji = std::get_if<EmojiPtr>(&data)) {
return resolveCustomInstance(FakeEmojiDocumentId(*emoji), *emoji); return resolveCustomInstance(FakeEmojiDocumentId(*emoji), *emoji);
} }
Unexpected("Custom recent emoji id."); Unexpected("Custom recent emoji id.");

View file

@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/tooltip.h" #include "ui/widgets/tooltip.h"
#include "base/timer.h" #include "base/timer.h"
namespace Core {
struct RecentEmojiId;
} // namespace Core
namespace Data { namespace Data {
class StickersSet; class StickersSet;
} // namespace Data } // namespace Data
@ -119,10 +123,7 @@ private:
bool painted = false; bool painted = false;
bool premium = false; bool premium = false;
}; };
struct RecentOne { struct RecentOne;
not_null<CustomInstance*> instance;
std::variant<EmojiPtr, DocumentId> id;
};
struct RepaintSet { struct RepaintSet {
base::flat_set<uint64> ids; base::flat_set<uint64> ids;
crl::time when = 0; crl::time when = 0;
@ -234,7 +235,7 @@ private:
not_null<DocumentData*> document, not_null<DocumentData*> document,
uint64 setId); uint64 setId);
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance( [[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
std::variant<EmojiPtr, DocumentId> customId); Core::RecentEmojiId customId);
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance( [[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
DocumentId fakeId, DocumentId fakeId,
EmojiPtr emoji); EmojiPtr emoji);

View file

@ -22,8 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Core { namespace Core {
namespace { namespace {
constexpr auto kRecentEmojiLimit = 42;
[[nodiscard]] WindowPosition Deserialize(const QByteArray &data) { [[nodiscard]] WindowPosition Deserialize(const QByteArray &data) {
QDataStream stream(data); QDataStream stream(data);
stream.setVersion(QDataStream::Qt_5_1); stream.setVersion(QDataStream::Qt_5_1);
@ -67,6 +65,24 @@ constexpr auto kRecentEmojiLimit = 42;
return result; return result;
} }
[[nodiscard]] QString Serialize(RecentEmojiDocument document) {
return u"%1-%2"_q.arg(document.id).arg(document.test ? 1 : 0);
}
[[nodiscard]] std::optional<RecentEmojiDocument> ParseRecentEmojiDocument(
const QString &serialized) {
const auto parts = QStringView(serialized).split('-');
if (parts.size() != 2 || parts[1].size() != 1) {
return {};
}
const auto id = parts[0].toULongLong();
const auto test = parts[1][0];
if (!id || (test != '0' && test != '1')) {
return {};
}
return RecentEmojiDocument{ id, (test == '1') };
}
} // namespace } // namespace
Settings::Settings() Settings::Settings()
@ -86,8 +102,9 @@ QByteArray Settings::serialize() const {
recentEmojiPreloadGenerated.reserve(_recentEmoji.size()); recentEmojiPreloadGenerated.reserve(_recentEmoji.size());
for (const auto &[id, rating] : _recentEmoji) { for (const auto &[id, rating] : _recentEmoji) {
auto string = QString(); auto string = QString();
if (const auto documentId = std::get_if<DocumentId>(&id.data)) { if (const auto document = std::get_if<RecentEmojiDocument>(
string = QString::number(*documentId); &id.data)) {
string = Serialize(*document);
} else if (const auto emoji = std::get_if<EmojiPtr>(&id.data)) { } else if (const auto emoji = std::get_if<EmojiPtr>(&id.data)) {
string = (*emoji)->id(); string = (*emoji)->id();
} }
@ -788,7 +805,7 @@ rpl::producer<int> Settings::thirdColumnWidthChanges() const {
return _thirdColumnWidth.changes(); return _thirdColumnWidth.changes();
} }
const std::vector<Settings::RecentEmoji> &Settings::recentEmoji() const { const std::vector<RecentEmoji> &Settings::recentEmoji() const {
if (_recentEmoji.empty()) { if (_recentEmoji.empty()) {
resolveRecentEmoji(); resolveRecentEmoji();
} }
@ -802,6 +819,8 @@ void Settings::resolveRecentEmoji() const {
id, id,
[](const RecentEmoji &data) { return data.id; }); [](const RecentEmoji &data) { return data.id; });
}; };
auto testCount = 0;
auto nonTestCount = 0;
if (!_recentEmojiPreload.empty()) { if (!_recentEmojiPreload.empty()) {
_recentEmoji.reserve(_recentEmojiPreload.size()); _recentEmoji.reserve(_recentEmojiPreload.size());
for (const auto &[id, rating] : base::take(_recentEmojiPreload)) { for (const auto &[id, rating] : base::take(_recentEmojiPreload)) {
@ -811,16 +830,22 @@ void Settings::resolveRecentEmoji() const {
if (!haveAlready({ emoji })) { if (!haveAlready({ emoji })) {
_recentEmoji.push_back({ { emoji }, rating }); _recentEmoji.push_back({ { emoji }, rating });
} }
} else if (const auto documentId = id.toULongLong()) { } else if (const auto document = ParseRecentEmojiDocument(id)) {
if (!haveAlready({ documentId })) { if (!haveAlready({ *document })) {
_recentEmoji.push_back({ { documentId }, rating }); _recentEmoji.push_back({ { *document }, rating });
if (document->test) {
++testCount;
} else {
++nonTestCount;
}
} }
} }
} }
_recentEmojiPreload.clear(); _recentEmojiPreload.clear();
} }
const auto specialCount = std::max(testCount, nonTestCount);
for (const auto emoji : Ui::Emoji::GetDefaultRecent()) { for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
if (_recentEmoji.size() >= kRecentEmojiLimit) { if (_recentEmoji.size() >= specialCount + kRecentEmojiLimit) {
break; break;
} else if (!haveAlready({ emoji })) { } else if (!haveAlready({ emoji })) {
_recentEmoji.push_back({ { emoji }, 1 }); _recentEmoji.push_back({ { emoji }, 1 });
@ -854,9 +879,6 @@ void Settings::incrementRecentEmoji(RecentEmojiId id) {
} }
} }
if (i == e) { if (i == e) {
while (_recentEmoji.size() >= kRecentEmojiLimit) {
_recentEmoji.pop_back();
}
_recentEmoji.push_back({ id, 1 }); _recentEmoji.push_back({ id, 1 });
for (i = _recentEmoji.end() - 1; i != _recentEmoji.begin(); --i) { for (i = _recentEmoji.end() - 1; i != _recentEmoji.begin(); --i) {
if ((i - 1)->rating > i->rating) { if ((i - 1)->rating > i->rating) {
@ -864,6 +886,22 @@ void Settings::incrementRecentEmoji(RecentEmojiId id) {
} }
std::swap(*i, *(i - 1)); std::swap(*i, *(i - 1));
} }
auto testCount = 0;
auto nonTestCount = 0;
for (const auto &emoji : _recentEmoji) {
const auto id = &emoji.id.data;
if (const auto document = std::get_if<RecentEmojiDocument>(id)) {
if (document->test) {
++testCount;
} else {
++nonTestCount;
}
}
}
const auto specialCount = std::max(testCount, nonTestCount);
while (_recentEmoji.size() >= specialCount + kRecentEmojiLimit) {
_recentEmoji.pop_back();
}
} }
_recentEmojiUpdated.fire({}); _recentEmojiUpdated.fire({});
_saveDelayed.fire({}); _saveDelayed.fire({});

View file

@ -53,6 +53,30 @@ struct WindowPosition {
int h = 0; int h = 0;
}; };
constexpr auto kRecentEmojiLimit = 42;
struct RecentEmojiDocument {
DocumentId id = 0;
bool test = false;
friend inline auto operator<=>(
RecentEmojiDocument,
RecentEmojiDocument) = default;
};
struct RecentEmojiId {
std::variant<EmojiPtr, RecentEmojiDocument> data;
friend inline auto operator<=>(
RecentEmojiId,
RecentEmojiId) = default;
};
struct RecentEmoji {
RecentEmojiId id;
ushort rating = 0;
};
class Settings final { class Settings final {
public: public:
enum class ScreenCorner { enum class ScreenCorner {
@ -573,17 +597,6 @@ public:
return _workMode.changes(); return _workMode.changes();
} }
struct RecentEmojiId {
std::variant<EmojiPtr, DocumentId> data;
friend inline auto operator<=>(
RecentEmojiId,
RecentEmojiId) = default;
};
struct RecentEmoji {
RecentEmojiId id;
ushort rating = 0;
};
[[nodiscard]] const std::vector<RecentEmoji> &recentEmoji() const; [[nodiscard]] const std::vector<RecentEmoji> &recentEmoji() const;
void incrementRecentEmoji(RecentEmojiId id); void incrementRecentEmoji(RecentEmojiId id);
void setLegacyRecentEmojiPreload(QVector<QPair<QString, ushort>> data); void setLegacyRecentEmojiPreload(QVector<QPair<QString, ushort>> data);

View file

@ -258,10 +258,14 @@ rpl::producer<bool> Session::premiumPossibleValue() const {
_1 || _2); _1 || _2);
} }
bool Session::isTestMode() const {
return mtp().isTestMode();
}
uint64 Session::uniqueId() const { uint64 Session::uniqueId() const {
// See also Account::willHaveSessionUniqueId. // See also Account::willHaveSessionUniqueId.
return userId().bare return userId().bare
| (mtp().isTestMode() ? 0x0100'0000'0000'0000ULL : 0ULL); | (isTestMode() ? 0x0100'0000'0000'0000ULL : 0ULL);
} }
UserId Session::userId() const { UserId Session::userId() const {

View file

@ -86,6 +86,7 @@ public:
[[nodiscard]] rpl::producer<bool> premiumPossibleValue() const; [[nodiscard]] rpl::producer<bool> premiumPossibleValue() const;
[[nodiscard]] bool premiumBadgesShown() const; [[nodiscard]] bool premiumBadgesShown() const;
[[nodiscard]] bool isTestMode() const;
[[nodiscard]] uint64 uniqueId() const; // userId() with TestDC shift. [[nodiscard]] uint64 uniqueId() const; // userId() with TestDC shift.
[[nodiscard]] UserId userId() const; [[nodiscard]] UserId userId() const;
[[nodiscard]] PeerId userPeerId() const; [[nodiscard]] PeerId userPeerId() const;