Suggest animated emoji in Saved Messages.

This commit is contained in:
John Preston 2022-08-02 19:23:06 +03:00
parent 2319278c92
commit 59903b0b1c
7 changed files with 67 additions and 41 deletions

View file

@ -244,15 +244,19 @@ void EditCaptionBox::rebuildPreview() {
void EditCaptionBox::setupField() { void EditCaptionBox::setupField() {
const auto peer = _historyItem->history()->peer; const auto peer = _historyItem->history()->peer;
const auto allow = [=](const auto&) {
return Data::AllowEmojiWithoutPremium(peer);
};
InitMessageFieldHandlers( InitMessageFieldHandlers(
_controller, _controller,
_field.get(), _field.get(),
Window::GifPauseReason::Layer, Window::GifPauseReason::Layer,
[=](const auto&) { return Data::AllowEmojiWithoutPremium(peer); }); allow);
Ui::Emoji::SuggestionsController::Init( Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(), getDelegate()->outerContainer(),
_field, _field,
&_controller->session()); &_controller->session(),
{ .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow });
_field->setSubmitSettings( _field->setSubmitSettings(
Core::App().settings().sendSubmitWay()); Core::App().settings().sendSubmitWay());

View file

@ -674,15 +674,19 @@ void SendFilesBox::updateSendWayControlsVisibility() {
} }
void SendFilesBox::setupCaption() { void SendFilesBox::setupCaption() {
const auto allow = [=](const auto&) {
return _allowEmojiWithoutPremium;
};
InitMessageFieldHandlers( InitMessageFieldHandlers(
_controller, _controller,
_caption.data(), _caption.data(),
Window::GifPauseReason::Layer, Window::GifPauseReason::Layer,
[=](const auto&) { return _allowEmojiWithoutPremium; }); allow);
Ui::Emoji::SuggestionsController::Init( Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(), getDelegate()->outerContainer(),
_caption, _caption,
&_controller->session()); &_controller->session(),
{ .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow });
_caption->setSubmitSettings( _caption->setSubmitSettings(
Core::App().settings().sendSubmitWay()); Core::App().settings().sendSubmitWay());

View file

@ -299,7 +299,8 @@ void ShareBox::prepare() {
Ui::Emoji::SuggestionsController::Init( Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(), getDelegate()->outerContainer(),
_comment->entity(), _comment->entity(),
_descriptor.session); _descriptor.session,
{ .suggestCustomEmoji = true });
_select->raise(); _select->raise();
} }

View file

