mirror of https://github.com/procxx/kepka.git
Allow instant template selection (support).
This commit is contained in:
parent
ec49ff31ef
commit
e896971fa4
|
@ -40,7 +40,7 @@ AuthSessionSettings::Variables::Variables()
|
||||||
, floatPlayerColumn(Window::Column::Second)
|
, floatPlayerColumn(Window::Column::Second)
|
||||||
, floatPlayerCorner(RectPart::TopRight)
|
, floatPlayerCorner(RectPart::TopRight)
|
||||||
, sendSubmitWay(Ui::InputSubmitSettings::Enter)
|
, sendSubmitWay(Ui::InputSubmitSettings::Enter)
|
||||||
, supportSwitch(Support::SwitchSettings::None) {
|
, supportSwitch(Support::SwitchSettings::Next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray AuthSessionSettings::serialize() const {
|
QByteArray AuthSessionSettings::serialize() const {
|
||||||
|
@ -82,6 +82,7 @@ QByteArray AuthSessionSettings::serialize() const {
|
||||||
stream << qint32(_variables.sendSubmitWay);
|
stream << qint32(_variables.sendSubmitWay);
|
||||||
stream << qint32(_variables.supportSwitch);
|
stream << qint32(_variables.supportSwitch);
|
||||||
stream << qint32(_variables.supportFixChatsOrder ? 1 : 0);
|
stream << qint32(_variables.supportFixChatsOrder ? 1 : 0);
|
||||||
|
stream << qint32(_variables.supportTemplatesAutocomplete ? 1 : 0);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +112,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
|
||||||
qint32 sendSubmitWay = static_cast<qint32>(_variables.sendSubmitWay);
|
qint32 sendSubmitWay = static_cast<qint32>(_variables.sendSubmitWay);
|
||||||
qint32 supportSwitch = static_cast<qint32>(_variables.supportSwitch);
|
qint32 supportSwitch = static_cast<qint32>(_variables.supportSwitch);
|
||||||
qint32 supportFixChatsOrder = _variables.supportFixChatsOrder ? 1 : 0;
|
qint32 supportFixChatsOrder = _variables.supportFixChatsOrder ? 1 : 0;
|
||||||
|
qint32 supportTemplatesAutocomplete = _variables.supportTemplatesAutocomplete ? 1 : 0;
|
||||||
|
|
||||||
stream >> selectorTab;
|
stream >> selectorTab;
|
||||||
stream >> lastSeenWarningSeen;
|
stream >> lastSeenWarningSeen;
|
||||||
|
@ -171,6 +173,9 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
|
||||||
stream >> supportSwitch;
|
stream >> supportSwitch;
|
||||||
stream >> supportFixChatsOrder;
|
stream >> supportFixChatsOrder;
|
||||||
}
|
}
|
||||||
|
if (!stream.atEnd()) {
|
||||||
|
stream >> supportTemplatesAutocomplete;
|
||||||
|
}
|
||||||
if (stream.status() != QDataStream::Ok) {
|
if (stream.status() != QDataStream::Ok) {
|
||||||
LOG(("App Error: "
|
LOG(("App Error: "
|
||||||
"Bad data for AuthSessionSettings::constructFromSerialized()"));
|
"Bad data for AuthSessionSettings::constructFromSerialized()"));
|
||||||
|
@ -236,7 +241,8 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
|
||||||
case Support::SwitchSettings::Next:
|
case Support::SwitchSettings::Next:
|
||||||
case Support::SwitchSettings::Previous: _variables.supportSwitch = uncheckedSupportSwitch; break;
|
case Support::SwitchSettings::Previous: _variables.supportSwitch = uncheckedSupportSwitch; break;
|
||||||
}
|
}
|
||||||
_variables.supportFixChatsOrder = (supportFixChatsOrder ? 1 : 0);
|
_variables.supportFixChatsOrder = (supportFixChatsOrder == 1);
|
||||||
|
_variables.supportTemplatesAutocomplete = (supportTemplatesAutocomplete == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuthSessionSettings::setTabbedSelectorSectionEnabled(bool enabled) {
|
void AuthSessionSettings::setTabbedSelectorSectionEnabled(bool enabled) {
|
||||||
|
|
|
@ -96,6 +96,12 @@ public:
|
||||||
bool supportFixChatsOrder() const {
|
bool supportFixChatsOrder() const {
|
||||||
return _variables.supportFixChatsOrder;
|
return _variables.supportFixChatsOrder;
|
||||||
}
|
}
|
||||||
|
void setSupportTemplatesAutocomplete(bool enabled) {
|
||||||
|
_variables.supportTemplatesAutocomplete = enabled;
|
||||||
|
}
|
||||||
|
bool supportTemplatesAutocomplete() const {
|
||||||
|
return _variables.supportTemplatesAutocomplete;
|
||||||
|
}
|
||||||
|
|
||||||
ChatHelpers::SelectorTab selectorTab() const {
|
ChatHelpers::SelectorTab selectorTab() const {
|
||||||
return _variables.selectorTab;
|
return _variables.selectorTab;
|
||||||
|
@ -216,6 +222,7 @@ private:
|
||||||
|
|
||||||
Support::SwitchSettings supportSwitch;
|
Support::SwitchSettings supportSwitch;
|
||||||
bool supportFixChatsOrder = true;
|
bool supportFixChatsOrder = true;
|
||||||
|
bool supportTemplatesAutocomplete = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
rpl::event_stream<bool> _thirdSectionInfoEnabledValue;
|
rpl::event_stream<bool> _thirdSectionInfoEnabledValue;
|
||||||
|
|
|
@ -795,10 +795,7 @@ void HistoryWidget::supportShareContact(Support::Contact contact) {
|
||||||
if (!_history) {
|
if (!_history) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto commented = !contact.comment.isEmpty();
|
|
||||||
if (commented) {
|
|
||||||
supportInsertText(contact.comment);
|
supportInsertText(contact.comment);
|
||||||
}
|
|
||||||
contact.comment = _field->getLastText();
|
contact.comment = _field->getLastText();
|
||||||
|
|
||||||
const auto submit = [=](Qt::KeyboardModifiers modifiers) {
|
const auto submit = [=](Qt::KeyboardModifiers modifiers) {
|
||||||
|
@ -5522,7 +5519,7 @@ void HistoryWidget::replyToNextMessage() {
|
||||||
|
|
||||||
void HistoryWidget::onFieldTabbed() {
|
void HistoryWidget::onFieldTabbed() {
|
||||||
if (_supportAutocomplete) {
|
if (_supportAutocomplete) {
|
||||||
_supportAutocomplete->activate();
|
_supportAutocomplete->activate(_field.data());
|
||||||
} else if (!_fieldAutocomplete->isHidden()) {
|
} else if (!_fieldAutocomplete->isHidden()) {
|
||||||
_fieldAutocomplete->chooseSelected(FieldAutocomplete::ChooseMethod::ByTab);
|
_fieldAutocomplete->chooseSelected(FieldAutocomplete::ChooseMethod::ByTab);
|
||||||
}
|
}
|
||||||
|
|
|
@ -946,6 +946,23 @@ void SetupSupport(not_null<Ui::VerticalLayout*> container) {
|
||||||
});
|
});
|
||||||
|
|
||||||
AddSkip(inner, st::settingsCheckboxesSkip);
|
AddSkip(inner, st::settingsCheckboxesSkip);
|
||||||
|
|
||||||
|
base::ObservableViewer(
|
||||||
|
inner->add(
|
||||||
|
object_ptr<Ui::Checkbox>(
|
||||||
|
inner,
|
||||||
|
"Enable templates autocomplete",
|
||||||
|
Auth().settings().supportTemplatesAutocomplete(),
|
||||||
|
st::settingsCheckbox),
|
||||||
|
st::settingsSendTypePadding
|
||||||
|
)->checkedChanged
|
||||||
|
) | rpl::start_with_next([=](bool checked) {
|
||||||
|
Auth().settings().setSupportTemplatesAutocomplete(checked);
|
||||||
|
Local::writeUserSettings();
|
||||||
|
}, inner->lifetime());
|
||||||
|
|
||||||
|
AddSkip(inner, st::settingsCheckboxesSkip);
|
||||||
|
AddSkip(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat::Chat(QWidget *parent, not_null<UserData*> self)
|
Chat::Chat(QWidget *parent, not_null<UserData*> self)
|
||||||
|
|
|
@ -84,6 +84,7 @@ bool PrepareAlbumMediaIsWaiting(
|
||||||
std::min(previewWidth, convertScale(image->data.width()))
|
std::min(previewWidth, convertScale(image->data.width()))
|
||||||
* cIntRetinaFactor(),
|
* cIntRetinaFactor(),
|
||||||
Qt::SmoothTransformation));
|
Qt::SmoothTransformation));
|
||||||
|
Assert(!file.preview.isNull());
|
||||||
file.preview.setDevicePixelRatio(cRetinaFactor());
|
file.preview.setDevicePixelRatio(cRetinaFactor());
|
||||||
file.type = PreparedFile::AlbumType::Photo;
|
file.type = PreparedFile::AlbumType::Photo;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +96,7 @@ bool PrepareAlbumMediaIsWaiting(
|
||||||
file.preview = std::move(blurred).scaledToWidth(
|
file.preview = std::move(blurred).scaledToWidth(
|
||||||
previewWidth * cIntRetinaFactor(),
|
previewWidth * cIntRetinaFactor(),
|
||||||
Qt::SmoothTransformation);
|
Qt::SmoothTransformation);
|
||||||
|
Assert(!file.preview.isNull());
|
||||||
file.preview.setDevicePixelRatio(cRetinaFactor());
|
file.preview.setDevicePixelRatio(cRetinaFactor());
|
||||||
file.type = PreparedFile::AlbumType::Video;
|
file.type = PreparedFile::AlbumType::Video;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ private:
|
||||||
int _selected = -1;
|
int _selected = -1;
|
||||||
int _pressed = -1;
|
int _pressed = -1;
|
||||||
bool _selectByKeys = false;
|
bool _selectByKeys = false;
|
||||||
rpl::event_stream<Qt::KeyboardModifiers> _activated;
|
rpl::event_stream<> _activated;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ void Inner::mousePressEvent(QMouseEvent *e) {
|
||||||
void Inner::mouseReleaseEvent(QMouseEvent *e) {
|
void Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
const auto pressed = base::take(_pressed);
|
const auto pressed = base::take(_pressed);
|
||||||
if (pressed == _selected && pressed >= 0) {
|
if (pressed == _selected && pressed >= 0) {
|
||||||
_activated.fire(e->modifiers());
|
_activated.fire({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,8 +327,34 @@ Autocomplete::Autocomplete(QWidget *parent, not_null<AuthSession*> session)
|
||||||
setupContent();
|
setupContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Autocomplete::activate() {
|
void Autocomplete::activate(not_null<Ui::InputField*> field) {
|
||||||
|
if (Auth().settings().supportTemplatesAutocomplete()) {
|
||||||
_activate();
|
_activate();
|
||||||
|
} else {
|
||||||
|
const auto templates = Auth().supportTemplates();
|
||||||
|
const auto max = templates->maxKeyLength();
|
||||||
|
auto cursor = field->textCursor();
|
||||||
|
const auto position = cursor.position();
|
||||||
|
const auto anchor = cursor.anchor();
|
||||||
|
const auto text = (position != anchor)
|
||||||
|
? field->getTextWithTagsPart(
|
||||||
|
std::min(position, anchor),
|
||||||
|
std::max(position, anchor))
|
||||||
|
: field->getTextWithTagsPart(
|
||||||
|
std::max(position - max, 0),
|
||||||
|
position);
|
||||||
|
const auto result = (position != anchor)
|
||||||
|
? templates->matchExact(text.text)
|
||||||
|
: templates->matchFromEnd(text.text);
|
||||||
|
if (result) {
|
||||||
|
const auto till = std::max(position, anchor);
|
||||||
|
const auto from = till - result->key.size();
|
||||||
|
cursor.setPosition(from);
|
||||||
|
cursor.setPosition(till, QTextCursor::KeepAnchor);
|
||||||
|
field->setTextCursor(cursor);
|
||||||
|
submitValue(result->question.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Autocomplete::deactivate() {
|
void Autocomplete::deactivate() {
|
||||||
|
@ -376,9 +402,9 @@ void Autocomplete::setupContent() {
|
||||||
|
|
||||||
const auto inner = scroll->setOwnedWidget(object_ptr<Inner>(scroll));
|
const auto inner = scroll->setOwnedWidget(object_ptr<Inner>(scroll));
|
||||||
|
|
||||||
const auto submit = [=](Qt::KeyboardModifiers modifiers) {
|
const auto submit = [=] {
|
||||||
if (const auto question = inner->selected()) {
|
if (const auto question = inner->selected()) {
|
||||||
submitValue(question->value, modifiers);
|
submitValue(question->value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -440,9 +466,7 @@ void Autocomplete::setupContent() {
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Autocomplete::submitValue(
|
void Autocomplete::submitValue(const QString &value) {
|
||||||
const QString &value,
|
|
||||||
Qt::KeyboardModifiers modifiers) {
|
|
||||||
const auto prefix = qstr("contact:");
|
const auto prefix = qstr("contact:");
|
||||||
if (value.startsWith(prefix)) {
|
if (value.startsWith(prefix)) {
|
||||||
const auto line = value.indexOf('\n');
|
const auto line = value.indexOf('\n');
|
||||||
|
@ -462,8 +486,7 @@ void Autocomplete::submitValue(
|
||||||
text,
|
text,
|
||||||
phone,
|
phone,
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName });
|
||||||
HandleSwitch(modifiers) });
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_insertRequests.fire_copy(value);
|
_insertRequests.fire_copy(value);
|
||||||
|
|
|
@ -17,6 +17,7 @@ class AuthSession;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
|
class InputField;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Support {
|
namespace Support {
|
||||||
|
@ -26,14 +27,13 @@ struct Contact {
|
||||||
QString phone;
|
QString phone;
|
||||||
QString firstName;
|
QString firstName;
|
||||||
QString lastName;
|
QString lastName;
|
||||||
bool handleSwitch = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Autocomplete : public Ui::RpWidget {
|
class Autocomplete : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
Autocomplete(QWidget *parent, not_null<AuthSession*> session);
|
Autocomplete(QWidget *parent, not_null<AuthSession*> session);
|
||||||
|
|
||||||
void activate();
|
void activate(not_null<Ui::InputField*> field);
|
||||||
void deactivate();
|
void deactivate();
|
||||||
void setBoundings(QRect rect);
|
void setBoundings(QRect rect);
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupContent();
|
void setupContent();
|
||||||
void submitValue(const QString &value, Qt::KeyboardModifiers modifiers);
|
void submitValue(const QString &value);
|
||||||
|
|
||||||
not_null<AuthSession*> _session;
|
not_null<AuthSession*> _session;
|
||||||
Fn<void()> _activate;
|
Fn<void()> _activate;
|
||||||
|
|
|
@ -416,9 +416,27 @@ QString UpdateFile(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CountMaxKeyLength(const TemplatesData &data) {
|
||||||
|
auto result = 0;
|
||||||
|
for (const auto &[path, file] : data.files) {
|
||||||
|
for (const auto &[normalized, question] : file.questions) {
|
||||||
|
for (const auto &key : question.keys) {
|
||||||
|
accumulate_max(result, key.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString NormalizeKey(const QString &query) {
|
||||||
|
return TextUtilities::RemoveAccents(query.trimmed().toLower());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
|
using namespace details;
|
||||||
|
|
||||||
struct Templates::Updates {
|
struct Templates::Updates {
|
||||||
QNetworkAccessManager manager;
|
QNetworkAccessManager manager;
|
||||||
std::map<QString, QNetworkReply*> requests;
|
std::map<QString, QNetworkReply*> requests;
|
||||||
|
@ -439,8 +457,8 @@ void Templates::reload() {
|
||||||
auto[left, right] = base::make_binary_guard();
|
auto[left, right] = base::make_binary_guard();
|
||||||
_reading = std::move(left);
|
_reading = std::move(left);
|
||||||
crl::async([=, guard = std::move(right)]() mutable {
|
crl::async([=, guard = std::move(right)]() mutable {
|
||||||
auto result = details::ReadFiles(cWorkingDir() + "TEMPLATES");
|
auto result = ReadFiles(cWorkingDir() + "TEMPLATES");
|
||||||
result.index = details::ComputeIndex(result.result);
|
result.index = ComputeIndex(result.result);
|
||||||
crl::on_main([
|
crl::on_main([
|
||||||
=,
|
=,
|
||||||
result = std::move(result),
|
result = std::move(result),
|
||||||
|
@ -449,7 +467,7 @@ void Templates::reload() {
|
||||||
if (!guard.alive()) {
|
if (!guard.alive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_data = std::move(result.result);
|
setData(std::move(result.result));
|
||||||
_index = std::move(result.index);
|
_index = std::move(result.index);
|
||||||
_errors.fire(std::move(result.errors));
|
_errors.fire(std::move(result.errors));
|
||||||
crl::on_main(this, [=] {
|
crl::on_main(this, [=] {
|
||||||
|
@ -463,6 +481,11 @@ void Templates::reload() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Templates::setData(TemplatesData &&data) {
|
||||||
|
_data = std::move(data);
|
||||||
|
_maxKeyLength = CountMaxKeyLength(_data);
|
||||||
|
}
|
||||||
|
|
||||||
void Templates::ensureUpdatesCreated() {
|
void Templates::ensureUpdatesCreated() {
|
||||||
if (_updates) {
|
if (_updates) {
|
||||||
return;
|
return;
|
||||||
|
@ -521,10 +544,10 @@ void Templates::updateRequestFinished(QNetworkReply *reply) {
|
||||||
).arg(reply->url().toDisplayString()));
|
).arg(reply->url().toDisplayString()));
|
||||||
const auto content = reply->readAll();
|
const auto content = reply->readAll();
|
||||||
crl::async([=, weak = base::make_weak(this)]{
|
crl::async([=, weak = base::make_weak(this)]{
|
||||||
auto result = details::ReadFromBlob(content);
|
auto result = ReadFromBlob(content);
|
||||||
auto one = details::TemplatesData();
|
auto one = TemplatesData();
|
||||||
one.files.emplace(path, std::move(result.result));
|
one.files.emplace(path, std::move(result.result));
|
||||||
auto index = details::ComputeIndex(one);
|
auto index = ComputeIndex(one);
|
||||||
crl::on_main(weak,[
|
crl::on_main(weak,[
|
||||||
=,
|
=,
|
||||||
one = std::move(one),
|
one = std::move(one),
|
||||||
|
@ -533,16 +556,16 @@ void Templates::updateRequestFinished(QNetworkReply *reply) {
|
||||||
]() mutable {
|
]() mutable {
|
||||||
auto &existing = _data.files.at(path);
|
auto &existing = _data.files.at(path);
|
||||||
auto &parsed = one.files.at(path);
|
auto &parsed = one.files.at(path);
|
||||||
details::MoveKeys(parsed, existing);
|
MoveKeys(parsed, existing);
|
||||||
details::ReplaceFileIndex(_index, details::ComputeIndex(one), path);
|
ReplaceFileIndex(_index, ComputeIndex(one), path);
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
_errors.fire(std::move(errors));
|
_errors.fire(std::move(errors));
|
||||||
}
|
}
|
||||||
if (const auto delta = details::ComputeDelta(existing, parsed)) {
|
if (const auto delta = ComputeDelta(existing, parsed)) {
|
||||||
const auto text = details::FormatUpdateNotification(
|
const auto text = FormatUpdateNotification(
|
||||||
path,
|
path,
|
||||||
delta);
|
delta);
|
||||||
const auto copy = details::UpdateFile(
|
const auto copy = UpdateFile(
|
||||||
path,
|
path,
|
||||||
content,
|
content,
|
||||||
existing.url,
|
existing.url,
|
||||||
|
@ -568,6 +591,54 @@ void Templates::checkUpdateFinished() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Templates::matchExact(QString query) const
|
||||||
|
-> std::optional<QuestionByKey> {
|
||||||
|
if (query.isEmpty() || query.size() > _maxKeyLength) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
query = NormalizeKey(query);
|
||||||
|
|
||||||
|
for (const auto &[path, file] : _data.files) {
|
||||||
|
for (const auto &[normalized, question] : file.questions) {
|
||||||
|
for (const auto &key : question.keys) {
|
||||||
|
if (key == query) {
|
||||||
|
return QuestionByKey{ question, key };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Templates::matchFromEnd(QString query) const
|
||||||
|
-> std::optional<QuestionByKey> {
|
||||||
|
if (query.size() > _maxKeyLength) {
|
||||||
|
query = query.mid(query.size() - _maxKeyLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto size = query.size();
|
||||||
|
auto queries = std::vector<QString>();
|
||||||
|
queries.reserve(size);
|
||||||
|
for (auto i = 0; i != size; ++i) {
|
||||||
|
queries.push_back(NormalizeKey(query.mid(size - i - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = std::optional<QuestionByKey>();
|
||||||
|
for (const auto &[path, file] : _data.files) {
|
||||||
|
for (const auto &[normalized, question] : file.questions) {
|
||||||
|
for (const auto &key : question.keys) {
|
||||||
|
if (key.size() <= queries.size()
|
||||||
|
&& queries[key.size() - 1] == key
|
||||||
|
&& (!result || result->key.size() < key.size())) {
|
||||||
|
result = QuestionByKey{ question, key };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Templates::~Templates() = default;
|
Templates::~Templates() = default;
|
||||||
|
|
||||||
auto Templates::query(const QString &text) const -> std::vector<Question> {
|
auto Templates::query(const QString &text) const -> std::vector<Question> {
|
||||||
|
@ -584,8 +655,8 @@ auto Templates::query(const QString &text) const -> std::vector<Question> {
|
||||||
if (narrowed == end(_index.first)) {
|
if (narrowed == end(_index.first)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
using Id = details::TemplatesIndex::Id;
|
using Id = TemplatesIndex::Id;
|
||||||
using Term = details::TemplatesIndex::Term;
|
using Term = TemplatesIndex::Term;
|
||||||
const auto questionById = [&](const Id &id) {
|
const auto questionById = [&](const Id &id) {
|
||||||
return _data.files.at(id.first).questions.at(id.second);
|
return _data.files.at(id.first).questions.at(id.second);
|
||||||
};
|
};
|
||||||
|
@ -632,7 +703,7 @@ auto Templates::query(const QString &text) const -> std::vector<Question> {
|
||||||
);
|
);
|
||||||
return good | ranges::view::transform([](const Pair &pair) {
|
return good | ranges::view::transform([](const Pair &pair) {
|
||||||
return pair.first;
|
return pair.first;
|
||||||
}) | ranges::view::take(details::kQueryLimit) | ranges::to_vector;
|
}) | ranges::view::take(kQueryLimit) | ranges::to_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Support
|
} // namespace Support
|
||||||
|
|
|
@ -52,6 +52,16 @@ public:
|
||||||
return _errors.events();
|
return _errors.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct QuestionByKey {
|
||||||
|
Question question;
|
||||||
|
QString key;
|
||||||
|
};
|
||||||
|
std::optional<QuestionByKey> matchExact(QString text) const;
|
||||||
|
std::optional<QuestionByKey> matchFromEnd(QString text) const;
|
||||||
|
int maxKeyLength() const {
|
||||||
|
return _maxKeyLength;
|
||||||
|
}
|
||||||
|
|
||||||
~Templates();
|
~Templates();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -61,6 +71,7 @@ private:
|
||||||
void ensureUpdatesCreated();
|
void ensureUpdatesCreated();
|
||||||
void updateRequestFinished(QNetworkReply *reply);
|
void updateRequestFinished(QNetworkReply *reply);
|
||||||
void checkUpdateFinished();
|
void checkUpdateFinished();
|
||||||
|
void setData(details::TemplatesData &&data);
|
||||||
|
|
||||||
not_null<AuthSession*> _session;
|
not_null<AuthSession*> _session;
|
||||||
|
|
||||||
|
@ -70,6 +81,8 @@ private:
|
||||||
base::binary_guard _reading;
|
base::binary_guard _reading;
|
||||||
bool _reloadAfterRead = false;
|
bool _reloadAfterRead = false;
|
||||||
|
|
||||||
|
int _maxKeyLength = 0;
|
||||||
|
|
||||||
std::unique_ptr<Updates> _updates;
|
std::unique_ptr<Updates> _updates;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue