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;
using Core::RecentEmojiId;
using Core::RecentEmojiDocument;
[[nodiscard]] DocumentId FakeEmojiDocumentId(EmojiPtr emoji) {
return kFakeEmojiDocumentIdBase + emoji->index();
}
@ -177,6 +180,11 @@ struct EmojiListWidget::CustomInstance {
bool recentOnly = false;
};
struct EmojiListWidget::RecentOne {
not_null<CustomInstance*> instance;
RecentEmojiId id;
};
EmojiListWidget::CustomInstance::CustomInstance(
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
Fn<void(
@ -435,11 +443,9 @@ EmojiListWidget::EmojiListWidget(
_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);
_counts[i] = (section == Section::Recent)
? int(Core::App().settings().recentEmoji().size())
: Ui::Emoji::GetSectionCount(section);
_counts[i] = Ui::Emoji::GetSectionCount(section);
}
_picker->chosen(
@ -646,7 +652,7 @@ bool EmojiListWidget::enumerateSections(Callback callback) const {
};
for (; i != kEmojiSectionCount; ++i) {
info.section = i;
info.count = _counts[i];
info.count = i ? _counts[i] : _recent.size();
if (!next()) {
return false;
}
@ -752,17 +758,24 @@ void EmojiListWidget::fillRecent() {
_recentCustomIds.clear();
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) {
const auto document = std::get_if<RecentEmojiDocument>(&one.id.data);
if (document && document->test != test) {
continue;
}
_recent.push_back({
.instance = resolveCustomInstance(one.id.data),
.id = one.id.data,
.instance = resolveCustomInstance(one.id),
.id = one.id,
});
if (const auto documentId = std::get_if<DocumentId>(&one.id.data)) {
_recentCustomIds.emplace(*documentId);
if (document) {
_recentCustomIds.emplace(document->id);
}
if (_recent.size() >= Core::kRecentEmojiLimit) {
break;
}
}
_counts[0] = _recent.size();
}
void EmojiListWidget::paintEvent(QPaintEvent *e) {
@ -962,8 +975,8 @@ EmojiPtr EmojiListWidget::lookupOverEmoji(const OverEmoji *over) const {
const auto index = over ? over->index : -1;
return (section == int(Section::Recent)
&& index < _recent.size()
&& v::is<EmojiPtr>(_recent[index].id))
? v::get<EmojiPtr>(_recent[index].id)
&& v::is<EmojiPtr>(_recent[index].id.data))
? v::get<EmojiPtr>(_recent[index].id.data)
: (section > int(Section::Recent)
&& section < kEmojiSectionCount
&& index < _emoji[section].size())
@ -1033,12 +1046,13 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
selectEmoji(emoji);
} else if (section == int(Section::Recent)
&& index < _recent.size()) {
const auto id = std::get_if<DocumentId>(&_recent[index].id);
const auto document = id
? session().data().document(*id).get()
const auto document = std::get_if<RecentEmojiDocument>(
&_recent[index].id.data);
const auto custom = document
? session().data().document(document->id).get()
: nullptr;
if (document && document->sticker()) {
selectCustom(document);
if (custom && custom->sticker()) {
selectCustom(custom);
}
} else if (section >= kEmojiSectionCount
&& index < _custom[section - kEmojiSectionCount].list.size()) {
@ -1086,7 +1100,10 @@ void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
PremiumPreview::AnimatedEmoji);
return;
}
Core::App().settings().incrementRecentEmoji({ document->id });
Core::App().settings().incrementRecentEmoji({ RecentEmojiDocument{
document->id,
document->session().isTestMode(),
} });
_customChosen.fire({ .document = document });
}
@ -1381,11 +1398,12 @@ auto EmojiListWidget::resolveCustomInstance(
}
auto EmojiListWidget::resolveCustomInstance(
std::variant<EmojiPtr, DocumentId> customId)
RecentEmojiId customId)
-> not_null<CustomInstance*> {
if (const auto documentId = std::get_if<DocumentId>(&customId)) {
return resolveCustomInstance(*documentId);
} else if (const auto emoji = std::get_if<EmojiPtr>(&customId)) {
const auto &data = customId.data;
if (const auto document = std::get_if<RecentEmojiDocument>(&data)) {
return resolveCustomInstance(document->id);
} else if (const auto emoji = std::get_if<EmojiPtr>(&data)) {
return resolveCustomInstance(FakeEmojiDocumentId(*emoji), *emoji);
}
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 "base/timer.h"
namespace Core {
struct RecentEmojiId;
} // namespace Core
namespace Data {
class StickersSet;
} // namespace Data
@ -119,10 +123,7 @@ private:
bool painted = false;
bool premium = false;
};
struct RecentOne {
not_null<CustomInstance*> instance;
std::variant<EmojiPtr, DocumentId> id;
};
struct RecentOne;
struct RepaintSet {
base::flat_set<uint64> ids;
crl::time when = 0;
@ -234,7 +235,7 @@ private:
not_null<DocumentData*> document,
uint64 setId);
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
std::variant<EmojiPtr, DocumentId> customId);
Core::RecentEmojiId customId);
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
DocumentId fakeId,
EmojiPtr emoji);

