Add updating emoji on the run.

This commit is contained in:
John Preston 2018-12-10 17:26:53 +04:00
parent 8190b10680
commit 79fea49272
5 changed files with 115 additions and 21 deletions

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/popup_menu.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/shadow.h"
#include "ui/emoji_config.h"
#include "lang/lang_cloud_manager.h"
#include "lang/lang_instance.h"
#include "lang/lang_keys.h"
@ -93,6 +94,11 @@ MainWindow::MainWindow() {
updateGlobalMenu();
}, lifetime());
Ui::Emoji::Updated(
) | rpl::start_with_next([=] {
Ui::ForceFullRepaint(this);
}, lifetime());
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_OpaquePaintEvent);
}

View File

@ -29,6 +29,13 @@ constexpr auto kSetVersion = uint32(1);
constexpr auto kCacheVersion = uint32(3);
constexpr auto kMaxId = uint32(1 << 8);
const auto kSets = {
Set{ 0, 0, "Mac" },
Set{ 1, 205, "Android" },
Set{ 2, 206, "Twemoji" },
Set{ 3, 237, "EmojiOne" },
};
// 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.
@ -76,12 +83,13 @@ auto SizeNormal = -1;
auto SizeLarge = -1;
auto SpritesCount = -1;
std::unique_ptr<Instance> InstanceNormal;
std::unique_ptr<Instance> InstanceLarge;
std::shared_ptr<UniversalImages> Universal;
auto InstanceNormal = std::unique_ptr<Instance>();
auto InstanceLarge = std::unique_ptr<Instance>();
auto Universal = std::shared_ptr<UniversalImages>();
auto Updates = rpl::event_stream<>();
std::map<int, QPixmap> MainEmojiMap;
std::map<int, std::map<int, QPixmap>> OtherEmojiMap;
auto MainEmojiMap = std::map<int, QPixmap>();
auto OtherEmojiMap = std::map<int, std::map<int, QPixmap>>();
int RowsCount(int index) {
if (index + 1 < SpritesCount) {
@ -158,9 +166,8 @@ void ClearCurrentSetId() {
if (!id) {
return;
}
QFile(CurrentSettingPath()).remove();
QDir(SetDataPath(id)).removeRecursively();
Universal = std::make_shared<UniversalImages>(0);
SwitchToSet(0);
}
void SaveToFile(int id, const QImage &image, int size, int index) {
@ -510,6 +517,45 @@ void ClearIrrelevantCache() {
});
}
std::vector<Set> Sets() {
return kSets;
}
int CurrentSetId() {
Expects(Universal != nullptr);
return Universal->id();
}
bool SwitchToSet(int id) {
Expects(IsValidSetId(id));
if (Universal && Universal->id() == id) {
return true;
}
auto universal = std::make_shared<UniversalImages>(id);
if (!universal->ensureLoaded()) {
return false;
}
auto setting = QFile(CurrentSettingPath());
if (!id) {
setting.remove();
} else if (setting.open(QIODevice::WriteOnly)) {
auto stream = QDataStream(&setting);
stream.setVersion(QDataStream::Qt_5_1);
stream << qint32(id);
}
Universal = std::move(universal);
MainEmojiMap.clear();
OtherEmojiMap.clear();
Updates.fire({});
return true;
}
rpl::producer<> Updated() {
return Updates.events();
}
int GetSizeNormal() {
Expects(SizeNormal > 0);
@ -833,7 +879,6 @@ void Instance::checkUniversalImages() {
}
if (!Universal->ensureLoaded() && Universal->id() != 0) {
ClearCurrentSetId();
Universal->ensureLoaded();
}
}

View File

@ -20,6 +20,17 @@ void Clear();
void ClearIrrelevantCache();
struct Set {
int id = 0;
int postId = 0;
QString name;
};
std::vector<Set> Sets();
int CurrentSetId();
bool SwitchToSet(int id);
rpl::producer<> Updated();
int GetSizeNormal();
int GetSizeLarge();

View File

@ -45,6 +45,49 @@ const auto kClearFormatSequence = QKeySequence("ctrl+shift+n");
const auto kMonospaceSequence = QKeySequence("ctrl+shift+m");
const auto kEditLinkSequence = QKeySequence("ctrl+k");
class InputDocument : public QTextDocument {
public:
InputDocument(QObject *parent, const style::InputField &st);
protected:
QVariant loadResource(int type, const QUrl &name) override;
private:
const style::InputField &_st;
std::map<QUrl, QVariant> _emojiCache;
rpl::lifetime _lifetime;
};
InputDocument::InputDocument(QObject *parent, const style::InputField &st)
: QTextDocument(parent)
, _st(st) {
Ui::Emoji::Updated(
) | rpl::start_with_next([=] {
_emojiCache.clear();
}, _lifetime);
}
QVariant InputDocument::loadResource(int type, const QUrl &name) {
if (type != QTextDocument::ImageResource
|| name.scheme() != qstr("emoji")) {
return QTextDocument::loadResource(type, name);
}
const auto i = _emojiCache.find(name);
if (i != _emojiCache.end()) {
return i->second;
}
auto result = [&] {
if (const auto emoji = Ui::Emoji::FromUrl(name.toDisplayString())) {
const auto height = _st.font->height;
return QVariant(Ui::Emoji::SinglePixmap(emoji, height));
}
return QVariant();
}();
_emojiCache.emplace(name, result);
return result;
}
bool IsNewline(QChar ch) {
return (kNewlineChars.indexOf(ch) >= 0);
}
@ -727,10 +770,6 @@ public:
Inner(not_null<InputField*> parent) : QTextEdit(parent) {
}
QVariant loadResource(int type, const QUrl &name) override {
return outer()->loadResource(type, name);
}
protected:
bool viewportEvent(QEvent *e) override {
return outer()->viewportEventInner(e);
@ -1141,6 +1180,8 @@ InputField::InputField(
, _inner(std::make_unique<Inner>(this))
, _lastTextWithTags(value)
, _placeholderFactory(std::move(placeholderFactory)) {
_inner->setDocument(Ui::CreateChild<InputDocument>(_inner.get(), _st));
_inner->setAcceptRichText(false);
resize(_st.width, _minHeight);
@ -1233,14 +1274,6 @@ bool InputField::viewportEventInner(QEvent *e) {
return _inner->QTextEdit::viewportEvent(e);
}
QVariant InputField::loadResource(int type, const QUrl &name) {
const auto imageName = name.toDisplayString();
if (const auto emoji = Ui::Emoji::FromUrl(imageName)) {
return QVariant(Ui::Emoji::SinglePixmap(emoji, _st.font->height));
}
return _inner->QTextEdit::loadResource(type, name);
}
void InputField::updatePalette() {
auto p = _inner->palette();
p.setColor(QPalette::Text, _st.textFg->c);

View File

@ -341,7 +341,6 @@ private:
void handleContentsChanged();
bool viewportEventInner(QEvent *e);
QVariant loadResource(int type, const QUrl &name);
void handleTouchEvent(QTouchEvent *e);
void updatePalette();