From ab5a2260562078b7e5abcda8bb0eb2a61984bfd5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 7 May 2020 19:04:45 +0400 Subject: [PATCH] Save set id that failed to load. --- ui/emoji_config.cpp | 101 ++++++++++++++++++++++++++++---------------- ui/emoji_config.h | 30 +++++++------ 2 files changed, 81 insertions(+), 50 deletions(-) diff --git a/ui/emoji_config.cpp b/ui/emoji_config.cpp index 79b12b9..1321614 100644 --- a/ui/emoji_config.cpp +++ b/ui/emoji_config.cpp @@ -31,12 +31,18 @@ constexpr auto kUniversalSize = 72; constexpr auto kImagesPerRow = 32; constexpr auto kImageRowsPerSprite = 16; -constexpr auto kSetVersion = uint32(1); -constexpr auto kCacheVersion = uint32(5); +constexpr auto kSetVersion = uint32(2); +constexpr auto kCacheVersion = uint32(6); constexpr auto kMaxId = uint32(1 << 8); constexpr auto kScaleForTouchBar = 150; +enum class ConfigResult { + Invalid, + BadVersion, + Good, +}; + // Right now we can't allow users of Ui::Emoji to create custom sizes. // Any Instance::Instance() can invalidate Universal.id() and sprites. // So all Instance::Instance() should happen before async generations. @@ -69,6 +75,7 @@ auto InstanceNormal = std::unique_ptr(); auto InstanceLarge = std::unique_ptr(); auto Universal = std::shared_ptr(); auto CanClearUniversal = false; +auto WaitingToSwitchBackToId = 0; auto Updates = rpl::event_stream<>(); #if defined Q_OS_MAC && !defined OS_MAC_OLD @@ -138,7 +145,17 @@ int ReadCurrentSetId() { : 0; } +void ApplyUniversalImages(std::shared_ptr images) { + Universal = std::move(images); + CanClearUniversal = false; + MainEmojiMap.clear(); + OtherEmojiMap.clear(); + Updates.fire({}); +} + void SwitchToSetPrepared(int id, std::shared_ptr images) { + WaitingToSwitchBackToId = 0; + auto setting = QFile(CurrentSettingPath()); if (!id) { setting.remove(); @@ -147,11 +164,34 @@ void SwitchToSetPrepared(int id, std::shared_ptr images) { stream.setVersion(QDataStream::Qt_5_1); stream << qint32(id); } - Universal = std::move(images); - CanClearUniversal = false; - MainEmojiMap.clear(); - OtherEmojiMap.clear(); - Updates.fire({}); + ApplyUniversalImages(std::move(images)); +} + +[[nodiscard]] ConfigResult ValidateConfig(int id) { + Expects(IsValidSetId(id)); + + if (!id) { + return ConfigResult::Good; + } + constexpr auto kSizeLimit = 65536; + auto config = QFile(internal::SetDataPath(id) + "/config.json"); + if (!config.open(QIODevice::ReadOnly) || config.size() > kSizeLimit) { + return ConfigResult::Invalid; + } + auto error = QJsonParseError{ 0, QJsonParseError::NoError }; + const auto document = QJsonDocument::fromJson( + base::parse::stripComments(config.readAll()), + &error); + config.close(); + if (error.error != QJsonParseError::NoError) { + return ConfigResult::Invalid; + } + if (document.object()["id"].toInt() != id) { + return ConfigResult::Invalid; + } else if (document.object()["version"].toInt() != kSetVersion) { + return ConfigResult::BadVersion; + } + return ConfigResult::Good; } void ClearCurrentSetIdSync() { @@ -161,12 +201,14 @@ void ClearCurrentSetIdSync() { if (!id) { return; } - QDir(internal::SetDataPath(id)).removeRecursively(); const auto newId = 0; auto universal = std::make_shared(newId); universal->ensureLoaded(); - SwitchToSetPrepared(newId, std::move(universal)); + + // Start loading the set when possible. + ApplyUniversalImages(std::move(universal)); + WaitingToSwitchBackToId = id; } void SaveToFile(int id, const QImage &image, int size, int index) { @@ -288,37 +330,12 @@ std::vector LoadSprites(int id) { }) | ranges::to_vector; } -bool ValidateConfig(int id) { - Expects(IsValidSetId(id)); - - if (!id) { - return true; - } - constexpr auto kSizeLimit = 65536; - auto config = QFile(internal::SetDataPath(id) + "/config.json"); - if (!config.open(QIODevice::ReadOnly) || config.size() > kSizeLimit) { - return false; - } - auto error = QJsonParseError{ 0, QJsonParseError::NoError }; - const auto document = QJsonDocument::fromJson( - base::parse::stripComments(config.readAll()), - &error); - config.close(); - if (error.error != QJsonParseError::NoError) { - return false; - } - if (document.object()["id"].toInt() != id - || document.object()["version"].toInt() != kSetVersion) { - return false; - } - return true; -} - std::vector LoadAndValidateSprites(int id) { Expects(IsValidSetId(id)); Expects(SpritesCount > 0); - if (!ValidateConfig(id)) { + const auto config = ValidateConfig(id); + if (config != ConfigResult::Good) { return {}; } auto result = LoadSprites(id); @@ -526,6 +543,18 @@ int CurrentSetId() { return Universal->id(); } +int NeedToSwitchBackToId() { + return WaitingToSwitchBackToId; +} + +void ClearNeedSwitchToId() { + if (!WaitingToSwitchBackToId) { + return; + } + WaitingToSwitchBackToId = 0; + QFile(CurrentSettingPath()).remove(); +} + void SwitchToSet(int id, Fn callback) { Expects(IsValidSetId(id)); diff --git a/ui/emoji_config.h b/ui/emoji_config.h index e8a8eba..75f10e1 100644 --- a/ui/emoji_config.h +++ b/ui/emoji_config.h @@ -32,14 +32,16 @@ void ClearIrrelevantCache(); // Thread safe, callback is called on main thread. void SwitchToSet(int id, Fn callback); -int CurrentSetId(); -bool SetIsReady(int id); -rpl::producer<> Updated(); +[[nodiscard]] int CurrentSetId(); +[[nodiscard]] int NeedToSwitchBackToId(); +void ClearNeedSwitchToId(); +[[nodiscard]] bool SetIsReady(int id); +[[nodiscard]] rpl::producer<> Updated(); -int GetSizeNormal(); -int GetSizeLarge(); +[[nodiscard]] int GetSizeNormal(); +[[nodiscard]] int GetSizeLarge(); #if defined Q_OS_MAC && !defined OS_MAC_OLD -int GetSizeTouchbar(); +[[nodiscard]] int GetSizeTouchbar(); #endif class One { @@ -113,7 +115,7 @@ private: }; -inline EmojiPtr FromUrl(const QString &url) { +[[nodiscard]] inline EmojiPtr FromUrl(const QString &url) { auto start = qstr("emoji://e."); if (url.startsWith(start)) { return internal::ByIndex(url.midRef(start.size()).toInt()); // skip emoji://e. @@ -121,21 +123,21 @@ inline EmojiPtr FromUrl(const QString &url) { return nullptr; } -inline EmojiPtr Find(const QChar *start, const QChar *end, int *outLength = nullptr) { +[[nodiscard]] inline EmojiPtr Find(const QChar *start, const QChar *end, int *outLength = nullptr) { return internal::Find(start, end, outLength); } -inline EmojiPtr Find(const QString &text, int *outLength = nullptr) { +[[nodiscard]] inline EmojiPtr Find(const QString &text, int *outLength = nullptr) { return Find(text.constBegin(), text.constEnd(), outLength); } -QString IdFromOldKey(uint64 oldKey); +[[nodiscard]] QString IdFromOldKey(uint64 oldKey); -inline EmojiPtr FromOldKey(uint64 oldKey) { +[[nodiscard]] inline EmojiPtr FromOldKey(uint64 oldKey) { return Find(IdFromOldKey(oldKey)); } -inline int ColorIndexFromCode(uint32 code) { +[[nodiscard]] inline int ColorIndexFromCode(uint32 code) { switch (code) { case 0xD83CDFFBU: return 1; case 0xD83CDFFCU: return 2; @@ -146,7 +148,7 @@ inline int ColorIndexFromCode(uint32 code) { return 0; } -inline int ColorIndexFromOldKey(uint64 oldKey) { +[[nodiscard]] inline int ColorIndexFromOldKey(uint64 oldKey) { return ColorIndexFromCode(uint32(oldKey & 0xFFFFFFFFLLU)); } @@ -175,7 +177,7 @@ private: }; -const std::shared_ptr &SourceImages(); +[[nodiscard]] const std::shared_ptr &SourceImages(); void ClearSourceImages(const std::shared_ptr &images); } // namespace Emoji