View file

@ -22,8 +22,6 @@ 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);
@ -67,6 +65,24 @@ constexpr auto kRecentEmojiLimit = 42;
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
Settings::Settings()
@ -86,8 +102,9 @@ QByteArray Settings::serialize() const {
recentEmojiPreloadGenerated.reserve(_recentEmoji.size());
for (const auto &[id, rating] : _recentEmoji) {
auto string = QString();
if (const auto documentId = std::get_if<DocumentId>(&id.data)) {
string = QString::number(*documentId);
if (const auto document = std::get_if<RecentEmojiDocument>(
&id.data)) {
string = Serialize(*document);
} else if (const auto emoji = std::get_if<EmojiPtr>(&id.data)) {
string = (*emoji)->id();
}
@ -788,7 +805,7 @@ rpl::producer<int> Settings::thirdColumnWidthChanges() const {
return _thirdColumnWidth.changes();
}
const std::vector<Settings::RecentEmoji> &Settings::recentEmoji() const {
const std::vector<RecentEmoji> &Settings::recentEmoji() const {
if (_recentEmoji.empty()) {
resolveRecentEmoji();
}
@ -802,6 +819,8 @@ void Settings::resolveRecentEmoji() const {
id,
[](const RecentEmoji &data) { return data.id; });
};
auto testCount = 0;
auto nonTestCount = 0;
if (!_recentEmojiPreload.empty()) {
_recentEmoji.reserve(_recentEmojiPreload.size());
for (const auto &[id, rating] : base::take(_recentEmojiPreload)) {
@ -811,16 +830,22 @@ void Settings::resolveRecentEmoji() const {
if (!haveAlready({ emoji })) {
_recentEmoji.push_back({ { emoji }, rating });
}
} else if (const auto documentId = id.toULongLong()) {
if (!haveAlready({ documentId })) {
_recentEmoji.push_back({ { documentId }, rating });
} else if (const auto document = ParseRecentEmojiDocument(id)) {
if (!haveAlready({ *document })) {
_recentEmoji.push_back({ { *document }, rating });
if (document->test) {
++testCount;
} else {
++nonTestCount;
}
}
}
}
_recentEmojiPreload.clear();
}
const auto specialCount = std::max(testCount, nonTestCount);
for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
if (_recentEmoji.size() >= kRecentEmojiLimit) {
if (_recentEmoji.size() >= specialCount + kRecentEmojiLimit) {
break;
} else if (!haveAlready({ emoji })) {
_recentEmoji.push_back({ { emoji }, 1 });
@ -854,9 +879,6 @@ void Settings::incrementRecentEmoji(RecentEmojiId id) {
}
}
if (i == e) {
while (_recentEmoji.size() >= kRecentEmojiLimit) {
_recentEmoji.pop_back();
}
_recentEmoji.push_back({ id, 1 });
for (i = _recentEmoji.end() - 1; i != _recentEmoji.begin(); --i) {
if ((i - 1)->rating > i->rating) {
@ -864,6 +886,22 @@ void Settings::incrementRecentEmoji(RecentEmojiId id) {
}
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({});
_saveDelayed.fire({});

View file

@ -53,6 +53,30 @@ struct WindowPosition {
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 {
public:
enum class ScreenCorner {
@ -573,17 +597,6 @@ public:
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;
void incrementRecentEmoji(RecentEmojiId id);
void setLegacyRecentEmojiPreload(QVector<QPair<QString, ushort>> data);

View file

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

View file

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