/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "chat_helpers/gifs_list_widget.h" #include "data/data_photo.h" #include "data/data_document.h" #include "data/data_session.h" #include "data/data_user.h" #include "styles/style_chat_helpers.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" #include "ui/effects/ripple_animation.h" #include "ui/image/image.h" #include "boxes/stickers_box.h" #include "inline_bots/inline_bot_result.h" #include "chat_helpers/stickers.h" #include "storage/localstorage.h" #include "lang/lang_keys.h" #include "mainwindow.h" #include "window/window_session_controller.h" #include "history/view/history_view_cursor_state.h" #include "facades.h" #include "app.h" #include namespace ChatHelpers { namespace { constexpr auto kSaveChosenTabTimeout = 1000; constexpr auto kSearchRequestDelay = 400; constexpr auto kInlineItemsMaxPerRow = 5; constexpr auto kSearchBotUsername = str_const("gif"); } // namespace class GifsListWidget::Footer : public TabbedSelector::InnerFooter { public: Footer(not_null parent); void stealFocus(); void returnFocus(); void setLoading(bool loading) { _cancel->setLoadingAnimation(loading); } protected: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; void processPanelHideFinished() override; private: not_null _pan; object_ptr _field; object_ptr _cancel; QPointer _focusTakenFrom; }; GifsListWidget::Footer::Footer(not_null parent) : InnerFooter(parent) , _pan(parent) , _field(this, st::gifsSearchField, tr::lng_gifs_search()) , _cancel(this, st::gifsSearchCancel) { connect(_field, &Ui::InputField::submitted, [=] { _pan->sendInlineRequest(); }); connect(_field, &Ui::InputField::cancelled, [=] { if (_field->getLastText().isEmpty()) { _pan->cancelled(); } else { _field->setText(QString()); } }); connect(_field, &Ui::InputField::changed, [=] { _cancel->toggle( !_field->getLastText().isEmpty(), anim::type::normal); _pan->searchForGifs(_field->getLastText()); }); _cancel->setClickedCallback([=] { _field->setText(QString()); }); } void GifsListWidget::Footer::stealFocus() { if (!_focusTakenFrom) { _focusTakenFrom = QApplication::focusWidget(); } _field->setFocus(); } void GifsListWidget::Footer::returnFocus() { if (_focusTakenFrom) { if (_field->hasFocus()) { _focusTakenFrom->setFocus(); } _focusTakenFrom = nullptr; } } void GifsListWidget::Footer::paintEvent(QPaintEvent *e) { Painter p(this); st::gifsSearchIcon.paint(p, st::gifsSearchIconPosition.x(), st::gifsSearchIconPosition.y(), width()); } void GifsListWidget::Footer::resizeEvent(QResizeEvent *e) { auto fieldWidth = width() - st::gifsSearchFieldPosition.x() - st::gifsSearchCancelPosition.x() - st::gifsSearchCancel.width; _field->resizeToWidth(fieldWidth); _field->moveToLeft(st::gifsSearchFieldPosition.x(), st::gifsSearchFieldPosition.y()); _cancel->moveToRight(st::gifsSearchCancelPosition.x(), st::gifsSearchCancelPosition.y()); } void GifsListWidget::Footer::processPanelHideFinished() { // Preserve panel state through visibility toggles. //_field->setText(QString()); } GifsListWidget::GifsListWidget( QWidget *parent, not_null controller) : Inner(parent, controller) , _section(Section::Gifs) , _updateInlineItems([=] { updateInlineItems(); }) , _previewTimer([=] { showPreview(); }) { setMouseTracking(true); setAttribute(Qt::WA_OpaquePaintEvent); _inlineRequestTimer.setSingleShot(true); connect( &_inlineRequestTimer, &QTimer::timeout, this, [=] { sendInlineRequest(); }); controller->session().data().savedGifsUpdated( ) | rpl::start_with_next([this] { refreshSavedGifs(); }, lifetime()); subscribe(controller->session().downloaderTaskFinished(), [this] { update(); }); subscribe(controller->gifPauseLevelChanged(), [=] { if (!controller->isGifPausedAtLeastFor( Window::GifPauseReason::SavedGifs)) { update(); } }); } rpl::producer> GifsListWidget::fileChosen() const { return _fileChosen.events(); } rpl::producer> GifsListWidget::photoChosen() const { return _photoChosen.events(); } auto GifsListWidget::inlineResultChosen() const -> rpl::producer { return _inlineResultChosen.events(); } object_ptr GifsListWidget::createFooter() { Expects(_footer == nullptr); auto result = object_ptr