Fix crash in emoji keywords init.

This commit is contained in:
John Preston 2019-03-29 16:21:11 +04:00
parent dba677dcc7
commit 817e9aa43d
3 changed files with 45 additions and 16 deletions

View File

@ -20,6 +20,7 @@ namespace ChatHelpers {
namespace { namespace {
constexpr auto kRefreshEach = 60 * 60 * crl::time(1000); // 1 hour. constexpr auto kRefreshEach = 60 * 60 * crl::time(1000); // 1 hour.
constexpr auto kKeepNotUsedLangPacksCount = 10;
using namespace Ui::Emoji; using namespace Ui::Emoji;
@ -208,6 +209,8 @@ public:
LangPack &operator=(const LangPack &other) = delete; LangPack &operator=(const LangPack &other) = delete;
~LangPack(); ~LangPack();
[[nodiscard]] QString id() const;
void refresh(); void refresh();
void apiChanged(); void apiChanged();
@ -270,6 +273,10 @@ void EmojiKeywords::LangPack::readLocalCache() {
}); });
} }
QString EmojiKeywords::LangPack::id() const {
return _id;
}
void EmojiKeywords::LangPack::refresh() { void EmojiKeywords::LangPack::refresh() {
if (_state != State::Refreshed) { if (_state != State::Refreshed) {
return; return;
@ -417,14 +424,16 @@ void EmojiKeywords::handleAuthSessionChanges() {
void EmojiKeywords::apiChanged(ApiWrap *api) { void EmojiKeywords::apiChanged(ApiWrap *api) {
_api = api; _api = api;
if (_api) { if (_api) {
base::ObservableViewer( crl::on_main(&Auth(), crl::guard(&_guard, [=] {
Lang::CurrentCloudManager().firstLanguageSuggestion() base::ObservableViewer(
) | rpl::filter([=] { Lang::CurrentCloudManager().firstLanguageSuggestion()
// Refresh with the suggested language if we already were asked. ) | rpl::filter([=] {
return !_data.empty(); // Refresh with the suggested language if we already were asked.
}) | rpl::start_with_next([=] { return !_data.empty();
refresh(); }) | rpl::start_with_next([=] {
}, _suggestedChangeLifetime); refresh();
}, _suggestedChangeLifetime);
}));
} else { } else {
_langsRequestId = 0; _langsRequestId = 0;
_suggestedChangeLifetime.destroy(); _suggestedChangeLifetime.destroy();
@ -452,6 +461,9 @@ std::vector<Result> EmojiKeywords::query(
const QString &query, const QString &query,
bool exact) const { bool exact) const {
const auto normalized = NormalizeQuery(query); const auto normalized = NormalizeQuery(query);
if (normalized.isEmpty()) {
return {};
}
auto result = std::vector<Result>(); auto result = std::vector<Result>();
for (const auto &[language, item] : _data) { for (const auto &[language, item] : _data) {
const auto oldcount = result.size(); const auto oldcount = result.size();
@ -514,6 +526,10 @@ void EmojiKeywords::setRemoteList(std::vector<QString> &&list) {
if (ranges::find(_remoteList, i->first) != end(_remoteList)) { if (ranges::find(_remoteList, i->first) != end(_remoteList)) {
++i; ++i;
} else { } else {
if (_notUsedData.size() > kKeepNotUsedLangPacksCount) {
_notUsedData.pop_front();
}
_notUsedData.push_back(std::move(i->second));
i = _data.erase(i); i = _data.erase(i);
} }
} }
@ -524,6 +540,15 @@ void EmojiKeywords::refreshFromRemoteList() {
for (const auto &id : _remoteList) { for (const auto &id : _remoteList) {
if (const auto i = _data.find(id); i != end(_data)) { if (const auto i = _data.find(id); i != end(_data)) {
i->second->refresh(); i->second->refresh();
continue;
}
const auto i = ranges::find(
_notUsedData,
id,
[](const std::unique_ptr<LangPack> &p) { return p->id(); });
if (i != end(_notUsedData)) {
_data.emplace(id, std::move(*i));
_notUsedData.erase(i);
} else { } else {
_data.emplace( _data.emplace(
id, id,

View File

@ -62,6 +62,7 @@ private:
std::vector<QString> _remoteList; std::vector<QString> _remoteList;
mtpRequestId _langsRequestId = 0; mtpRequestId _langsRequestId = 0;
base::flat_map<QString, std::unique_ptr<LangPack>> _data; base::flat_map<QString, std::unique_ptr<LangPack>> _data;
std::deque<std::unique_ptr<LangPack>> _notUsedData;
rpl::event_stream<> _refreshed; rpl::event_stream<> _refreshed;
rpl::lifetime _suggestedChangeLifetime; rpl::lifetime _suggestedChangeLifetime;

View File

@ -112,7 +112,7 @@ std::vector<SuggestionsWidget::Row> SuggestionsWidget::getRowsByQuery() const {
return result; return result;
} }
auto suggestions = std::vector<Row>(); auto suggestions = std::vector<Row>();
const auto results = Core::App().emojiKeywords().query(_query.mid(1)); const auto results = Core::App().emojiKeywords().query(_query);
for (const auto &result : results) { for (const auto &result : results) {
suggestions.emplace_back( suggestions.emplace_back(
result.emoji, result.emoji,
@ -475,13 +475,13 @@ QString SuggestionsController::getEmojiQuery() {
return QString(); return QString();
} }
auto cursor = _field->textCursor(); const auto cursor = _field->textCursor();
if (cursor.hasSelection()) { if (cursor.hasSelection()) {
return QString(); return QString();
} }
auto position = cursor.position(); const auto position = cursor.position();
auto findTextPart = [this, &position] { const auto findTextPart = [&] {
auto document = _field->document(); auto document = _field->document();
auto block = document->findBlock(position); auto block = document->findBlock(position);
for (auto i = block.begin(); !i.atEnd(); ++i) { for (auto i = block.begin(); !i.atEnd(); ++i) {
@ -496,18 +496,21 @@ QString SuggestionsController::getEmojiQuery() {
if (fragment.charFormat().isImageFormat()) { if (fragment.charFormat().isImageFormat()) {
continue; continue;
} }
position -= from;
_queryStartPosition = from; _queryStartPosition = from;
return fragment.text(); return fragment.text();
} }
return QString(); return QString();
}; };
auto text = findTextPart(); const auto text = findTextPart();
if (text.isEmpty()) { if (text.isEmpty()) {
return QString(); return QString();
} }
for (auto i = position - _queryStartPosition; i != 0;) {
if (text[--i] == ':') {
return text.mid(i + 1);
}
}
const auto isUpperCaseLetter = [](QChar ch) { const auto isUpperCaseLetter = [](QChar ch) {
return (ch >= 'A' && ch <= 'Z'); return (ch >= 'A' && ch <= 'Z');
}; };
@ -568,7 +571,7 @@ QString SuggestionsController::getEmojiQuery() {
} }
void SuggestionsController::replaceCurrent(const QString &replacement) { void SuggestionsController::replaceCurrent(const QString &replacement) {
auto suggestion = getEmojiQuery(); const auto suggestion = getEmojiQuery();
if (suggestion.isEmpty()) { if (suggestion.isEmpty()) {
_suggestions->showWithQuery(QString()); _suggestions->showWithQuery(QString());
} else { } else {