Add search with categories to GIF.

This commit is contained in:
John Preston 2023-01-24 13:20:57 +04:00
parent 4f18535f8d
commit d51d1939b0
9 changed files with 108 additions and 37 deletions

View file

@ -348,6 +348,7 @@ inlineBotsScroll: ScrollArea(defaultSolidScroll) {
deltab: stickerPanPadding; deltab: stickerPanPadding;
} }
gifsPadding: margins(9px, 5px, 3px, 9px);
gifsSearchField: defaultMultiSelectSearchField; gifsSearchField: defaultMultiSelectSearchField;
gifsSearchFieldPosition: point(42px, 7px); gifsSearchFieldPosition: point(42px, 7px);
gifsSearchCancel: defaultMultiSelectSearchCancel; gifsSearchCancel: defaultMultiSelectSearchCancel;

View file

@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qt/qt_key_modifiers.h" #include "base/qt/qt_key_modifiers.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_emoji_statuses.h"
#include "data/stickers/data_custom_emoji.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
@ -20,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/stickers/data_stickers.h" #include "data/stickers/data_stickers.h"
#include "menu/menu_send.h" // SendMenu::FillSendMenu #include "menu/menu_send.h" // SendMenu::FillSendMenu
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "ui/controls/tabbed_search.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
@ -186,6 +189,8 @@ GifsListWidget::GifsListWidget(
setMouseTracking(true); setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
setupSearch();
_inlineRequestTimer.setSingleShot(true); _inlineRequestTimer.setSingleShot(true);
connect( connect(
&_inlineRequestTimer, &_inlineRequestTimer,
@ -215,9 +220,8 @@ GifsListWidget::GifsListWidget(
_mosaic.setFullWidth(s.width()); _mosaic.setFullWidth(s.width());
}, lifetime()); }, lifetime());
_mosaic.setOffset( _mosaic.setPadding(st::gifsPadding
st::inlineResultsLeft - st::roundRadiusSmall, + QMargins(-st::emojiPanRadius, _search->height(), 0, 0));
st::stickerPanPadding);
_mosaic.setRightSkip(st::inlineResultsSkip); _mosaic.setRightSkip(st::inlineResultsSkip);
} }
@ -262,7 +266,7 @@ void GifsListWidget::checkLoadMore() {
} }
int GifsListWidget::countDesiredHeight(int newWidth) { int GifsListWidget::countDesiredHeight(int newWidth) {
return _mosaic.countDesiredHeight(newWidth) + st::stickerPanPadding * 2; return _mosaic.countDesiredHeight(newWidth);
} }
GifsListWidget::~GifsListWidget() { GifsListWidget::~GifsListWidget() {
@ -272,7 +276,7 @@ GifsListWidget::~GifsListWidget() {
} }
void GifsListWidget::cancelGifsSearch() { void GifsListWidget::cancelGifsSearch() {
_footer->setLoading(false); _search->setLoading(false);
if (_inlineRequestId) { if (_inlineRequestId) {
_api.request(_inlineRequestId).cancel(); _api.request(_inlineRequestId).cancel();
_inlineRequestId = 0; _inlineRequestId = 0;
@ -284,7 +288,7 @@ void GifsListWidget::cancelGifsSearch() {
} }
void GifsListWidget::inlineResultsDone(const MTPmessages_BotResults &result) { void GifsListWidget::inlineResultsDone(const MTPmessages_BotResults &result) {
_footer->setLoading(false); _search->setLoading(false);
_inlineRequestId = 0; _inlineRequestId = 0;
auto it = _inlineCache.find(_inlineQuery); auto it = _inlineCache.find(_inlineQuery);
@ -774,14 +778,14 @@ Data::FileOrigin GifsListWidget::inlineItemFileOrigin() {
} }
void GifsListWidget::afterShown() { void GifsListWidget::afterShown() {
if (_footer) { if (_search) {
_footer->stealFocus(); _search->stealFocus();
} }
} }
void GifsListWidget::beforeHiding() { void GifsListWidget::beforeHiding() {
if (_footer) { if (_search) {
_footer->returnFocus(); _search->returnFocus();
} }
} }
@ -797,6 +801,26 @@ bool GifsListWidget::refreshInlineRows(int32 *added) {
return (entry != nullptr); return (entry != nullptr);
} }
void GifsListWidget::setupSearch() {
const auto owner = &_controller->session().data();
using Descriptor = Ui::SearchDescriptor;
_search = std::make_unique<Ui::TabbedSearch>(this, st(), Descriptor{
.st = st().search,
.groups = owner->emojiStatuses().emojiGroupsValue(),
.customEmojiFactory = owner->customEmojiManager().factory(
Data::CustomEmojiManager::SizeTag::SetIcon,
Ui::SearchWithGroups::IconSizeOverride())
});
_search->queryValue(
) | rpl::start_with_next([=](std::vector<QString> &&query) {
searchForGifs(ranges::accumulate(query, QString(), [](
QString a,
QString b) {
return a.isEmpty() ? b : (a + ' ' + b);
}));
}, lifetime());
}
int32 GifsListWidget::showInlineRows(bool newResults) { int32 GifsListWidget::showInlineRows(bool newResults) {
auto added = 0; auto added = 0;
refreshInlineRows(&added); refreshInlineRows(&added);
@ -813,7 +837,7 @@ void GifsListWidget::searchForGifs(const QString &query) {
} }
if (_inlineQuery != query) { if (_inlineQuery != query) {
_footer->setLoading(false); _search->setLoading(false);
if (_inlineRequestId) { if (_inlineRequestId) {
_api.request(_inlineRequestId).cancel(); _api.request(_inlineRequestId).cancel();
_inlineRequestId = 0; _inlineRequestId = 0;
@ -862,7 +886,7 @@ void GifsListWidget::sendInlineRequest() {
if (!_searchBot) { if (!_searchBot) {
// Wait for the bot being resolved. // Wait for the bot being resolved.
_footer->setLoading(true); _search->setLoading(true);
_inlineRequestTimer.start(kSearchRequestDelay); _inlineRequestTimer.start(kSearchRequestDelay);
return; return;
} }
@ -874,12 +898,12 @@ void GifsListWidget::sendInlineRequest() {
if (it != _inlineCache.cend()) { if (it != _inlineCache.cend()) {
nextOffset = it->second->nextOffset; nextOffset = it->second->nextOffset;
if (nextOffset.isEmpty()) { if (nextOffset.isEmpty()) {
_footer->setLoading(false); _search->setLoading(false);
return; return;
} }
} }
_footer->setLoading(true); _search->setLoading(true);
_inlineRequestId = _api.request(MTPmessages_GetInlineBotResults( _inlineRequestId = _api.request(MTPmessages_GetInlineBotResults(
MTP_flags(0), MTP_flags(0),
_searchBot->inputUser, _searchBot->inputUser,
@ -891,7 +915,7 @@ void GifsListWidget::sendInlineRequest() {
inlineResultsDone(result); inlineResultsDone(result);
}).fail([this] { }).fail([this] {
// show error? // show error?
_footer->setLoading(false); _search->setLoading(false);
_inlineRequestId = 0; _inlineRequestId = 0;
}).handleAllErrors().send(); }).handleAllErrors().send();
} }

View file

@ -28,6 +28,7 @@ class Result;
namespace Ui { namespace Ui {
class PopupMenu; class PopupMenu;
class RoundButton; class RoundButton;
class TabbedSearch;
} // namespace Ui } // namespace Ui
namespace Window { namespace Window {
@ -119,6 +120,7 @@ private:
InlineResults results; InlineResults results;
}; };
void setupSearch();
void clearHeavyData(); void clearHeavyData();
void cancelGifsSearch(); void cancelGifsSearch();
void switchToSavedGifs(); void switchToSavedGifs();
@ -152,6 +154,7 @@ private:
bool forceSend = false); bool forceSend = false);
not_null<Window::SessionController*> _controller; not_null<Window::SessionController*> _controller;
std::unique_ptr<Ui::TabbedSearch> _search;
MTP::Sender _api; MTP::Sender _api;

View file

@ -65,7 +65,12 @@ bool ListSection::addItem(not_null<BaseLayout*> item) {
void ListSection::finishSection() { void ListSection::finishSection() {
if (_type == Type::GIF) { if (_type == Type::GIF) {
_mosaic.setOffset(st::infoMediaSkip, headerHeight()); _mosaic.setPadding({
st::infoMediaSkip,
headerHeight(),
st::infoMediaSkip,
st::stickerPanPadding,
});
_mosaic.setRightSkip(st::infoMediaSkip); _mosaic.setRightSkip(st::infoMediaSkip);
_mosaic.addItems(_items); _mosaic.addItems(_items);
} }
@ -390,7 +395,7 @@ int ListSection::recountHeight() {
} break; } break;
case Type::GIF: { case Type::GIF: {
return _mosaic.countDesiredHeight(0) + result; return _mosaic.countDesiredHeight(0);
} break; } break;
case Type::RoundVoiceFile: case Type::RoundVoiceFile:

View file

@ -443,13 +443,10 @@ void Inner::clearInlineRowsPanel() {
} }
void Inner::refreshMosaicOffset() { void Inner::refreshMosaicOffset() {
const auto top = st::stickerPanPadding const auto top = _switchPmButton
+ (_switchPmButton ? (_switchPmButton->height() + st::inlineResultsSkip)
? _switchPmButton->height() + st::inlineResultsSkip : 0;
: 0); _mosaic.setPadding(st::gifsPadding + QMargins(0, top, 0, 0));
_mosaic.setOffset(
st::inlineResultsLeft - st::roundRadiusSmall,
top);
} }
void Inner::refreshSwitchPmButton(const CacheEntry *entry) { void Inner::refreshSwitchPmButton(const CacheEntry *entry) {

View file

@ -27,12 +27,12 @@ int AbstractMosaicLayout::countDesiredHeight(int newWidth) {
layoutRow(row, newWidth ? newWidth : _width); layoutRow(row, newWidth ? newWidth : _width);
result += row.height; result += row.height;
} }
return result; return _padding.top() + result + _padding.bottom();
} }
FoundItem AbstractMosaicLayout::findByPoint(const QPoint &globalPoint) const { FoundItem AbstractMosaicLayout::findByPoint(const QPoint &globalPoint) const {
auto sx = globalPoint.x() - _offset.x(); auto sx = globalPoint.x() - _padding.left();
auto sy = globalPoint.y() - _offset.y(); auto sy = globalPoint.y() - _padding.top();
auto row = -1; auto row = -1;
auto col = -1; auto col = -1;
auto sel = -1; auto sel = -1;
@ -108,8 +108,8 @@ QRect AbstractMosaicLayout::findRect(int index) const {
if ((left + w) > fromX) { if ((left + w) > fromX) {
if (item->position() == index) { if (item->position() == index) {
return QRect( return QRect(
left + _offset.x(), left + _padding.left(),
top + _offset.y(), top + _padding.top(),
item->width(), item->width(),
item->height()); item->height());
} }
@ -139,8 +139,8 @@ void AbstractMosaicLayout::setRightSkip(int rightSkip) {
_rightSkip = rightSkip; _rightSkip = rightSkip;
} }
void AbstractMosaicLayout::setOffset(int left, int top) { void AbstractMosaicLayout::setPadding(QMargins padding) {
_offset = { left, top }; _padding = padding;
} }
void AbstractMosaicLayout::setFullWidth(int w) { void AbstractMosaicLayout::setFullWidth(int w) {
@ -211,7 +211,7 @@ void AbstractMosaicLayout::forEach(
void AbstractMosaicLayout::paint( void AbstractMosaicLayout::paint(
Fn<void(not_null<AbstractLayoutItem*>, QPoint)> paintItem, Fn<void(not_null<AbstractLayoutItem*>, QPoint)> paintItem,
const QRect &clip) const { const QRect &clip) const {
auto top = _offset.y(); auto top = _padding.top();
const auto fromX = style::RightToLeft() const auto fromX = style::RightToLeft()
? (_width - clip.x() - clip.width()) ? (_width - clip.x() - clip.width())
: clip.x(); : clip.x();
@ -225,7 +225,7 @@ void AbstractMosaicLayout::paint(
} }
auto &inlineRow = _rows[row]; auto &inlineRow = _rows[row];
if ((top + inlineRow.height) > clip.top()) { if ((top + inlineRow.height) > clip.top()) {
auto left = _offset.x(); auto left = _padding.left();
if (row == (rows - 1)) { if (row == (rows - 1)) {
// context.lastRow = true; // context.lastRow = true;
} }
@ -366,8 +366,7 @@ void AbstractMosaicLayout::layoutRow(Row &row, int fullWidth) {
auto desiredWidth = row.maxWidth; auto desiredWidth = row.maxWidth;
row.height = 0; row.height = 0;
auto availableWidth = fullWidth auto availableWidth = fullWidth - _padding.left() - _padding.right();
- (st::inlineResultsLeft - st::roundRadiusSmall);
for (auto i = 0; i < count; ++i) { for (auto i = 0; i < count; ++i) {
const auto index = indices[i]; const auto index = indices[i];
const auto &item = row.items[index]; const auto &item = row.items[index];

View file

@ -32,7 +32,7 @@ public:
[[nodiscard]] QRect findRect(int index) const; [[nodiscard]] QRect findRect(int index) const;
void setRightSkip(int rightSkip); void setRightSkip(int rightSkip);
void setOffset(int left, int top); void setPadding(QMargins padding);
void setFullWidth(int w); void setFullWidth(int w);
[[nodiscard]] bool empty() const; [[nodiscard]] bool empty() const;
@ -73,7 +73,7 @@ private:
int _bigWidth; int _bigWidth;
int _width = 0; int _width = 0;
int _rightSkip = 0; int _rightSkip = 0;
QPoint _offset; QMargins _padding;
std::vector<Row> _rows; std::vector<Row> _rows;
}; };

View file

@ -316,6 +316,7 @@ void SearchWithGroups::initField() {
} else { } else {
_debounceTimer.callOnce(kDebounceTimeout); _debounceTimer.callOnce(kDebounceTimeout);
_chosenGroup = QString(); _chosenGroup = QString();
scrollGroupsToStart();
} }
}); });
@ -518,6 +519,26 @@ auto SearchWithGroups::debouncedQueryValue() const
return _debouncedQuery.value(); return _debouncedQuery.value();
} }
void SearchWithGroups::setLoading(bool loading) {
_cancel->setLoadingAnimation(loading);
}
void SearchWithGroups::stealFocus() {
if (!_focusTakenFrom) {
_focusTakenFrom = QApplication::focusWidget();
}
_field->setFocus();
}
void SearchWithGroups::returnFocus() {
if (_field && _focusTakenFrom) {
if (_field->hasFocus()) {
_focusTakenFrom->setFocus();
}
_focusTakenFrom = nullptr;
}
}
int SearchWithGroups::IconSizeOverride() { int SearchWithGroups::IconSizeOverride() {
return style::ConvertScale(kCategoryIconSizeOverride); return style::ConvertScale(kCategoryIconSizeOverride);
} }
@ -600,6 +621,18 @@ int TabbedSearch::height() const {
return _search.height() + rect::m::sum::v(_st.searchMargin); return _search.height() + rect::m::sum::v(_st.searchMargin);
} }
void TabbedSearch::setLoading(bool loading) {
_search.setLoading(loading);
}
void TabbedSearch::stealFocus() {
_search.stealFocus();
}
void TabbedSearch::returnFocus() {
_search.returnFocus();
}
rpl::producer<std::vector<QString>> TabbedSearch::queryValue() const { rpl::producer<std::vector<QString>> TabbedSearch::queryValue() const {
return _search.queryValue(); return _search.queryValue();
} }

View file

@ -53,6 +53,10 @@ public:
[[nodiscard]] auto debouncedQueryValue() const [[nodiscard]] auto debouncedQueryValue() const
-> rpl::producer<std::vector<QString>>; -> rpl::producer<std::vector<QString>>;
void setLoading(bool loading);
void stealFocus();
void returnFocus();
[[nodiscard]] static int IconSizeOverride(); [[nodiscard]] static int IconSizeOverride();
private: private:
@ -79,6 +83,7 @@ private:
not_null<FadeWrap<IconButton>*> _back; not_null<FadeWrap<IconButton>*> _back;
not_null<CrossButton*> _cancel; not_null<CrossButton*> _cancel;
not_null<InputField*> _field; not_null<InputField*> _field;
QPointer<QWidget> _focusTakenFrom;
not_null<FadeWrap<RpWidget>*> _groups; not_null<FadeWrap<RpWidget>*> _groups;
not_null<RpWidget*> _fade; not_null<RpWidget*> _fade;
rpl::variable<float64> _fadeOpacity = 0.; rpl::variable<float64> _fadeOpacity = 0.;
@ -111,6 +116,10 @@ public:
[[nodiscard]] auto debouncedQueryValue() const [[nodiscard]] auto debouncedQueryValue() const
->rpl::producer<std::vector<QString>>; ->rpl::producer<std::vector<QString>>;
void setLoading(bool loading);
void stealFocus();
void returnFocus();
private: private:
const style::EmojiPan &_st; const style::EmojiPan &_st;
SearchWithGroups _search; SearchWithGroups _search;