@ -43,9 +43,13 @@ constexpr auto kAnimationDuration = crl::time(120);
SuggestionsWidget::SuggestionsWidget( SuggestionsWidget::SuggestionsWidget(
QWidget *parent, QWidget *parent,
not_null<Main::Session*> session) not_null<Main::Session*> session,
bool suggestCustomEmoji,
Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium)
: RpWidget(parent) : RpWidget(parent)
, _session(session) , _session(session)
, _suggestCustomEmoji(suggestCustomEmoji)
, _allowCustomWithoutPremium(std::move(allowCustomWithoutPremium))
, _oneWidth(st::emojiSuggestionSize) , _oneWidth(st::emojiSuggestionSize)
, _padding(st::emojiSuggestionsPadding) { , _padding(st::emojiSuggestionsPadding) {
resize( resize(
@ -71,11 +75,11 @@ void SuggestionsWidget::showWithQuery(SuggestionsQuery query, bool force) {
_query = query; _query = query;
auto rows = [&] { auto rows = [&] {
if (const auto emoji = std::get_if<EmojiPtr>(&query)) { if (const auto emoji = std::get_if<EmojiPtr>(&query)) {
return prependCustom( return appendCustom(
{}, {},
lookupCustom({ Row(*emoji, (*emoji)->text()) })); lookupCustom({ Row(*emoji, (*emoji)->text()) }));
} }
return prependCustom(getRowsByQuery(v::get<QString>(query))); return appendCustom(getRowsByQuery(v::get<QString>(query)));
}(); }();
if (rows.empty()) { if (rows.empty()) {
_toggleAnimated.fire(false); _toggleAnimated.fire(false);
@ -99,15 +103,15 @@ void SuggestionsWidget::selectFirstResult() {
} }
} }
auto SuggestionsWidget::prependCustom(std::vector<Row> rows) auto SuggestionsWidget::appendCustom(std::vector<Row> rows)
-> std::vector<Row> { -> std::vector<Row> {
const auto custom = lookupCustom(rows); const auto custom = lookupCustom(rows);
return prependCustom(std::move(rows), custom); return appendCustom(std::move(rows), custom);
} }
auto SuggestionsWidget::lookupCustom(const std::vector<Row> &rows) const auto SuggestionsWidget::lookupCustom(const std::vector<Row> &rows) const
-> base::flat_multi_map<int, Custom> { -> base::flat_multi_map<int, Custom> {
if (rows.empty()) { if (rows.empty() || !_suggestCustomEmoji) {
return {}; return {};
} }
auto custom = base::flat_multi_map<int, Custom>(); auto custom = base::flat_multi_map<int, Custom>();
@ -119,20 +123,25 @@ auto SuggestionsWidget::lookupCustom(const std::vector<Row> &rows) const
continue; continue;
} }
for (const auto &document : i->second->stickers) { for (const auto &document : i->second->stickers) {
if (!premium && document->isPremiumEmoji()) { if (!premium
&& document->isPremiumEmoji()
&& (!_allowCustomWithoutPremium
|| !_allowCustomWithoutPremium(document))) {
// Skip the whole premium emoji set. // Skip the whole premium emoji set.
break; break;
} }
if (const auto sticker = document->sticker()) { if (const auto sticker = document->sticker()) {
if (const auto emoji = Ui::Emoji::Find(sticker->alt)) { if (const auto emoji = Ui::Emoji::Find(sticker->alt)) {
const auto j = ranges::find( const auto original = emoji->original();
const auto j = ranges::find_if(
rows, rows,
not_null{ emoji }, [&](const Row &row) {
&Row::emoji); return row.emoji->original() == original;
});
if (j != end(rows)) { if (j != end(rows)) {
custom.emplace(int(j - begin(rows)), Custom{ custom.emplace(int(j - begin(rows)), Custom{
.document = document, .document = document,
.emoji = j->emoji, .emoji = emoji,
.replacement = j->replacement, .replacement = j->replacement,
}); });
} }
@ -143,24 +152,17 @@ auto SuggestionsWidget::lookupCustom(const std::vector<Row> &rows) const
return custom; return custom;
} }
auto SuggestionsWidget::prependCustom( auto SuggestionsWidget::appendCustom(
std::vector<Row> rows, std::vector<Row> rows,
const base::flat_multi_map<int, Custom> &custom) const base::flat_multi_map<int, Custom> &custom)
-> std::vector<Row> { -> std::vector<Row> {
if (custom.empty()) { rows.reserve(rows.size() + custom.size());
return rows;
}
auto result = std::vector<Row>();
result.reserve(custom.size() + rows.size());
for (const auto &[position, one] : custom) { for (const auto &[position, one] : custom) {
result.push_back(Row(one.emoji, one.replacement)); rows.push_back(Row(one.emoji, one.replacement));
result.back().document = one.document; rows.back().document = one.document;
result.back().custom = resolveCustomEmoji(one.document); rows.back().custom = resolveCustomEmoji(one.document);
} }
for (auto &row : rows) { return rows;
result.push_back(std::move(row));
}
return result;
} }
not_null<Ui::Text::CustomEmoji*> SuggestionsWidget::resolveCustomEmoji( not_null<Ui::Text::CustomEmoji*> SuggestionsWidget::resolveCustomEmoji(
@ -639,7 +641,9 @@ SuggestionsController::SuggestionsController(
_suggestions = _container->setOwnedWidget( _suggestions = _container->setOwnedWidget(
object_ptr<Ui::Emoji::SuggestionsWidget>( object_ptr<Ui::Emoji::SuggestionsWidget>(
_container, _container,
session)); session,
_options.suggestCustomEmoji,
_options.allowCustomWithoutPremium));
setReplaceCallback(nullptr); setReplaceCallback(nullptr);
@ -689,7 +693,7 @@ SuggestionsController::SuggestionsController(
handleTextChange(); handleTextChange();
} }
SuggestionsController *SuggestionsController::Init( not_null<SuggestionsController*> SuggestionsController::Init(
not_null<QWidget*> outer, not_null<QWidget*> outer,
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
not_null<Main::Session*> session, not_null<Main::Session*> session,

View file

@ -33,7 +33,11 @@ using SuggestionsQuery = std::variant<QString, EmojiPtr>;
class SuggestionsWidget final : public Ui::RpWidget { class SuggestionsWidget final : public Ui::RpWidget {
public: public:
SuggestionsWidget(QWidget *parent, not_null<Main::Session*> session); SuggestionsWidget(
QWidget *parent,
not_null<Main::Session*> session,
bool suggestCustomEmoji,
Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium);
~SuggestionsWidget(); ~SuggestionsWidget();
void showWithQuery(SuggestionsQuery query, bool force = false); void showWithQuery(SuggestionsQuery query, bool force = false);
@ -78,9 +82,9 @@ private:
[[nodiscard]] std::vector<Row> getRowsByQuery(const QString &text) const; [[nodiscard]] std::vector<Row> getRowsByQuery(const QString &text) const;
[[nodiscard]] base::flat_multi_map<int, Custom> lookupCustom( [[nodiscard]] base::flat_multi_map<int, Custom> lookupCustom(
const std::vector<Row> &rows) const; const std::vector<Row> &rows) const;
[[nodiscard]] std::vector<Row> prependCustom( [[nodiscard]] std::vector<Row> appendCustom(
std::vector<Row> rows); std::vector<Row> rows);
[[nodiscard]] std::vector<Row> prependCustom( [[nodiscard]] std::vector<Row> appendCustom(
std::vector<Row> rows, std::vector<Row> rows,
const base::flat_multi_map<int, Custom> &custom); const base::flat_multi_map<int, Custom> &custom);
void resizeToRows(); void resizeToRows();
@ -110,6 +114,8 @@ private:
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
SuggestionsQuery _query; SuggestionsQuery _query;
std::vector<Row> _rows; std::vector<Row> _rows;
bool _suggestCustomEmoji = false;
Fn<bool(not_null<DocumentData*>)> _allowCustomWithoutPremium;
base::flat_map< base::flat_map<
not_null<DocumentData*>, not_null<DocumentData*>,
@ -139,10 +145,9 @@ private:
class SuggestionsController { class SuggestionsController {
public: public:
struct Options { struct Options {
Options() : suggestExactFirstWord(true) { bool suggestExactFirstWord = true;
} bool suggestCustomEmoji = false;
Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium;
bool suggestExactFirstWord;
}; };
SuggestionsController( SuggestionsController(
@ -158,7 +163,7 @@ public:
const QString &replacement, const QString &replacement,
const QString &customEmojiData)> callback); const QString &customEmojiData)> callback);
static SuggestionsController *Init( static not_null<SuggestionsController*> Init(
not_null<QWidget*> outer, not_null<QWidget*> outer,
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
not_null<Main::Session*> session, not_null<Main::Session*> session,

View file

@ -480,10 +480,14 @@ HistoryWidget::HistoryWidget(
Unexpected("action in MimeData hook."); Unexpected("action in MimeData hook.");
}); });
const auto allow = [=](const auto&) {
return _peer && _peer->isSelf();
};
const auto suggestions = Ui::Emoji::SuggestionsController::Init( const auto suggestions = Ui::Emoji::SuggestionsController::Init(
this, this,
_field, _field,
&controller->session()); &controller->session(),
{ .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow });
_raiseEmojiSuggestions = [=] { suggestions->raise(); }; _raiseEmojiSuggestions = [=] { suggestions->raise(); };
updateFieldSubmitSettings(); updateFieldSubmitSettings();

View file

@ -1432,10 +1432,14 @@ void ComposeControls::initField() {
return false; return false;
}); });
initAutocomplete(); initAutocomplete();
const auto allow = [=](const auto &) {
return _history && Data::AllowEmojiWithoutPremium(_history->peer);
};
const auto suggestions = Ui::Emoji::SuggestionsController::Init( const auto suggestions = Ui::Emoji::SuggestionsController::Init(
_parent, _parent,
_field, _field,
&_window->session()); &_window->session(),
{ .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow });
_raiseEmojiSuggestions = [=] { suggestions->raise(); }; _raiseEmojiSuggestions = [=] { suggestions->raise(); };
const auto rawTextEdit = _field->rawTextEdit().get(); const auto rawTextEdit = _field->rawTextEdit().get();