Show inline bot results in a separate widget.

Add a InlineBots::Layout::Widget for inline bot results.
GIF search from EmojiPan is disabled for now.
This commit is contained in:
John Preston 2017-03-27 21:11:51 +03:00
parent 5cb66c99bd
commit 3d846fcd49
19 changed files with 1616 additions and 287 deletions

View File

@ -54,9 +54,9 @@ void hideSingleUseKeyboard(const HistoryItem *msg) {
}
}
bool insertBotCommand(const QString &cmd, bool specialGif) {
bool insertBotCommand(const QString &cmd) {
if (auto m = main()) {
return m->insertBotCommand(cmd, specialGif);
return m->insertBotCommand(cmd);
}
return false;
}
@ -264,20 +264,6 @@ void repaintHistoryItem(const HistoryItem *item) {
}
}
void repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
if (!layout) return;
if (auto main = App::main()) {
main->ui_repaintInlineItem(layout);
}
}
bool isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
if (auto main = App::main()) {
return main->ui_isInlineItemVisible(layout);
}
return false;
}
void autoplayMediaInlineAsync(const FullMsgId &msgId) {
if (auto main = App::main()) {
QMetaObject::invokeMethod(main, "ui_autoplayMediaInlineAsync", Qt::QueuedConnection, Q_ARG(qint32, msgId.channel), Q_ARG(qint32, msgId.msg));
@ -386,10 +372,6 @@ void historyItemLayoutChanged(const HistoryItem *item) {
if (MainWidget *m = App::main()) m->notify_historyItemLayoutChanged(item);
}
void inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) {
if (MainWidget *m = App::main()) m->notify_inlineItemLayoutChanged(layout);
}
void historyMuteUpdated(History *history) {
if (MainWidget *m = App::main()) m->notify_historyMuteUpdated(history);
}

View File

@ -67,7 +67,7 @@ inline base::lambda_once<void()> LambdaDelayedOnce(int duration, PointersAndLamb
}
void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo = 0);
bool insertBotCommand(const QString &cmd, bool specialGif = false);
bool insertBotCommand(const QString &cmd);
void activateBotCommand(const HistoryItem *msg, int row, int col);
void searchByHashtag(const QString &tag, PeerData *inPeer);
void openPeerByName(const QString &username, MsgId msgId = ShowAtUnreadMsgId, const QString &startToken = QString());
@ -109,8 +109,6 @@ bool isMediaViewShown();
bool isInlineItemBeingChosen();
void repaintHistoryItem(const HistoryItem *item);
void repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
bool isInlineItemVisible(const InlineBots::Layout::ItemBase *reader);
void autoplayMediaInlineAsync(const FullMsgId &msgId);
void showPeerProfile(const PeerId &peer);
@ -180,7 +178,6 @@ void migrateUpdated(PeerData *peer);
void clipStopperHidden(ClipStopperType type);
void historyItemLayoutChanged(const HistoryItem *item);
void inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout);
void historyMuteUpdated(History *history);
// handle pending resize() / paint() on history items

View File

@ -63,6 +63,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "auth_session.h"
#include "window/notifications_manager.h"
#include "window/window_controller.h"
#include "inline_bots/inline_results_widget.h"
namespace {
@ -3427,11 +3428,15 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
_inlineBot = bot;
inlineBotChanged();
}
if (_inlineBot->username == cInlineGifBotUsername() && query.isEmpty()) {
_emojiPan->clearInlineBot();
} else {
_emojiPan->queryInlineBot(_inlineBot, _peer, query);
if (!_inlineResults) {
_inlineResults.create(this);
_inlineResults->setResultSelectedCallback([this](InlineBots::Result *result, UserData *bot) {
onInlineResultSend(result, bot);
});
updateControlsGeometry();
orderWidgets();
}
_inlineResults->queryInlineBot(_inlineBot, _peer, query);
if (!_fieldAutocomplete->isHidden()) {
_fieldAutocomplete->hideAnimated();
}
@ -3440,6 +3445,20 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
}
}
void HistoryWidget::orderWidgets() {
_reportSpamPanel->raise();
_topShadow->raise();
if (_membersDropdown) {
_membersDropdown->raise();
}
if (_inlineResults) {
_inlineResults->raise();
}
_emojiPan->raise();
_attachDragDocument->raise();
_attachDragPhoto->raise();
}
void HistoryWidget::updateStickersByEmoji() {
int len = 0;
if (!_editMsgId) {
@ -4557,10 +4576,11 @@ void HistoryWidget::updateNotifySettings() {
}
bool HistoryWidget::contentOverlapped(const QRect &globalRect) {
return (_attachDragDocument->overlaps(globalRect) ||
_attachDragPhoto->overlaps(globalRect) ||
_fieldAutocomplete->overlaps(globalRect) ||
_emojiPan->overlaps(globalRect));
return (_attachDragDocument->overlaps(globalRect)
|| _attachDragPhoto->overlaps(globalRect)
|| _fieldAutocomplete->overlaps(globalRect)
|| _emojiPan->overlaps(globalRect)
|| (_inlineResults && _inlineResults->overlaps(globalRect)));
}
void HistoryWidget::updateReportSpamStatus() {
@ -4692,6 +4712,9 @@ void HistoryWidget::updateControlsVisibility() {
_botKeyboardHide->hide();
_botCommandStart->hide();
_emojiPan->hide();
if (_inlineResults) {
_inlineResults->hide();
}
if (_pinnedBar) {
_pinnedBar->cancel->hide();
_pinnedBar->shadow->hide();
@ -4750,6 +4773,9 @@ void HistoryWidget::updateControlsVisibility() {
_botKeyboardHide->hide();
_botCommandStart->hide();
_emojiPan->hide();
if (_inlineResults) {
_inlineResults->hide();
}
if (!_field->isHidden()) {
_field->hide();
resizeEvent(0);
@ -4861,6 +4887,9 @@ void HistoryWidget::updateControlsVisibility() {
_botKeyboardHide->hide();
_botCommandStart->hide();
_emojiPan->hide();
if (_inlineResults) {
_inlineResults->hide();
}
_kbScroll->hide();
if (!_field->isHidden()) {
_field->hide();
@ -5379,6 +5408,9 @@ bool HistoryWidget::saveEditMsgFail(History *history, const RPCError &error, mtp
void HistoryWidget::hideSelectorControlsAnimated() {
_fieldAutocomplete->hideAnimated();
_emojiPan->hideAnimated();
if (_inlineResults) {
_inlineResults->hideAnimated();
}
}
void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
@ -5971,7 +6003,7 @@ bool HistoryWidget::botCallbackFail(BotCallbackInfo info, const RPCError &error,
return true;
}
bool HistoryWidget::insertBotCommand(const QString &cmd, bool specialGif) {
bool HistoryWidget::insertBotCommand(const QString &cmd) {
if (!canWriteMessage()) return false;
bool insertingInlineBot = !cmd.isEmpty() && (cmd.at(0) == '@');
@ -5989,34 +6021,26 @@ bool HistoryWidget::insertBotCommand(const QString &cmd, bool specialGif) {
if (!insertingInlineBot) {
auto &textWithTags = _field->getTextWithTags();
if (specialGif) {
if (textWithTags.text.trimmed() == '@' + cInlineGifBotUsername() && textWithTags.text.at(0) == '@') {
clearFieldText(TextUpdateEvent::SaveDraft, Ui::FlatTextarea::AddToUndoHistory);
}
TextWithTags textWithTagsToSet;
QRegularExpressionMatch m = QRegularExpression(qsl("^/[A-Za-z_0-9]{0,64}(@[A-Za-z_0-9]{0,32})?(\\s|$)")).match(textWithTags.text);
if (m.hasMatch()) {
textWithTagsToSet = _field->getTextWithTagsPart(m.capturedLength());
} else {
TextWithTags textWithTagsToSet;
QRegularExpressionMatch m = QRegularExpression(qsl("^/[A-Za-z_0-9]{0,64}(@[A-Za-z_0-9]{0,32})?(\\s|$)")).match(textWithTags.text);
if (m.hasMatch()) {
textWithTagsToSet = _field->getTextWithTagsPart(m.capturedLength());
} else {
textWithTagsToSet = textWithTags;
}
textWithTagsToSet.text = toInsert + textWithTagsToSet.text;
for (auto &tag : textWithTagsToSet.tags) {
tag.offset += toInsert.size();
}
_field->setTextWithTags(textWithTagsToSet);
textWithTagsToSet = textWithTags;
}
textWithTagsToSet.text = toInsert + textWithTagsToSet.text;
for (auto &tag : textWithTagsToSet.tags) {
tag.offset += toInsert.size();
}
_field->setTextWithTags(textWithTagsToSet);
QTextCursor cur(_field->textCursor());
cur.movePosition(QTextCursor::End);
_field->setTextCursor(cur);
}
QTextCursor cur(_field->textCursor());
cur.movePosition(QTextCursor::End);
_field->setTextCursor(cur);
} else {
if (!specialGif || _field->isEmpty()) {
setFieldText({ toInsert, TextWithTags::Tags() }, TextUpdateEvent::SaveDraft, Ui::FlatTextarea::AddToUndoHistory);
_field->setFocus();
return true;
}
setFieldText({ toInsert, TextWithTags::Tags() }, TextUpdateEvent::SaveDraft, Ui::FlatTextarea::AddToUndoHistory);
_field->setFocus();
return true;
}
return false;
}
@ -6498,7 +6522,7 @@ void HistoryWidget::moveFieldControls() {
_kbScroll->setGeometry(0, bottom, width(), keyboardHeight);
}
// _attachToggle --------------------------------------------------------- _emojiPan --------- _fieldBarCancel
// _attachToggle -------- _inlineResults ---------------------------------- _emojiPan -------- _fieldBarCancel
// (_attachDocument|_attachPhoto) _field (_silent|_cmdStart|_kbShow) (_kbHide|_attachEmoji) [_broadcast] _send
// (_botStart|_unblock|_joinChannel|_muteUnmute)
@ -6515,6 +6539,9 @@ void HistoryWidget::moveFieldControls() {
_silent->moveToRight(right, buttonsBottom);
_fieldBarCancel->moveToRight(0, _field->y() - st::historySendPadding - _fieldBarCancel->height());
if (_inlineResults) {
_inlineResults->moveBottom(_field->y() - st::historySendPadding);
}
_emojiPan->moveBottom(_field->y() - st::historySendPadding);
auto fullWidthButtonRect = QRect(0, bottom - _botStart->height(), width(), _botStart->height());
@ -6546,7 +6573,9 @@ void HistoryWidget::clearInlineBot() {
inlineBotChanged();
_field->finishPlaceholder();
}
_emojiPan->clearInlineBot();
if (_inlineResults) {
_inlineResults->clearInlineBot();
}
onCheckFieldAutocomplete();
}
@ -7132,16 +7161,9 @@ void HistoryWidget::onUpdateHistoryItems() {
}
}
void HistoryWidget::ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
_emojiPan->ui_repaintInlineItem(layout);
}
bool HistoryWidget::ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
return _emojiPan->ui_isInlineItemVisible(layout);
}
bool HistoryWidget::ui_isInlineItemBeingChosen() {
return _emojiPan->ui_isInlineItemBeingChosen();
return _emojiPan->ui_isInlineItemBeingChosen()
|| (_inlineResults && _inlineResults->ui_isInlineItemBeingChosen());
}
PeerData *HistoryWidget::ui_getPeerForMouseAction() {
@ -7154,10 +7176,6 @@ void HistoryWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
}
}
void HistoryWidget::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) {
_emojiPan->notify_inlineItemLayoutChanged(layout);
}
void HistoryWidget::notify_handlePendingHistoryUpdate() {
if (hasPendingResizedItems()) {
updateListSize();
@ -7200,6 +7218,10 @@ void HistoryWidget::updateControlsGeometry() {
_emojiPan->setMinTop(0);
_emojiPan->setMinBottom(_attachEmoji->height());
if (_inlineResults) {
_inlineResults->setMinTop(0);
_inlineResults->setMinBottom(_attachEmoji->height());
}
if (_membersDropdown) {
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
}
@ -7776,14 +7798,7 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
_pinnedBar->shadow->show();
}
connect(_pinnedBar->cancel, SIGNAL(clicked()), this, SLOT(onPinnedHide()));
_reportSpamPanel->raise();
_topShadow->raise();
if (_membersDropdown) {
_membersDropdown->raise();
}
_emojiPan->raise();
_attachDragDocument->raise();
_attachDragPhoto->raise();
orderWidgets();
updatePinnedBar();
result = true;

View File

@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace InlineBots {
namespace Layout {
class ItemBase;
class Widget;
} // namespace Layout
class Result;
} // namespace InlineBots
@ -661,7 +662,7 @@ public:
void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo);
void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);
bool insertBotCommand(const QString &cmd, bool specialGif);
bool insertBotCommand(const QString &cmd);
bool eventFilter(QObject *obj, QEvent *e) override;
@ -712,13 +713,10 @@ public:
void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col);
void ui_repaintHistoryItem(const HistoryItem *item);
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *gif);
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemBeingChosen();
PeerData *ui_getPeerForMouseAction();
void notify_historyItemLayoutChanged(const HistoryItem *item);
void notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout);
void notify_botCommandsChanged(UserData *user);
void notify_inlineBotRequesting(bool requesting);
void notify_replyMarkupUpdated(const HistoryItem *item);
@ -848,6 +846,15 @@ private slots:
void updateField();
private:
struct SendingFilesLists {
QList<QUrl> nonLocalUrls;
QStringList directories;
QStringList emptyFiles;
QStringList tooLargeFiles;
QStringList filesToSend;
bool allFilesForCompress = true;
};
void topBarClick();
void animationCallback();
@ -858,14 +865,6 @@ private:
void chooseAttach();
void historyDownAnimationFinish();
void sendButtonClicked();
struct SendingFilesLists {
QList<QUrl> nonLocalUrls;
QStringList directories;
QStringList emptyFiles;
QStringList tooLargeFiles;
QStringList filesToSend;
bool allFilesForCompress = true;
};
SendingFilesLists getSendingFilesLists(const QList<QUrl> &files);
SendingFilesLists getSendingFilesLists(const QStringList &files);
void getSendingLocalFileInfo(SendingFilesLists &result, const QString &filepath);
@ -887,6 +886,7 @@ private:
bool historyHasNotFreezedUnreadBar(History *history) const;
bool canWriteMessage() const;
void orderWidgets();
void clearInlineBot();
void inlineBotChanged();
@ -1159,6 +1159,7 @@ private:
object_ptr<Ui::InnerDropdown> _membersDropdown = { nullptr };
QTimer _membersDropdownShowTimer;
object_ptr<InlineBots::Layout::Widget> _inlineResults = { nullptr };
object_ptr<EmojiPan> _emojiPan;
DragState _attachDrag = DragStateNone;
object_ptr<DragArea> _attachDragDocument, _attachDragPhoto;

View File

@ -37,10 +37,10 @@ namespace InlineBots {
namespace Layout {
namespace internal {
FileBase::FileBase(Result *result) : ItemBase(result) {
FileBase::FileBase(gsl::not_null<Context*> context, Result *result) : ItemBase(context, result) {
}
FileBase::FileBase(DocumentData *document) : ItemBase(document) {
FileBase::FileBase(gsl::not_null<Context*> context, DocumentData *document) : ItemBase(context, document) {
}
DocumentData *FileBase::getShownDocument() const {
@ -94,11 +94,13 @@ ImagePtr FileBase::content_thumb() const {
return getResultThumb();
}
Gif::Gif(Result *result) : FileBase(result) {
Gif::Gif(gsl::not_null<Context*> context, Result *result) : FileBase(context, result) {
}
Gif::Gif(DocumentData *document, bool hasDeleteButton) : FileBase(document)
, _delete(hasDeleteButton ? new DeleteSavedGifClickHandler(document) : nullptr) {
Gif::Gif(gsl::not_null<Context*> context, DocumentData *document, bool hasDeleteButton) : FileBase(context, document) {
if (hasDeleteButton) {
_delete = MakeShared<DeleteSavedGifClickHandler>(document);
}
}
void Gif::initDimensions() {
@ -338,7 +340,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
int32 height = st::inlineMediaHeight;
QSize frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, ImageRoundCorner::None);
} else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) {
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
_gif.reset();
getShownDocument()->forget();
}
@ -355,7 +357,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
}
}
Sticker::Sticker(Result *result) : FileBase(result) {
Sticker::Sticker(gsl::not_null<Context*> context, Result *result) : FileBase(context, result) {
}
void Sticker::initDimensions() {
@ -455,7 +457,7 @@ void Sticker::prepareThumb() const {
}
}
Photo::Photo(Result *result) : ItemBase(result) {
Photo::Photo(gsl::not_null<Context*> context, Result *result) : ItemBase(context, result) {
}
void Photo::initDimensions() {
@ -551,7 +553,7 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const {
}
}
Video::Video(Result *result) : FileBase(result)
Video::Video(gsl::not_null<Context*> context, Result *result) : FileBase(context, result)
, _link(getResultContentUrlHandler())
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
@ -668,11 +670,11 @@ void CancelFileClickHandler::onClickImpl() const {
_result->cancelFile();
}
File::File(Result *result) : FileBase(result)
File::File(gsl::not_null<Context*> context, Result *result) : FileBase(context, result)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::msgFileSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::msgFileSize - st::inlineThumbSkip)
, _open(new OpenFileClickHandler(result))
, _cancel(new CancelFileClickHandler(result)) {
, _open(MakeShared<OpenFileClickHandler>(result))
, _cancel(MakeShared<CancelFileClickHandler>(result)) {
updateStatusText();
regDocumentItem(getShownDocument(), this);
}
@ -789,12 +791,12 @@ File::~File() {
}
void File::thumbAnimationCallback() {
Ui::repaintInlineItem(this);
update();
}
void File::step_radial(TimeMs ms, bool timer) {
if (timer) {
Ui::repaintInlineItem(this);
update();
} else {
DocumentData *document = getShownDocument();
_animation->radial.update(document->progress(), !document->loading() || document->loaded(), ms);
@ -806,7 +808,7 @@ void File::step_radial(TimeMs ms, bool timer) {
void File::ensureAnimation() const {
if (!_animation) {
_animation.reset(new AnimationData(animation(const_cast<File*>(this), &File::step_radial)));
_animation = std::make_unique<AnimationData>(animation(const_cast<File*>(this), &File::step_radial));
}
}
@ -877,7 +879,7 @@ void File::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 r
}
}
Contact::Contact(Result *result) : ItemBase(result)
Contact::Contact(gsl::not_null<Context*> context, Result *result) : ItemBase(context, result)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
}
@ -966,7 +968,7 @@ void Contact::prepareThumb(int width, int height) const {
}
}
Article::Article(Result *result, bool withThumb) : ItemBase(result)
Article::Article(gsl::not_null<Context*> context, Result *result, bool withThumb) : ItemBase(context, result)
, _url(getResultUrlHandler())
, _link(getResultContentUrlHandler())
, _withThumb(withThumb)
@ -974,7 +976,7 @@ Article::Article(Result *result, bool withThumb) : ItemBase(result)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
LocationCoords location;
if (!_link && result->getLocationCoords(&location)) {
_link.reset(new LocationClickHandler(location));
_link = MakeShared<LocationClickHandler>(location);
}
_thumbLetter = getResultThumbLetter();
}
@ -1113,7 +1115,7 @@ void Article::prepareThumb(int width, int height) const {
}
}
Game::Game(Result *result) : ItemBase(result)
Game::Game(gsl::not_null<Context*> context, Result *result) : ItemBase(context, result)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
countFrameSize();
@ -1322,7 +1324,7 @@ void Game::clipCallback(Media::Clip::Notification notification) {
getResultDocument()->forget();
} else if (_gif->ready() && !_gif->started()) {
_gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None, ImageRoundCorner::None);
} else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) {
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
_gif.reset();
getResultDocument()->forget();
}

View File

@ -30,9 +30,9 @@ namespace internal {
class FileBase : public ItemBase {
public:
FileBase(Result *result);
FileBase(gsl::not_null<Context*> context, Result *result);
// for saved gif layouts
FileBase(DocumentData *doc);
FileBase(gsl::not_null<Context*> context, DocumentData *doc);
protected:
DocumentData *getShownDocument() const;
@ -58,8 +58,8 @@ private:
class Gif : public FileBase {
public:
Gif(Result *result);
Gif(DocumentData *doc, bool hasDeleteButton);
Gif(gsl::not_null<Context*> context, Result *result);
Gif(gsl::not_null<Context*> context, DocumentData *doc, bool hasDeleteButton);
void setPosition(int32 position) override;
void initDimensions() override;
@ -117,9 +117,9 @@ private:
class Photo : public ItemBase {
public:
Photo(Result *result);
Photo(gsl::not_null<Context*> context, Result *result);
// Not used anywhere currently.
//LayoutInlinePhoto(PhotoData *photo);
//Photo(gsl::not_null<Context*> context, PhotoData *photo);
void initDimensions() override;
@ -146,9 +146,9 @@ private:
class Sticker : public FileBase {
public:
Sticker(Result *result);
Sticker(gsl::not_null<Context*> context, Result *result);
// Not used anywhere currently.
//LayoutInlineSticker(DocumentData *document);
//Sticker(gsl::not_null<Context*> context, DocumentData *document);
void initDimensions() override;
@ -167,7 +167,6 @@ public:
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
private:
QSize getThumbSize() const;
mutable Animation _a_over;
@ -181,7 +180,7 @@ private:
class Video : public FileBase {
public:
Video(Result *result);
Video(gsl::not_null<Context*> context, Result *result);
void initDimensions() override;
@ -189,7 +188,6 @@ public:
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private:
ClickHandlerPtr _link;
mutable QPixmap _thumb;
@ -229,7 +227,7 @@ private:
class File : public FileBase {
public:
File(Result *result);
File(gsl::not_null<Context*> context, Result *result);
void initDimensions() override;
@ -291,7 +289,7 @@ private:
class Contact : public ItemBase {
public:
Contact(Result *result);
Contact(gsl::not_null<Context*> context, Result *result);
void initDimensions() override;
int resizeGetHeight(int width) override;
@ -300,7 +298,6 @@ public:
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private:
mutable QPixmap _thumb;
Text _title, _description;
@ -310,7 +307,7 @@ private:
class Article : public ItemBase {
public:
Article(Result *result, bool withThumb);
Article(gsl::not_null<Context*> context, Result *result, bool withThumb);
void initDimensions() override;
int resizeGetHeight(int width) override;
@ -319,7 +316,6 @@ public:
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private:
ClickHandlerPtr _url, _link;
bool _withThumb;
@ -334,7 +330,7 @@ private:
class Game : public ItemBase {
public:
Game(Result *result);
Game(gsl::not_null<Context*> context, Result *result);
void setPosition(int32 position) override;
void initDimensions() override;

View File

@ -95,31 +95,37 @@ void ItemBase::preload() const {
void ItemBase::update() {
if (_position >= 0) {
Ui::repaintInlineItem(this);
context()->inlineItemRepaint(this);
}
}
std::unique_ptr<ItemBase> ItemBase::createLayout(Result *result, bool forceThumb) {
void ItemBase::layoutChanged() {
if (_position >= 0) {
context()->inlineItemLayoutChanged(this);
}
}
std::unique_ptr<ItemBase> ItemBase::createLayout(gsl::not_null<Context*> context, Result *result, bool forceThumb) {
using Type = Result::Type;
switch (result->_type) {
case Type::Photo: return std::make_unique<internal::Photo>(result); break;
case Type::Photo: return std::make_unique<internal::Photo>(context, result); break;
case Type::Audio:
case Type::File: return std::make_unique<internal::File>(result); break;
case Type::Video: return std::make_unique<internal::Video>(result); break;
case Type::Sticker: return std::make_unique<internal::Sticker>(result); break;
case Type::Gif: return std::make_unique<internal::Gif>(result); break;
case Type::File: return std::make_unique<internal::File>(context, result); break;
case Type::Video: return std::make_unique<internal::Video>(context, result); break;
case Type::Sticker: return std::make_unique<internal::Sticker>(context, result); break;
case Type::Gif: return std::make_unique<internal::Gif>(context, result); break;
case Type::Article:
case Type::Geo:
case Type::Venue: return std::make_unique<internal::Article>(result, forceThumb); break;
case Type::Game: return std::make_unique<internal::Game>(result); break;
case Type::Contact: return std::make_unique<internal::Contact>(result); break;
case Type::Venue: return std::make_unique<internal::Article>(context, result, forceThumb); break;
case Type::Game: return std::make_unique<internal::Game>(context, result); break;
case Type::Contact: return std::make_unique<internal::Contact>(context, result); break;
}
return std::unique_ptr<ItemBase>();
}
std::unique_ptr<ItemBase> ItemBase::createLayoutGif(DocumentData *document) {
return std::make_unique<internal::Gif>(document, true);
std::unique_ptr<ItemBase> ItemBase::createLayoutGif(gsl::not_null<Context*> context, DocumentData *document) {
return std::make_unique<internal::Gif>(context, document, true);
}
DocumentData *ItemBase::getResultDocument() const {

View File

@ -47,15 +47,21 @@ public:
}
};
class Context {
public:
virtual void inlineItemLayoutChanged(const ItemBase *layout) = 0;
virtual bool inlineItemVisible(const ItemBase *item) = 0;
virtual void inlineItemRepaint(const ItemBase *item) = 0;
};
class ItemBase : public LayoutItemBase {
public:
ItemBase(Result *result) : _result(result) {
ItemBase(gsl::not_null<Context*> context, Result *result) : _context(context), _result(result) {
}
ItemBase(DocumentData *doc) : _doc(doc) {
ItemBase(gsl::not_null<Context*> context, DocumentData *doc) : _context(context), _doc(doc) {
}
// Not used anywhere currently.
//ItemBase(PhotoData *photo) : _photo(photo) {
//ItemBase(gsl::not_null<Context*> context, PhotoData *photo) : _context(context), _photo(photo) {
//}
virtual void paint(Painter &p, const QRect &clip, const PaintContext *context) const = 0;
@ -82,6 +88,7 @@ public:
virtual void preload() const;
void update();
void layoutChanged();
// ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override {
@ -91,8 +98,8 @@ public:
update();
}
static std::unique_ptr<ItemBase> createLayout(Result *result, bool forceThumb);
static std::unique_ptr<ItemBase> createLayoutGif(DocumentData *document);
static std::unique_ptr<ItemBase> createLayout(gsl::not_null<Context*> context, Result *result, bool forceThumb);
static std::unique_ptr<ItemBase> createLayoutGif(gsl::not_null<Context*> context, DocumentData *document);
protected:
DocumentData *getResultDocument() const;
@ -105,6 +112,10 @@ protected:
ClickHandlerPtr getResultContentUrlHandler() const;
QString getResultThumbLetter() const;
gsl::not_null<Context*> context() const {
return _context;
}
Result *_result = nullptr;
DocumentData *_doc = nullptr;
PhotoData *_photo = nullptr;
@ -113,6 +124,9 @@ protected:
int _position = 0; // < 0 means removed from layout
private:
gsl::not_null<Context*> _context;
};
using DocumentItems = QMap<DocumentData*, OrderedSet<ItemBase*>>;

View File

@ -121,13 +121,13 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
auto &r = message->c_botInlineMessageMediaAuto();
if (result->_type == Type::Photo) {
result->createPhoto();
result->sendData.reset(new internal::SendPhoto(result->_photo, qs(r.vcaption)));
result->sendData = std::make_unique<internal::SendPhoto>(result->_photo, qs(r.vcaption));
} else if (result->_type == Type::Game) {
result->createGame();
result->sendData.reset(new internal::SendGame(result->_game));
result->sendData = std::make_unique<internal::SendGame>(result->_game);
} else {
result->createDocument();
result->sendData.reset(new internal::SendFile(result->_document, qs(r.vcaption)));
result->sendData = std::make_unique<internal::SendFile>(result->_document, qs(r.vcaption));
}
if (r.has_reply_markup()) {
result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(r.vreply_markup);
@ -137,7 +137,7 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
case mtpc_botInlineMessageText: {
auto &r = message->c_botInlineMessageText();
auto entities = r.has_entities() ? entitiesFromMTP(r.ventities.v) : EntitiesInText();
result->sendData.reset(new internal::SendText(qs(r.vmessage), entities, r.is_no_webpage()));
result->sendData = std::make_unique<internal::SendText>(qs(r.vmessage), entities, r.is_no_webpage());
if (result->_type == Type::Photo) {
result->createPhoto();
} else if (result->_type == Type::Audio || result->_type == Type::File || result->_type == Type::Video || result->_type == Type::Sticker || result->_type == Type::Gif) {
@ -151,7 +151,7 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
case mtpc_botInlineMessageMediaGeo: {
auto &r = message->c_botInlineMessageMediaGeo();
if (r.vgeo.type() == mtpc_geoPoint) {
result->sendData.reset(new internal::SendGeo(r.vgeo.c_geoPoint()));
result->sendData = std::make_unique<internal::SendGeo>(r.vgeo.c_geoPoint());
} else {
badAttachment = true;
}
@ -163,7 +163,7 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
case mtpc_botInlineMessageMediaVenue: {
auto &r = message->c_botInlineMessageMediaVenue();
if (r.vgeo.type() == mtpc_geoPoint) {
result->sendData.reset(new internal::SendVenue(r.vgeo.c_geoPoint(), qs(r.vvenue_id), qs(r.vprovider), qs(r.vtitle), qs(r.vaddress)));
result->sendData = std::make_unique<internal::SendVenue>(r.vgeo.c_geoPoint(), qs(r.vvenue_id), qs(r.vprovider), qs(r.vtitle), qs(r.vaddress));
} else {
badAttachment = true;
}
@ -174,7 +174,7 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
case mtpc_botInlineMessageMediaContact: {
auto &r = message->c_botInlineMessageMediaContact();
result->sendData.reset(new internal::SendContact(qs(r.vfirst_name), qs(r.vlast_name), qs(r.vphone_number)));
result->sendData = std::make_unique<internal::SendContact>(qs(r.vfirst_name), qs(r.vlast_name), qs(r.vphone_number));
if (r.has_reply_markup()) {
result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(r.vreply_markup);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,274 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "ui/twidget.h"
#include "ui/abstract_button.h"
#include "ui/effects/panel_animation.h"
#include "mtproto/sender.h"
#include "inline_bots/inline_bot_layout_item.h"
namespace Ui {
class ScrollArea;
class IconButton;
class LinkButton;
class RoundButton;
class RippleAnimation;
} // namesapce Ui
namespace InlineBots {
class Result;
namespace Layout {
class ItemBase;
namespace internal {
constexpr int kInlineItemsMaxPerRow = 5;
using Results = std::vector<std::unique_ptr<Result>>;
struct CacheEntry {
QString nextOffset;
QString switchPmText, switchPmStartToken;
Results results;
};
class Inner : public TWidget, public Context, private base::Subscriber {
Q_OBJECT
public:
Inner(QWidget *parent);
void setMaxHeight(int maxHeight);
void hideFinish(bool completely);
void clearSelection();
int refreshInlineRows(UserData *bot, const CacheEntry *results, bool resultsDeleted);
void inlineBotChanged();
void hideInlineRowsPanel();
void clearInlineRowsPanel();
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
void preloadImages();
void inlineItemLayoutChanged(const ItemBase *layout) override;
void inlineItemRepaint(const ItemBase *layout) override;
bool inlineItemVisible(const ItemBase *layout) override;
bool ui_isInlineItemBeingChosen();
int countHeight(bool plain = false);
void setResultSelectedCallback(base::lambda<void(Result *result, UserData *bot)> callback) {
_resultSelectedCallback = std::move(callback);
}
~Inner();
protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void leaveEventHook(QEvent *e) override;
void leaveToChildEvent(QEvent *e, QWidget *child) override;
void enterFromChildEvent(QEvent *e, QWidget *child) override;
private slots:
void onPreview();
void onUpdateInlineItems();
void onSwitchPm();
signals:
void emptyInlineRows();
private:
static constexpr bool kRefreshIconsScrollAnimation = true;
static constexpr bool kRefreshIconsNoAnimation = false;
void updateSelected();
void paintInlineItems(Painter &p, const QRect &r);
void refreshSwitchPmButton(const CacheEntry *entry);
int32 _maxHeight;
int _visibleTop = 0;
int _visibleBottom = 0;
UserData *_inlineBot;
QString _inlineBotTitle;
TimeMs _lastScrolled = 0;
QTimer _updateInlineItems;
bool _inlineWithThumb = false;
object_ptr<Ui::RoundButton> _switchPmButton = { nullptr };
QString _switchPmStartToken;
struct Row {
int height = 0;
QVector<ItemBase*> items;
};
QVector<Row> _rows;
void clearInlineRows(bool resultsDeleted);
std::map<Result*, std::unique_ptr<ItemBase>> _inlineLayouts;
ItemBase *layoutPrepareInlineResult(Result *result, int32 position);
bool inlineRowsAddItem(Result *result, Row &row, int32 &sumWidth);
bool inlineRowFinalize(Row &row, int32 &sumWidth, bool force = false);
Row &layoutInlineRow(Row &row, int32 sumWidth = 0);
void deleteUnusedInlineLayouts();
int validateExistingInlineRows(const Results &results);
void selectInlineResult(int row, int column);
int _selected = -1;
int _pressed = -1;
QPoint _lastMousePos;
QTimer _previewTimer;
bool _previewShown = false;
base::lambda<void(Result *result, UserData *bot)> _resultSelectedCallback;
};
} // namespace internal
class Widget : public TWidget, private MTP::Sender {
Q_OBJECT
public:
Widget(QWidget *parent);
void setMinTop(int minTop);
void setMinBottom(int minBottom);
void moveBottom(int bottom);
void hideFast();
bool hiding() const {
return _hiding;
}
void queryInlineBot(UserData *bot, PeerData *peer, QString query);
void clearInlineBot();
bool overlaps(const QRect &globalRect) const;
bool ui_isInlineItemBeingChosen();
void showAnimated();
void hideAnimated();
void setResultSelectedCallback(base::lambda<void(Result *result, UserData *bot)> callback) {
_inner->setResultSelectedCallback(std::move(callback));
}
~Widget();
protected:
void paintEvent(QPaintEvent *e) override;
private slots:
void onWndActiveChanged();
void onScroll();
void onInlineRequest();
void onEmptyInlineRows();
private:
int countBottom() const;
void moveByBottom();
void paintContent(Painter &p);
style::margins innerPadding() const;
// Rounded rect which has shadow around it.
QRect innerRect() const;
// Inner rect with removed st::buttonRadius from top and bottom.
// This one is allowed to be not rounded.
QRect horizontalRect() const;
// Inner rect with removed st::buttonRadius from left and right.
// This one is allowed to be not rounded.
QRect verticalRect() const;
QImage grabForPanelAnimation();
void startShowAnimation();
void startOpacityAnimation(bool hiding);
void prepareCache();
class Container;
void opacityAnimationCallback();
void hideFinished();
void showStarted();
void updateContentHeight();
void inlineBotChanged();
int showInlineRows(bool newResults);
void recountContentMaxHeight();
bool refreshInlineRows(int *added = nullptr);
void inlineResultsDone(const MTPmessages_BotResults &result);
int _minTop = 0;
int _minBottom = 0;
int _contentMaxHeight = 0;
int _contentHeight = 0;
bool _horizontal = false;
int _width = 0;
int _height = 0;
int _bottom = 0;
std::unique_ptr<Ui::PanelAnimation> _showAnimation;
Animation _a_show;
bool _hiding = false;
QPixmap _cache;
Animation _a_opacity;
bool _inPanelGrab = false;
object_ptr<Ui::ScrollArea> _scroll;
QPointer<internal::Inner> _inner;
std::map<QString, std::unique_ptr<internal::CacheEntry>> _inlineCache;
QTimer _inlineRequestTimer;
UserData *_inlineBot = nullptr;
PeerData *_inlineQueryPeer = nullptr;
QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
mtpRequestId _inlineRequestId = 0;
};
} // namespace Layout
} // namespace InlineBots

View File

@ -554,14 +554,6 @@ void MainWidget::ui_repaintHistoryItem(const HistoryItem *item) {
if (_overview) _overview->ui_repaintHistoryItem(item);
}
void MainWidget::ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
_history->ui_repaintInlineItem(layout);
}
bool MainWidget::ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
return _history->ui_isInlineItemVisible(layout);
}
bool MainWidget::ui_isInlineItemBeingChosen() {
return _history->ui_isInlineItemBeingChosen();
}
@ -571,10 +563,6 @@ void MainWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
if (_overview) _overview->notify_historyItemLayoutChanged(item);
}
void MainWidget::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) {
_history->notify_inlineItemLayoutChanged(layout);
}
void MainWidget::notify_historyMuteUpdated(History *history) {
_dialogs->notify_historyMuteUpdated(history);
}
@ -1339,8 +1327,8 @@ void MainWidget::app_sendBotCallback(const HistoryMessageReplyMarkup::Button *bu
_history->app_sendBotCallback(button, msg, row, col);
}
bool MainWidget::insertBotCommand(const QString &cmd, bool specialGif) {
return _history->insertBotCommand(cmd, specialGif);
bool MainWidget::insertBotCommand(const QString &cmd) {
return _history->insertBotCommand(cmd);
}
void MainWidget::searchMessages(const QString &query, PeerData *inPeer) {
@ -1564,7 +1552,7 @@ void MainWidget::handleAudioUpdate(const AudioMsgId &audioId) {
}
if (auto items = InlineBots::Layout::documentItems()) {
for (auto item : items->value(audioId.audio())) {
Ui::repaintInlineItem(item);
item->update();
}
}
}

View File

@ -306,7 +306,7 @@ public:
void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo);
void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);
bool insertBotCommand(const QString &cmd, bool specialGif);
bool insertBotCommand(const QString &cmd);
void jumpToDate(PeerData *peer, const QDate &date);
void searchMessages(const QString &query, PeerData *inPeer);
@ -383,8 +383,6 @@ public:
void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col);
void ui_repaintHistoryItem(const HistoryItem *item);
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemBeingChosen();
void ui_showPeerHistory(quint64 peer, qint32 msgId, Ui::ShowWay way);
PeerData *ui_getPeerForMouseAction();
@ -399,7 +397,6 @@ public:
void notify_migrateUpdated(PeerData *peer);
void notify_clipStopperHidden(ClipStopperType type);
void notify_historyItemLayoutChanged(const HistoryItem *item);
void notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout);
void notify_historyMuteUpdated(History *history);
void notify_handlePendingHistoryUpdate();

View File

@ -61,9 +61,6 @@ DeclareSetting(uint64, RealBetaVersion);
DeclareSetting(QByteArray, BetaPrivateKey);
DeclareSetting(bool, TestMode);
inline QString cInlineGifBotUsername() {
return cTestMode() ? qstr("contextbot") : qstr("gif");
}
DeclareSetting(QString, LoggedPhoneNumber);
DeclareSetting(bool, AutoStart);
DeclareSetting(bool, StartMinimized);

View File

@ -1304,10 +1304,6 @@ void StickerPanInner::hideFinish(bool completely) {
}
clearInstalledLocally();
}
if (_setGifCommand && _section == Section::Gifs) {
App::insertBotCommand(qsl(""), true);
}
_setGifCommand = false;
// Reset to the recent stickers section.
if (_section == Section::Featured) {
@ -1420,7 +1416,6 @@ void StickerPanInner::refreshSavedGifs() {
}
void StickerPanInner::inlineBotChanged() {
_setGifCommand = false;
refreshInlineRows(nullptr, nullptr, true);
}
@ -1445,7 +1440,7 @@ void StickerPanInner::clearInlineRows(bool resultsDeleted) {
InlineItem *StickerPanInner::layoutPrepareSavedGif(DocumentData *doc, int32 position) {
auto it = _gifLayouts.find(doc);
if (it == _gifLayouts.cend()) {
if (auto layout = InlineItem::createLayoutGif(doc)) {
if (auto layout = InlineItem::createLayoutGif(this, doc)) {
it = _gifLayouts.emplace(doc, std::move(layout)).first;
it->second->initDimensions();
} else {
@ -1461,7 +1456,7 @@ InlineItem *StickerPanInner::layoutPrepareSavedGif(DocumentData *doc, int32 posi
InlineItem *StickerPanInner::layoutPrepareInlineResult(InlineResult *result, int32 position) {
auto it = _inlineLayouts.find(result);
if (it == _inlineLayouts.cend()) {
if (auto layout = InlineItem::createLayout(result, _inlineWithThumb)) {
if (auto layout = InlineItem::createLayout(this, result, _inlineWithThumb)) {
it = _inlineLayouts.emplace(result, std::move(layout)).first;
it->second->initDimensions();
} else {
@ -1632,7 +1627,7 @@ int StickerPanInner::refreshInlineRows(UserData *bot, const InlineCacheEntry *en
return true;
}
if (entry->results.empty() && entry->switchPmText.isEmpty()) {
if (!_inlineBot || _inlineBot->username != cInlineGifBotUsername()) {
if (!_inlineBot) {
return true;
}
}
@ -1745,8 +1740,8 @@ int StickerPanInner::validateExistingInlineRows(const InlineResults &results) {
return until;
}
void StickerPanInner::notify_inlineItemLayoutChanged(const InlineItem *layout) {
if (_selected < 0 || !showingInlineItems()) {
void StickerPanInner::inlineItemLayoutChanged(const InlineItem *layout) {
if (_selected < 0 || !showingInlineItems() || !isVisible()) {
return;
}
@ -1758,7 +1753,7 @@ void StickerPanInner::notify_inlineItemLayoutChanged(const InlineItem *layout) {
}
}
void StickerPanInner::ui_repaintInlineItem(const InlineItem *layout) {
void StickerPanInner::inlineItemRepaint(const InlineItem *layout) {
auto ms = getms();
if (_lastScrolled + 100 <= ms) {
update();
@ -1767,9 +1762,9 @@ void StickerPanInner::ui_repaintInlineItem(const InlineItem *layout) {
}
}
bool StickerPanInner::ui_isInlineItemVisible(const InlineItem *layout) {
bool StickerPanInner::inlineItemVisible(const InlineItem *layout) {
int32 position = layout->position();
if (!showingInlineItems() || position < 0) {
if (!showingInlineItems() || position < 0 || !isVisible()) {
return false;
}
@ -2015,12 +2010,12 @@ void StickerPanInner::updateSelected() {
if (_selected != sel) {
if (srow >= 0 && scol >= 0) {
t_assert(srow >= 0 && srow < _inlineRows.size() && scol >= 0 && scol < _inlineRows.at(srow).items.size());
Ui::repaintInlineItem(_inlineRows.at(srow).items.at(scol));
_inlineRows[srow].items[scol]->update();
}
_selected = sel;
if (row >= 0 && col >= 0) {
t_assert(row >= 0 && row < _inlineRows.size() && col >= 0 && col < _inlineRows.at(row).items.size());
Ui::repaintInlineItem(_inlineRows.at(row).items.at(col));
_inlineRows[row].items[col]->update();
}
if (_previewShown && _selected >= 0 && _pressed != _selected) {
_pressed = _selected;
@ -2193,16 +2188,10 @@ void StickerPanInner::showStickerSet(uint64 setId) {
refreshSavedGifs();
emit scrollToY(0);
emit scrollUpdated();
showFinish();
return;
}
if (showingInlineItems()) {
if (_setGifCommand && _section == Section::Gifs) {
App::insertBotCommand(qsl(""), true);
}
_setGifCommand = false;
cSetShowingSavedGifs(false);
emit saveConfigDelayed(kSaveRecentEmojiTimeout);
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
@ -2259,12 +2248,6 @@ void StickerPanInner::updateShowingSavedGifs() {
}
}
void StickerPanInner::showFinish() {
if (_section == Section::Gifs) {
_setGifCommand = App::insertBotCommand('@' + cInlineGifBotUsername(), true);
}
}
EmojiPanel::EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY) : TWidget(parent)
, _wantedY(wantedY)
, _setId(setId)
@ -2388,22 +2371,6 @@ void EmojiSwitchButton::paintEvent(QPaintEvent *e) {
namespace {
FORCE_INLINE uint32 twoImagesOnBgWithAlpha(
const anim::Shifted shiftedBg,
const uint32 source1Alpha,
const uint32 source2Alpha,
const uint32 source1,
const uint32 source2,
const uint32 alpha) {
auto source1Pattern = anim::reshifted(anim::shifted(source1) * source1Alpha);
auto bg1Alpha = 256 - anim::getAlpha(source1Pattern);
auto mixed1Pattern = anim::reshifted(shiftedBg * bg1Alpha) + source1Pattern;
auto source2Pattern = anim::reshifted(anim::shifted(source2) * source2Alpha);
auto bg2Alpha = 256 - anim::getAlpha(source2Pattern);
auto mixed2Pattern = anim::reshifted(mixed1Pattern * bg2Alpha) + source2Pattern;
return anim::unshifted(mixed2Pattern * alpha);
}
FORCE_INLINE uint32 oneImageOnBgWithAlpha(
const anim::Shifted shiftedBg,
const uint32 sourceAlpha,
@ -2966,23 +2933,19 @@ bool EmojiPan::inlineResultsShown() const {
}
int EmojiPan::countBottom() const {
return (_origin == Ui::PanelAnimation::Origin::BottomLeft) ? _bottom : (parentWidget()->height() - _minBottom);
return (parentWidget()->height() - _minBottom);
}
void EmojiPan::moveByBottom() {
if (inlineResultsShown()) {
setOrigin(Ui::PanelAnimation::Origin::BottomLeft);
moveToLeft(0, y());
} else {
setOrigin(Ui::PanelAnimation::Origin::BottomRight);
moveToRight(0, y());
}
moveToRight(0, y());
updateContentHeight();
}
void EmojiPan::enterEventHook(QEvent *e) {
_hideTimer.stop();
if (_hiding) showAnimated(_origin);
if (_hiding) {
showAnimated();
}
}
bool EmojiPan::preventAutoHide() const {
@ -2990,7 +2953,9 @@ bool EmojiPan::preventAutoHide() const {
}
void EmojiPan::leaveEventHook(QEvent *e) {
if (preventAutoHide() || s_inner->inlineResultsShown()) return;
if (preventAutoHide()) {
return;
}
auto ms = getms();
if (_a_show.animating(ms) || _a_opacity.animating(ms)) {
hideAnimated();
@ -3002,7 +2967,7 @@ void EmojiPan::leaveEventHook(QEvent *e) {
void EmojiPan::otherEnter() {
_hideTimer.stop();
showAnimated(_origin);
showAnimated();
}
void EmojiPan::otherLeave() {
@ -3244,7 +3209,7 @@ void EmojiPan::opacityAnimationCallback() {
}
void EmojiPan::hideByTimerOrLeave() {
if (isHidden() || preventAutoHide() || s_inner->inlineResultsShown()) return;
if (isHidden() || preventAutoHide()) return;
hideAnimated();
}
@ -3286,7 +3251,7 @@ void EmojiPan::startShowAnimation() {
_a_opacity = base::take(opacityAnimation);
_cache = base::take(_cache);
_showAnimation = std::make_unique<Ui::PanelAnimation>(st::emojiPanAnimation, _origin);
_showAnimation = std::make_unique<Ui::PanelAnimation>(st::emojiPanAnimation, Ui::PanelAnimation::Origin::BottomRight);
auto inner = rect().marginsRemoved(st::emojiPanMargins);
_showAnimation->setFinalImage(std::move(image), QRect(inner.topLeft() * cIntRetinaFactor(), inner.size() * cIntRetinaFactor()));
auto corners = App::cornersMask(ImageRoundRadius::Small);
@ -3343,12 +3308,7 @@ void EmojiPan::hideFinished() {
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
}
void EmojiPan::setOrigin(Ui::PanelAnimation::Origin origin) {
_origin = origin;
}
void EmojiPan::showAnimated(Ui::PanelAnimation::Origin origin) {
setOrigin(origin);
void EmojiPan::showAnimated() {
_hideTimer.stop();
showStarted();
}
@ -3397,7 +3357,7 @@ bool EmojiPan::eventFilter(QObject *obj, QEvent *e) {
} else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton/* && !dynamic_cast<StickerPan*>(obj)*/) {
if (isHidden() || _hiding) {
_hideTimer.stop();
showAnimated(_origin);
showAnimated();
} else {
hideAnimated();
}
@ -3415,26 +3375,7 @@ void EmojiPan::stickersInstalled(uint64 setId) {
showAll();
s_inner->showStickerSet(setId);
updateContentHeight();
showAnimated(Ui::PanelAnimation::Origin::BottomRight);
}
void EmojiPan::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) {
if (!_emojiShown && !isHidden()) {
s_inner->notify_inlineItemLayoutChanged(layout);
}
}
void EmojiPan::ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
if (!_emojiShown && !isHidden()) {
s_inner->ui_repaintInlineItem(layout);
}
}
bool EmojiPan::ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
if (!_emojiShown && !isHidden()) {
return s_inner->ui_isInlineItemVisible(layout);
}
return false;
showAnimated();
}
bool EmojiPan::ui_isInlineItemBeingChosen() {
@ -3640,9 +3581,6 @@ void EmojiPan::performSwitch() {
} else {
s_inner->updateShowingSavedGifs();
}
if (cShowingSavedGifs()) {
s_inner->showFinish();
}
validateSelectedIcon(ValidateIconAnimations::None);
updateContentHeight();
}
@ -3745,15 +3683,11 @@ bool EmojiPan::overlaps(const QRect &globalRect) const {
|| inner.marginsRemoved(QMargins(0, st::buttonRadius, 0, st::buttonRadius)).contains(testRect);
}
bool EmojiPan::hideOnNoInlineResults() {
return _inlineBot && inlineResultsShown() && (_shownFromInlineQuery || _inlineBot->username != cInlineGifBotUsername());
}
void EmojiPan::inlineBotChanged() {
if (!_inlineBot) return;
if (!isHidden() && !_hiding) {
if (hideOnNoInlineResults() || !rect().contains(mapFromGlobal(QCursor::pos()))) {
if (!rect().contains(mapFromGlobal(QCursor::pos()))) {
hideAnimated();
}
}
@ -3868,7 +3802,7 @@ void EmojiPan::onInlineRequest() {
}
void EmojiPan::onEmptyInlineRows() {
if (_shownFromInlineQuery || hideOnNoInlineResults()) {
if (_shownFromInlineQuery) {
hideAnimated();
s_inner->clearInlineRowsPanel();
} else if (!_inlineBot) {
@ -3906,15 +3840,13 @@ int32 EmojiPan::showInlineRows(bool newResults) {
recountContentMaxHeight();
}
if (clear) {
if (!hidden && hideOnNoInlineResults()) {
hideAnimated();
} else if (!_hiding) {
if (!_hiding) {
_cache = QPixmap(); // clear after refreshInlineRows()
}
} else {
_hideTimer.stop();
if (hidden || _hiding) {
showAnimated(_origin);
showAnimated();
} else if (_emojiShown) {
onSwitch();
}

View File

@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/abstract_button.h"
#include "ui/effects/panel_animation.h"
#include "mtproto/sender.h"
#include "inline_bots/inline_bot_layout_item.h"
namespace InlineBots {
namespace Layout {
@ -199,7 +200,7 @@ struct StickerIcon {
int pixh = 0;
};
class StickerPanInner : public TWidget, private base::Subscriber {
class StickerPanInner : public TWidget, public InlineBots::Layout::Context, private base::Subscriber {
Q_OBJECT
public:
@ -208,7 +209,6 @@ public:
void setMaxHeight(int maxHeight);
void hideFinish(bool completely);
void showFinish();
void showStickerSet(uint64 setId);
void updateShowingSavedGifs();
@ -233,9 +233,9 @@ public:
uint64 currentSet(int yOffset) const;
void notify_inlineItemLayoutChanged(const InlineItem *layout);
void ui_repaintInlineItem(const InlineItem *layout);
bool ui_isInlineItemVisible(const InlineItem *layout);
void inlineItemLayoutChanged(const InlineItem *layout) override;
void inlineItemRepaint(const InlineItem *layout) override;
bool inlineItemVisible(const InlineItem *layout) override;
bool ui_isInlineItemBeingChosen();
bool inlineResultsShown() const {
@ -353,7 +353,6 @@ private:
Stickers,
};
Section _section = Section::Stickers;
bool _setGifCommand = false;
UserData *_inlineBot;
QString _inlineBotTitle;
TimeMs _lastScrolled = 0;
@ -487,13 +486,9 @@ public:
bool overlaps(const QRect &globalRect) const;
void notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout);
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
bool ui_isInlineItemBeingChosen();
void setOrigin(Ui::PanelAnimation::Origin origin);
void showAnimated(Ui::PanelAnimation::Origin origin);
void showAnimated();
void hideAnimated();
~EmojiPan();
@ -614,7 +609,6 @@ private:
int _height = 0;
int _bottom = 0;
Ui::PanelAnimation::Origin _origin = Ui::PanelAnimation::Origin::BottomRight;
std::unique_ptr<Ui::PanelAnimation> _showAnimation;
Animation _a_show;
@ -675,7 +669,6 @@ private:
void inlineBotChanged();
int32 showInlineRows(bool newResults);
bool hideOnNoInlineResults();
void recountContentMaxHeight();
bool refreshInlineRows(int32 *added = 0);
UserData *_inlineBot = nullptr;

View File

@ -206,3 +206,8 @@ hashtagClose: IconButton {
stickersToastMaxWidth: 340px;
stickersToastPadding: margins(16px, 13px, 16px, 12px);
inlineBotsScroll: ScrollArea(defaultSolidScroll) {
deltat: stickerPanPadding;
deltab: stickerPanPadding;
}

View File

@ -1641,7 +1641,7 @@ void DocumentData::notifyLayoutChanged() const {
if (auto items = InlineBots::Layout::documentItems()) {
for (auto item : items->value(const_cast<DocumentData*>(this))) {
Notify::inlineItemLayoutChanged(item);
item->layoutChanged();
}
}
}

View File

@ -125,6 +125,8 @@
<(src_loc)/inline_bots/inline_bot_result.h
<(src_loc)/inline_bots/inline_bot_send_data.cpp
<(src_loc)/inline_bots/inline_bot_send_data.h
<(src_loc)/inline_bots/inline_results_widget.cpp
<(src_loc)/inline_bots/inline_results_widget.h
<(src_loc)/intro/introwidget.cpp
<(src_loc)/intro/introwidget.h
<(src_loc)/intro/introcode.cpp