Save set id that failed to load.
This commit is contained in:
parent
2e82e7a3c9
commit
ab5a226056
2 changed files with 81 additions and 50 deletions
|
|
@ -31,12 +31,18 @@ constexpr auto kUniversalSize = 72;
|
||||||
constexpr auto kImagesPerRow = 32;
|
constexpr auto kImagesPerRow = 32;
|
||||||
constexpr auto kImageRowsPerSprite = 16;
|
constexpr auto kImageRowsPerSprite = 16;
|
||||||
|
|
||||||
constexpr auto kSetVersion = uint32(1);
|
constexpr auto kSetVersion = uint32(2);
|
||||||
constexpr auto kCacheVersion = uint32(5);
|
constexpr auto kCacheVersion = uint32(6);
|
||||||
constexpr auto kMaxId = uint32(1 << 8);
|
constexpr auto kMaxId = uint32(1 << 8);
|
||||||
|
|
||||||
constexpr auto kScaleForTouchBar = 150;
|
constexpr auto kScaleForTouchBar = 150;
|
||||||
|
|
||||||
|
enum class ConfigResult {
|
||||||
|
Invalid,
|
||||||
|
BadVersion,
|
||||||
|
Good,
|
||||||
|
};
|
||||||
|
|
||||||
// Right now we can't allow users of Ui::Emoji to create custom sizes.
|
// Right now we can't allow users of Ui::Emoji to create custom sizes.
|
||||||
// Any Instance::Instance() can invalidate Universal.id() and sprites.
|
// Any Instance::Instance() can invalidate Universal.id() and sprites.
|
||||||
// So all Instance::Instance() should happen before async generations.
|
// So all Instance::Instance() should happen before async generations.
|
||||||
|
|
@ -69,6 +75,7 @@ auto InstanceNormal = std::unique_ptr<Instance>();
|
||||||
auto InstanceLarge = std::unique_ptr<Instance>();
|
auto InstanceLarge = std::unique_ptr<Instance>();
|
||||||
auto Universal = std::shared_ptr<UniversalImages>();
|
auto Universal = std::shared_ptr<UniversalImages>();
|
||||||
auto CanClearUniversal = false;
|
auto CanClearUniversal = false;
|
||||||
|
auto WaitingToSwitchBackToId = 0;
|
||||||
auto Updates = rpl::event_stream<>();
|
auto Updates = rpl::event_stream<>();
|
||||||
|
|
||||||
#if defined Q_OS_MAC && !defined OS_MAC_OLD
|
#if defined Q_OS_MAC && !defined OS_MAC_OLD
|
||||||
|
|
@ -138,7 +145,17 @@ int ReadCurrentSetId() {
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplyUniversalImages(std::shared_ptr<UniversalImages> images) {
|
||||||
|
Universal = std::move(images);
|
||||||
|
CanClearUniversal = false;
|
||||||
|
MainEmojiMap.clear();
|
||||||
|
OtherEmojiMap.clear();
|
||||||
|
Updates.fire({});
|
||||||
|
}
|
||||||
|
|
||||||
void SwitchToSetPrepared(int id, std::shared_ptr<UniversalImages> images) {
|
void SwitchToSetPrepared(int id, std::shared_ptr<UniversalImages> images) {
|
||||||
|
WaitingToSwitchBackToId = 0;
|
||||||
|
|
||||||
auto setting = QFile(CurrentSettingPath());
|
auto setting = QFile(CurrentSettingPath());
|
||||||
if (!id) {
|
if (!id) {
|
||||||
setting.remove();
|
setting.remove();
|
||||||
|
|
@ -147,11 +164,34 @@ void SwitchToSetPrepared(int id, std::shared_ptr<UniversalImages> images) {
|
||||||
stream.setVersion(QDataStream::Qt_5_1);
|
stream.setVersion(QDataStream::Qt_5_1);
|
||||||
stream << qint32(id);
|
stream << qint32(id);
|
||||||
}
|
}
|
||||||
Universal = std::move(images);
|
ApplyUniversalImages(std::move(images));
|
||||||
CanClearUniversal = false;
|
}
|
||||||
MainEmojiMap.clear();
|
|
||||||
OtherEmojiMap.clear();
|
[[nodiscard]] ConfigResult ValidateConfig(int id) {
|
||||||
Updates.fire({});
|
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() {
|
void ClearCurrentSetIdSync() {
|
||||||
|
|
@ -161,12 +201,14 @@ void ClearCurrentSetIdSync() {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QDir(internal::SetDataPath(id)).removeRecursively();
|
|
||||||
|
|
||||||
const auto newId = 0;
|
const auto newId = 0;
|
||||||
auto universal = std::make_shared<UniversalImages>(newId);
|
auto universal = std::make_shared<UniversalImages>(newId);
|
||||||
universal->ensureLoaded();
|
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) {
|
void SaveToFile(int id, const QImage &image, int size, int index) {
|
||||||
|
|
@ -288,37 +330,12 @@ std::vector<QImage> LoadSprites(int id) {
|
||||||
}) | ranges::to_vector;
|
}) | 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<QImage> LoadAndValidateSprites(int id) {
|
std::vector<QImage> LoadAndValidateSprites(int id) {
|
||||||
Expects(IsValidSetId(id));
|
Expects(IsValidSetId(id));
|
||||||
Expects(SpritesCount > 0);
|
Expects(SpritesCount > 0);
|
||||||
|
|
||||||
if (!ValidateConfig(id)) {
|
const auto config = ValidateConfig(id);
|
||||||
|
if (config != ConfigResult::Good) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto result = LoadSprites(id);
|
auto result = LoadSprites(id);
|
||||||
|
|
@ -526,6 +543,18 @@ int CurrentSetId() {
|
||||||
return Universal->id();
|
return Universal->id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int NeedToSwitchBackToId() {
|
||||||
|
return WaitingToSwitchBackToId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearNeedSwitchToId() {
|
||||||
|
if (!WaitingToSwitchBackToId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WaitingToSwitchBackToId = 0;
|
||||||
|
QFile(CurrentSettingPath()).remove();
|
||||||
|
}
|
||||||
|
|
||||||
void SwitchToSet(int id, Fn<void(bool)> callback) {
|
void SwitchToSet(int id, Fn<void(bool)> callback) {
|
||||||
Expects(IsValidSetId(id));
|
Expects(IsValidSetId(id));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,16 @@ void ClearIrrelevantCache();
|
||||||
// Thread safe, callback is called on main thread.
|
// Thread safe, callback is called on main thread.
|
||||||
void SwitchToSet(int id, Fn<void(bool)> callback);
|
void SwitchToSet(int id, Fn<void(bool)> callback);
|
||||||
|
|
||||||
int CurrentSetId();
|
[[nodiscard]] int CurrentSetId();
|
||||||
bool SetIsReady(int id);
|
[[nodiscard]] int NeedToSwitchBackToId();
|
||||||
rpl::producer<> Updated();
|
void ClearNeedSwitchToId();
|
||||||
|
[[nodiscard]] bool SetIsReady(int id);
|
||||||
|
[[nodiscard]] rpl::producer<> Updated();
|
||||||
|
|
||||||
int GetSizeNormal();
|
[[nodiscard]] int GetSizeNormal();
|
||||||
int GetSizeLarge();
|
[[nodiscard]] int GetSizeLarge();
|
||||||
#if defined Q_OS_MAC && !defined OS_MAC_OLD
|
#if defined Q_OS_MAC && !defined OS_MAC_OLD
|
||||||
int GetSizeTouchbar();
|
[[nodiscard]] int GetSizeTouchbar();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class One {
|
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.");
|
auto start = qstr("emoji://e.");
|
||||||
if (url.startsWith(start)) {
|
if (url.startsWith(start)) {
|
||||||
return internal::ByIndex(url.midRef(start.size()).toInt()); // skip emoji://e.
|
return internal::ByIndex(url.midRef(start.size()).toInt()); // skip emoji://e.
|
||||||
|
|
@ -121,21 +123,21 @@ inline EmojiPtr FromUrl(const QString &url) {
|
||||||
return nullptr;
|
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);
|
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);
|
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));
|
return Find(IdFromOldKey(oldKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int ColorIndexFromCode(uint32 code) {
|
[[nodiscard]] inline int ColorIndexFromCode(uint32 code) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 0xD83CDFFBU: return 1;
|
case 0xD83CDFFBU: return 1;
|
||||||
case 0xD83CDFFCU: return 2;
|
case 0xD83CDFFCU: return 2;
|
||||||
|
|
@ -146,7 +148,7 @@ inline int ColorIndexFromCode(uint32 code) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int ColorIndexFromOldKey(uint64 oldKey) {
|
[[nodiscard]] inline int ColorIndexFromOldKey(uint64 oldKey) {
|
||||||
return ColorIndexFromCode(uint32(oldKey & 0xFFFFFFFFLLU));
|
return ColorIndexFromCode(uint32(oldKey & 0xFFFFFFFFLLU));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,7 +177,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::shared_ptr<UniversalImages> &SourceImages();
|
[[nodiscard]] const std::shared_ptr<UniversalImages> &SourceImages();
|
||||||
void ClearSourceImages(const std::shared_ptr<UniversalImages> &images);
|
void ClearSourceImages(const std::shared_ptr<UniversalImages> &images);
|
||||||
|
|
||||||
} // namespace Emoji
|
} // namespace Emoji
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue