Extract FieldAutocomplete code.

This commit is contained in:
John Preston
2024-09-13 17:39:15 +04:00
parent 969152e949
commit ba7cd25f21
10 changed files with 497 additions and 481 deletions
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/business/data_shortcut_messages.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_changes.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
@@ -202,12 +203,6 @@ struct FieldAutocomplete::BotCommandRow {
Ui::Text::String descriptionText;
};
FieldAutocomplete::FieldAutocomplete(
QWidget *parent,
not_null<Window::SessionController*> controller)
: FieldAutocomplete(parent, controller->uiShow()) {
}
FieldAutocomplete::FieldAutocomplete(
QWidget *parent,
std::shared_ptr<Show> show,
@@ -252,6 +247,22 @@ std::shared_ptr<Show> FieldAutocomplete::uiShow() const {
return _show;
}
void FieldAutocomplete::requestRefresh() {
_refreshRequests.fire({});
}
rpl::producer<> FieldAutocomplete::refreshRequests() const {
return _refreshRequests.events();
}
void FieldAutocomplete::requestStickersUpdate() {
_stickersUpdateRequests.fire({});
}
rpl::producer<> FieldAutocomplete::stickersUpdateRequests() const {
return _stickersUpdateRequests.events();
}
auto FieldAutocomplete::mentionChosen() const
-> rpl::producer<FieldAutocomplete::MentionChosen> {
return _inner->mentionChosen();
@@ -378,6 +389,10 @@ void FieldAutocomplete::showStickers(EmojiPtr emoji) {
updateFiltered(resetScroll);
}
EmojiPtr FieldAutocomplete::stickersEmoji() const {
return _emoji;
}
bool FieldAutocomplete::clearFilteredBotCommands() {
if (_brows.empty()) {
return false;
@@ -1634,4 +1649,165 @@ auto FieldAutocomplete::Inner::scrollToRequested() const
return _scrollToRequested.events();
}
void InitFieldAutocomplete(
std::unique_ptr<FieldAutocomplete> &autocomplete,
FieldAutocompleteDescriptor &&descriptor) {
Expects(!autocomplete);
autocomplete = std::make_unique<FieldAutocomplete>(
descriptor.parent,
descriptor.show,
descriptor.stOverride);
const auto raw = autocomplete.get();
const auto field = descriptor.field;
field->rawTextEdit()->installEventFilter(raw);
raw->mentionChosen(
) | rpl::start_with_next([=](FieldAutocomplete::MentionChosen data) {
const auto user = data.user;
if (data.mention.isEmpty()) {
field->insertTag(
user->firstName.isEmpty() ? user->name() : user->firstName,
PrepareMentionTag(user));
} else {
field->insertTag('@' + data.mention);
}
}, raw->lifetime());
const auto sendCommand = descriptor.sendBotCommand;
const auto setText = descriptor.setText;
raw->hashtagChosen(
) | rpl::start_with_next([=](FieldAutocomplete::HashtagChosen data) {
field->insertTag(data.hashtag);
}, raw->lifetime());
const auto peer = descriptor.peer;
const auto processShortcut = descriptor.processShortcut;
const auto shortcutMessages = (processShortcut != nullptr)
? &peer->owner().shortcutMessages()
: nullptr;
raw->botCommandChosen(
) | rpl::start_with_next([=](FieldAutocomplete::BotCommandChosen data) {
using Method = FieldAutocompleteChooseMethod;
const auto byTab = (data.method == Method::ByTab);
const auto shortcut = data.user->isSelf();
// Send bot command at once, if it was not inserted by pressing Tab.
if (byTab && data.command.size() > 1) {
field->insertTag(data.command);
} else if (!shortcut) {
sendCommand(data.command);
setText(
field->getTextWithTagsPart(field->textCursor().position()));
} else if (processShortcut) {
processShortcut(data.command.mid(1));
}
}, raw->lifetime());
raw->setModerateKeyActivateCallback(std::move(descriptor.moderateKeyActivateCallback));
const auto stickerChoosing = descriptor.stickerChoosing;
raw->choosingProcesses(
) | rpl::start_with_next([=](FieldAutocomplete::Type type) {
if (type == FieldAutocomplete::Type::Stickers) {
stickerChoosing();
}
}, raw->lifetime());
if (auto chosen = descriptor.stickerChosen) {
raw->stickerChosen(
) | rpl::start_with_next(std::move(chosen), raw->lifetime());
}
field->tabbed(
) | rpl::start_with_next([=] {
if (!raw->isHidden()) {
raw->chooseSelected(FieldAutocomplete::ChooseMethod::ByTab);
}
}, raw->lifetime());
const auto features = descriptor.features;
const auto check = [=] {
auto parsed = ParseMentionHashtagBotCommandQuery(field, features());
if (parsed.query.isEmpty()) {
} else if (parsed.query[0] == '#'
&& cRecentWriteHashtags().isEmpty()
&& cRecentSearchHashtags().isEmpty()) {
peer->session().local().readRecentHashtagsAndBots();
} else if (parsed.query[0] == '@'
&& cRecentInlineBots().isEmpty()) {
peer->session().local().readRecentHashtagsAndBots();
} else if (parsed.query[0] == '/'
&& peer->isUser()
&& !peer->asUser()->isBot()
&& (!shortcutMessages
|| shortcutMessages->shortcuts().list.empty())) {
parsed = {};
}
raw->showFiltered(peer, parsed.query, parsed.fromStart);
};
const auto updateStickersByEmoji = [=] {
const auto errorForStickers = Data::RestrictionError(
peer,
ChatRestriction::SendStickers);
if (features().suggestStickersByEmoji && !errorForStickers) {
const auto &text = field->getTextWithTags().text;
auto length = 0;
if (const auto emoji = Ui::Emoji::Find(text, &length)) {
if (text.size() <= length) {
raw->showStickers(emoji);
return;
}
}
}
raw->showStickers(nullptr);
};
raw->refreshRequests(
) | rpl::start_with_next(check, raw->lifetime());
raw->stickersUpdateRequests(
) | rpl::start_with_next(updateStickersByEmoji, raw->lifetime());
peer->owner().botCommandsChanges(
) | rpl::filter([=](not_null<PeerData*> changed) {
return (peer == changed);
}) | rpl::start_with_next([=] {
if (raw->clearFilteredBotCommands()) {
check();
}
}, raw->lifetime());
peer->owner().stickers().updated(
Data::StickersType::Stickers
) | rpl::start_with_next(updateStickersByEmoji, raw->lifetime());
QObject::connect(
field->rawTextEdit(),
&QTextEdit::cursorPositionChanged,
raw,
check,
Qt::QueuedConnection);
field->changes() | rpl::start_with_next(
updateStickersByEmoji,
raw->lifetime());
peer->session().changes().peerUpdates(
Data::PeerUpdate::Flag::Rights
) | rpl::filter([=](const Data::PeerUpdate &update) {
return (update.peer == peer);
}) | rpl::start_with_next(updateStickersByEmoji, raw->lifetime());
if (shortcutMessages) {
shortcutMessages->shortcutsChanged(
) | rpl::start_with_next(check, raw->lifetime());
}
raw->setSendMenuDetails(std::move(descriptor.sendMenuDetails));
raw->hideFast();
}
} // namespace ChatHelpers