From fa0c700ca65d5bf602ad889bd3e887a15cf34083 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 8 Apr 2016 18:16:52 +0400 Subject: [PATCH] Inline switch to pm and back support added for inline bots. --- Telegram/Resources/lang.strings | 2 + Telegram/Resources/style.txt | 15 +- Telegram/SourceFiles/dropdown.cpp | 100 +++++++++----- Telegram/SourceFiles/dropdown.h | 33 +++-- Telegram/SourceFiles/facades.cpp | 14 ++ Telegram/SourceFiles/facades.h | 1 + Telegram/SourceFiles/history.cpp | 86 +++++++----- Telegram/SourceFiles/history.h | 86 ++++++++---- Telegram/SourceFiles/historywidget.cpp | 161 +++++++++++++++------- Telegram/SourceFiles/historywidget.h | 6 + Telegram/SourceFiles/localstorage.cpp | 8 +- Telegram/SourceFiles/mainwidget.cpp | 34 ++++- Telegram/SourceFiles/mainwidget.h | 4 + Telegram/SourceFiles/mtproto/core_types.h | 10 +- Telegram/SourceFiles/structs.h | 29 ++-- Telegram/SourceFiles/title.cpp | 4 +- Telegram/SourceFiles/ui/flatbutton.cpp | 23 +++- Telegram/SourceFiles/ui/flatbutton.h | 7 +- 18 files changed, 430 insertions(+), 193 deletions(-) diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index 3e5a90d59..1b56ca4d0 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -815,6 +815,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_forward_messages" = "{count:_not_used_|Forwarded message|# forwarded messages}"; "lng_forwarding_from" = "{user} and {count:_not_used_|# other|# others}"; "lng_forwarding_from_two" = "{user} and {second_user}"; +"lng_inline_switch_choose" = "Choose conversation..."; +"lng_inline_switch_cant" = "Sorry, no way to write here :("; "lng_share_cant" = "Sorry, no way to share here :("; "lng_reply_cant" = "Sorry, no way to reply to an old message in supergroup :("; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index b3b5711ab..917c77ca1 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1090,9 +1090,9 @@ msgBotKbFont: semiboldFont; msgBotKbOverOpacity: 0.1; msgBotKbIconPadding: 2px; msgBotKbUrlIcon: sprite(188px, 338px, 10px, 10px); -msgBotKbCallbackIcon: msgBotKbUrlIcon; -msgBotKbRequestPhoneIcon: msgBotKbUrlIcon; -msgBotKbRequestLocationIcon: msgBotKbUrlIcon; +//msgBotKbRequestPhoneIcon: msgBotKbUrlIcon; +//msgBotKbRequestLocationIcon: msgBotKbUrlIcon; +msgBotKbSwitchPmIcon: sprite(188px, 348px, 10px, 10px); msgBotKbButton: botKeyboardButton { margin: 5px; padding: 10px; @@ -2124,19 +2124,24 @@ botKbButton: botKeyboardButton { padding: 10px; height: 38px; textTop: 9px; - downTextTop: 10px; + downTextTop: 9px; } botKbTinyButton: botKeyboardButton { margin: 4px; padding: 3px; height: 25px; textTop: 2px; - downTextTop: 3px; + downTextTop: 2px; } botKbScroll: flatScroll(solidScroll) { deltax: 3px; width: 10px; } +switchPmButton: BoxButton(defaultBoxButton) { + width: 320px; + height: 34px; + textTop: 7px; +} minPhotoSize: 100px; maxMediaSize: 420px; diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 566950c11..08644945a 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -1194,6 +1194,13 @@ void EmojiPanInner::step_selected(uint64 ms, bool timer) { if (_animations.isEmpty()) _a_selected.stop(); } +void InlineCacheEntry::clearResults() { + for_const (const InlineBots::Result *result, results) { + delete result; + } + results.clear(); +} + void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) { clearSelection(true); @@ -1259,6 +1266,9 @@ int32 StickerPanInner::countHeight(bool plain) { int result = 0, minLastH = plain ? 0 : (_maxHeight - st::stickerPanPadding); if (_showingInlineItems) { result = st::emojiPanHeader; + if (_switchPmButton) { + result += _switchPmButton->height() + st::inlineResultsSkip; + } for (int i = 0, l = _inlineRows.count(); i < l; ++i) { result += _inlineRows.at(i).height; } @@ -1320,19 +1330,23 @@ void StickerPanInner::paintInlineItems(Painter &p, const QRect &r) { } InlineBots::Layout::PaintContext context(getms(), false, Ui::isLayerShown() || Ui::isMediaViewShown() || _previewShown, false); - int32 top = st::emojiPanHeader; - int32 fromx = rtl() ? (width() - r.x() - r.width()) : r.x(), tox = rtl() ? (width() - r.x()) : (r.x() + r.width()); - for (int32 row = 0, rows = _inlineRows.size(); row < rows; ++row) { + int top = st::emojiPanHeader; + if (_switchPmButton) { + top += _switchPmButton->height() + st::inlineResultsSkip; + } + + int fromx = rtl() ? (width() - r.x() - r.width()) : r.x(), tox = rtl() ? (width() - r.x()) : (r.x() + r.width()); + for (int row = 0, rows = _inlineRows.size(); row < rows; ++row) { const InlineRow &inlineRow(_inlineRows.at(row)); if (top >= r.top() + r.height()) break; if (top + inlineRow.height > r.top()) { - int32 left = st::inlineResultsLeft; + int left = st::inlineResultsLeft; if (row == rows - 1) context.lastRow = true; - for (int32 col = 0, cols = inlineRow.items.size(); col < cols; ++col) { + for (int col = 0, cols = inlineRow.items.size(); col < cols; ++col) { if (left >= tox) break; const InlineItem *item = inlineRow.items.at(col); - int32 w = item->width(); + int w = item->width(); if (left + w > fromx) { p.translate(left, top); item->paint(p, r.translated(-left, -top), 0, &context); @@ -1713,7 +1727,7 @@ void StickerPanInner::refreshSavedGifs() { void StickerPanInner::inlineBotChanged() { _setGifCommand = false; - refreshInlineRows(0, InlineResults(), true); + refreshInlineRows(nullptr, nullptr, true); deleteUnusedInlineLayouts(); } @@ -1897,9 +1911,27 @@ void StickerPanInner::clearInlineRowsPanel() { clearInlineRows(false); } -int32 StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted) { +void StickerPanInner::refreshSwitchPmButton(const InlineCacheEntry *entry) { + if (!entry || entry->switchPmText.isEmpty()) { + _switchPmButton.reset(); + _switchPmStartToken.clear(); + } else { + if (!_switchPmButton) { + _switchPmButton = MakeUnique(this, QString(), st::switchPmButton); + _switchPmButton->show(); + _switchPmButton->move(st::inlineResultsLeft, st::emojiPanHeader); + connect(_switchPmButton.data(), SIGNAL(clicked()), this, SLOT(onSwitchPm())); + } + _switchPmButton->setText(entry->switchPmText); // doesn't perform text.toUpper() + _switchPmStartToken = entry->switchPmStartToken; + } + update(); +} + +int StickerPanInner::refreshInlineRows(UserData *bot, const InlineCacheEntry *entry, bool resultsDeleted) { _inlineBot = bot; - if (results.isEmpty() && (!_inlineBot || _inlineBot->username != cInlineGifBotUsername())) { + refreshSwitchPmButton(entry); + if (!entry || entry->results.isEmpty() && (!_inlineBot || _inlineBot->username != cInlineGifBotUsername())) { if (resultsDeleted) { clearInlineRows(true); } @@ -1916,7 +1948,7 @@ int32 StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &res _showingSavedGifs = false; _settings.hide(); - int32 count = results.size(), from = validateExistingInlineRows(results), added = 0; + int32 count = entry->results.size(), from = validateExistingInlineRows(entry->results), added = 0; if (count) { _inlineRows.reserve(count); @@ -1924,7 +1956,7 @@ int32 StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &res row.items.reserve(InlineItemsMaxPerRow); int32 sumWidth = 0; for (int32 i = from; i < count; ++i) { - if (inlineRowsAddItem(0, results.at(i), row, sumWidth)) { + if (inlineRowsAddItem(0, entry->results.at(i), row, sumWidth)) { ++added; } } @@ -2180,14 +2212,18 @@ void StickerPanInner::updateSelected() { QPoint p(mapFromGlobal(_lastMousePos)); if (_showingInlineItems) { - int sx = (rtl() ? width() - p.x() : p.x()) - st::inlineResultsLeft, sy = p.y() - st::emojiPanHeader; - int32 row = -1, col = -1, sel = -1; + int sx = (rtl() ? width() - p.x() : p.x()) - st::inlineResultsLeft; + int sy = p.y() - st::emojiPanHeader; + if (_switchPmButton) { + sy -= _switchPmButton->height() + st::inlineResultsSkip; + } + int row = -1, col = -1, sel = -1; ClickHandlerPtr lnk; ClickHandlerHost *lnkhost = nullptr; HistoryCursorState cursor = HistoryDefaultCursorState; if (sy >= 0) { row = 0; - for (int32 rows = _inlineRows.size(); row < rows; ++row) { + for (int rows = _inlineRows.size(); row < rows; ++row) { if (sy < _inlineRows.at(row).height) { break; } @@ -2359,6 +2395,13 @@ void StickerPanInner::onUpdateInlineItems() { } } +void StickerPanInner::onSwitchPm() { + if (_inlineBot && _inlineBot->botInfo) { + _inlineBot->botInfo->startToken = _switchPmStartToken; + Ui::showPeerHistory(_inlineBot, ShowAndStartBotMsgId); + } +} + void StickerPanInner::step_selected(uint64 ms, bool timer) { QRegion toUpdate; for (Animations::iterator i = _animations.begin(); i != _animations.end();) { @@ -3359,7 +3402,7 @@ bool EmojiPan::ui_isInlineItemBeingChosen() { } void EmojiPan::notify_automaticLoadSettingsChangedGif() { - for_const (const InlineCacheEntry *entry, _inlineCache) { + for_const (const internal::InlineCacheEntry *entry, _inlineCache) { for_const (InlineBots::Result *l, entry->results) { l->automaticLoadSettingsChangedGif(); } @@ -3600,13 +3643,6 @@ bool EmojiPan::hideOnNoInlineResults() { return _inlineBot && _stickersShown && s_inner.inlineResultsShown() && (_shownFromInlineQuery || _inlineBot->username != cInlineGifBotUsername()); } -void EmojiPan::InlineCacheEntry::clearResults() { - for_const (const InlineBots::Result *result, results) { - delete result; - } - results.clear(); -} - void EmojiPan::inlineBotChanged() { if (!_inlineBot) return; @@ -3643,13 +3679,13 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) { uint64 queryId(d.vquery_id.v); if (!adding) { - it = _inlineCache.insert(_inlineQuery, new InlineCacheEntry()); + it = _inlineCache.insert(_inlineQuery, new internal::InlineCacheEntry()); } it.value()->nextOffset = qs(d.vnext_offset); if (d.has_switch_pm() && d.vswitch_pm.type() == mtpc_inlineBotSwitchPM) { const auto &switchPm = d.vswitch_pm.c_inlineBotSwitchPM(); it.value()->switchPmText = qs(switchPm.vtext); - it.value()->switchPmStartParam = qs(switchPm.vstart_param); + it.value()->switchPmStartToken = qs(switchPm.vstart_param); } if (int count = v.size()) { @@ -3657,7 +3693,7 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) { } int added = 0; for_const (const auto &res, v) { - if (UniquePointer result = InlineBots::Result::create(queryId, res)) { + if (auto result = InlineBots::Result::create(queryId, res)) { ++added; it.value()->results.push_back(result.release()); } @@ -3740,16 +3776,18 @@ void EmojiPan::onEmptyInlineRows() { } bool EmojiPan::refreshInlineRows(int32 *added) { - bool clear = true; - InlineCache::const_iterator i = _inlineCache.constFind(_inlineQuery); + auto i = _inlineCache.constFind(_inlineQuery); + const internal::InlineCacheEntry *entry = nullptr; if (i != _inlineCache.cend()) { - clear = i.value()->results.isEmpty(); + if (!i.value()->results.isEmpty()) { + entry = i.value(); + } _inlineNextOffset = i.value()->nextOffset; } - if (clear) prepareShowHideCache(); - int32 result = s_inner.refreshInlineRows(_inlineBot, clear ? internal::InlineResults() : i.value()->results, false); + if (!entry) prepareShowHideCache(); + int32 result = s_inner.refreshInlineRows(_inlineBot, entry, false); if (added) *added = result; - return !clear; + return (entry != nullptr); } int32 EmojiPan::showInlineRows(bool newResults) { diff --git a/Telegram/SourceFiles/dropdown.h b/Telegram/SourceFiles/dropdown.h index 93d40b6c7..49531c364 100644 --- a/Telegram/SourceFiles/dropdown.h +++ b/Telegram/SourceFiles/dropdown.h @@ -173,6 +173,16 @@ using InlineResult = InlineBots::Result; using InlineResults = QList; using InlineItem = InlineBots::Layout::ItemBase; +struct InlineCacheEntry { + ~InlineCacheEntry() { + clearResults(); + } + QString nextOffset; + QString switchPmText, switchPmStartToken; + InlineResults results; // owns this results list + void clearResults(); +}; + class EmojiColorPicker : public TWidget { Q_OBJECT @@ -358,7 +368,7 @@ public: void refreshStickers(); void refreshRecentStickers(bool resize = true); void refreshSavedGifs(); - int32 refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted); + int refreshInlineRows(UserData *bot, const InlineCacheEntry *results, bool resultsDeleted); void refreshRecent(); void inlineBotChanged(); void hideInlineRowsPanel(); @@ -384,12 +394,13 @@ public: ~StickerPanInner(); -public slots: +private slots: void updateSelected(); void onSettings(); void onPreview(); void onUpdateInlineItems(); + void onSwitchPm(); signals: @@ -416,13 +427,15 @@ private: void paintInlineItems(Painter &p, const QRect &r); void paintStickers(Painter &p, const QRect &r); - int32 _maxHeight; + void refreshSwitchPmButton(const InlineCacheEntry *entry); void appendSet(uint64 setId); void selectEmoji(EmojiPtr emoji); QRect stickerRect(int tab, int sel); + int32 _maxHeight; + typedef QMap Animations; // index - showing, -index - hiding Animations _animations; Animation _a_selected; @@ -449,6 +462,9 @@ private: QTimer _updateInlineItems; bool _inlineWithThumb; + UniquePointer _switchPmButton; + QString _switchPmStartToken; + typedef QVector InlineItems; struct InlineRow { InlineRow() : height(0) { @@ -705,16 +721,7 @@ private: QTimer _saveConfigTimer; // inline bots - struct InlineCacheEntry { - ~InlineCacheEntry() { - clearResults(); - } - QString nextOffset; - QString switchPmText, switchPmStartParam; - internal::InlineResults results; - void clearResults(); - }; - typedef QMap InlineCache; + typedef QMap InlineCache; InlineCache _inlineCache; QTimer _inlineRequestTimer; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 508a0e491..2dc0cf2c1 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -83,6 +83,14 @@ namespace App { box->connect(box, SIGNAL(confirmed(PeerData*)), App::main(), SLOT(onSharePhoneWithBot(PeerData*))); Ui::showLayer(box); } break; + + case HistoryMessageReplyMarkup::Button::SwitchInline: { + if (MainWidget *m = App::main()) { + if (UserData *bot = msg->history()->peer->asUser()) { + m->inlineSwitchLayer('@' + bot->username + ' ' + QString::fromUtf8(button->data)); + } + } + } break; } } @@ -266,6 +274,12 @@ namespace Notify { } } + void switchInlineBotButtonReceived(const QString &query) { + if (MainWidget *m = App::main()) { + m->notify_switchInlineBotButtonReceived(query); + } + } + void migrateUpdated(PeerData *peer) { if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer); } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index f6a83571d..862652c9b 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -103,6 +103,7 @@ namespace Notify { void inlineBotRequesting(bool requesting); void replyMarkupUpdated(const HistoryItem *item); void inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); + void switchInlineBotButtonReceived(const QString &query); void migrateUpdated(PeerData *peer); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 554648925..3b5a04d89 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -258,32 +258,9 @@ void FakeDialogRow::paint(Painter &p, int32 w, bool act, bool sel, bool onlyBack history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); } -History::History(const PeerId &peerId) : width(0), height(0) -, unreadCount(0) -, inboxReadBefore(1) -, outboxReadBefore(1) -, showFrom(nullptr) -, unreadBar(nullptr) -, peer(App::peer(peerId)) -, oldLoaded(false) -, newLoaded(true) -, lastMsg(0) -, msgDraft(0) -, editDraft(0) -, showAtMsgId(ShowAtUnreadMsgId) -, scrollTopItem(nullptr) -, scrollTopOffset(0) -, mute(isNotifyMuted(peer->notify)) -, lastKeyboardInited(false) -, lastKeyboardUsed(false) -, lastKeyboardId(0) -, lastKeyboardHiddenId(0) -, lastKeyboardFrom(0) -, sendRequestId(0) -, textCachedFor(0) -, lastItemTextCache(st::dlgRichMinWidth) -, typingText(st::dlgRichMinWidth) -, _sortKeyInChatList(0) { +History::History(const PeerId &peerId) +: peer(App::peer(peerId)) +, mute(isNotifyMuted(peer->notify)) { if (peer->isChannel() || (peer->isUser() && peer->asUser()->botInfo)) { outboxReadBefore = INT_MAX; } @@ -1191,11 +1168,40 @@ void Histories::remove(const PeerId &peer) { } } +namespace { + +void checkForSwitchInlineButton(HistoryItem *item) { + if (item->out() || !item->hasSwitchInlineButton()) { + return; + } + if (UserData *user = item->history()->peer->asUser()) { + if (!user->botInfo || !user->botInfo->inlineReturnPeerId) { + return; + } + if (auto markup = item->Get()) { + for_const (const auto &row, markup->rows) { + for_const (const auto &button, row) { + if (button.type == HistoryMessageReplyMarkup::Button::SwitchInline) { + Notify::switchInlineBotButtonReceived(QString::fromUtf8(button.data)); + return; + } + } + } + } + } +} + +} // namespace + HistoryItem *Histories::addNewMessage(const MTPMessage &msg, NewMessageType type) { PeerId peer = peerFromMessage(msg); - if (!peer) return 0; + if (!peer) return nullptr; - return findOrInsert(peer, 0, 0)->addNewMessage(msg, type); + HistoryItem *result = findOrInsert(peer, 0, 0)->addNewMessage(msg, type); + if (result && type == NewMessageUnread) { + checkForSwitchInlineButton(result); + } + return result; } HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem) { @@ -2614,8 +2620,6 @@ void History::removeBlock(HistoryBlock *block) { History::~History() { clearOnDestroy(); - deleteAndMark(msgDraft); - deleteAndMark(editDraft); } int HistoryBlock::resizeGetHeight(int newWidth, bool resizeAllItems) { @@ -3047,6 +3051,7 @@ void HistoryMessageReplyMarkup::createFromButtonRows(const QVector 0) { result = std::min(result, iconWidth + 2 * int(st::msgBotKbIconPadding)); @@ -6855,6 +6864,9 @@ void HistoryMessage::createComponents(const CreateConfig &config) { } if (auto markup = Get()) { markup->create(*config.markup); + if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button) { + _flags |= MTPDmessage_ClientFlag::f_has_switch_inline_button; + } } initTime(); } diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 0d0729c9c..e7004fd5c 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -351,31 +351,53 @@ public: typedef QList Blocks; Blocks blocks; - int32 width, height, msgCount, unreadCount; - int32 inboxReadBefore, outboxReadBefore; - HistoryItem *showFrom; - HistoryItem *unreadBar; + int width = 0; + int height = 0; + int32 msgCount = 0; + int32 unreadCount = 0; + MsgId inboxReadBefore = 1; + MsgId outboxReadBefore = 1; + HistoryItem *showFrom = nullptr; + HistoryItem *unreadBar = nullptr; PeerData *peer; - bool oldLoaded, newLoaded; - HistoryItem *lastMsg; + bool oldLoaded = false; + bool newLoaded = true; + HistoryItem *lastMsg = nullptr; QDateTime lastMsgDate; typedef QList NotifyQueue; NotifyQueue notifies; - HistoryDraft *msgDraft; - HistoryEditDraft *editDraft; + HistoryDraft *msgDraft() { + return _msgDraft.data(); + } + HistoryEditDraft *editDraft() { + return _editDraft.data(); + } + void setMsgDraft(UniquePointer &&draft) { + _msgDraft = std_::move(draft); + } + void takeMsgDraft(History *from) { + if (auto &draft = from->_msgDraft) { + if (!draft->text.isEmpty() && !_msgDraft) { + _msgDraft = std_::move(draft); + _msgDraft->msgId = 0; // edit and reply to drafts can't migrate + } + from->clearMsgDraft(); + } + } + void setEditDraft(UniquePointer &&draft) { + _editDraft = std_::move(draft); + } + void clearMsgDraft() { + _msgDraft.clear(); + } + void clearEditDraft() { + _editDraft.clear(); + } HistoryDraft *draft() { - return editDraft ? editDraft : msgDraft; - } - void setMsgDraft(HistoryDraft *draft) { - if (msgDraft) delete msgDraft; - msgDraft = draft; - } - void setEditDraft(HistoryEditDraft *draft) { - if (editDraft) delete editDraft; - editDraft = draft; + return _editDraft ? editDraft() : msgDraft(); } // some fields below are a property of a currently displayed instance of this @@ -383,13 +405,13 @@ public: public: // we save the last showAtMsgId to restore the state when switching // between different conversation histories - MsgId showAtMsgId; + MsgId showAtMsgId = ShowAtUnreadMsgId; // we save a pointer of the history item at the top of the displayed window // together with an offset from the window top to the top of this message // resulting scrollTop = top(scrollTopItem) + scrollTopOffset - HistoryItem *scrollTopItem; - int scrollTopOffset; + HistoryItem *scrollTopItem = nullptr; + int scrollTopOffset = 0; void forgetScrollState() { scrollTopItem = nullptr; } @@ -412,21 +434,23 @@ public: bool mute; - bool lastKeyboardInited, lastKeyboardUsed; - MsgId lastKeyboardId, lastKeyboardHiddenId; - PeerId lastKeyboardFrom; + bool lastKeyboardInited = false; + bool lastKeyboardUsed = false; + MsgId lastKeyboardId = 0; + MsgId lastKeyboardHiddenId = 0; + PeerId lastKeyboardFrom = 0; - mtpRequestId sendRequestId; + mtpRequestId sendRequestId = 0; - mutable const HistoryItem *textCachedFor; // cache - mutable Text lastItemTextCache; + mutable const HistoryItem *textCachedFor = nullptr; // cache + mutable Text lastItemTextCache = Text{ int(st::dlgRichMinWidth) }; typedef QMap TypingUsers; TypingUsers typing; typedef QMap SendActionUsers; SendActionUsers sendActions; QString typingStr; - Text typingText; + Text typingText = Text{ int(st::dlgRichMinWidth) }; uint32 typingDots; QMap mySendActions; @@ -536,7 +560,7 @@ private: t_assert(it != _chatListLinks.cend()); return it.value(); } - uint64 _sortKeyInChatList; // like ((unixtime) << 32) | (incremented counter) + uint64 _sortKeyInChatList = 0; // like ((unixtime) << 32) | (incremented counter) typedef QMap MediaOverviewIds; MediaOverviewIds overviewIds[OverviewCount]; @@ -555,6 +579,9 @@ private: // Depending on isBuildingFrontBlock() gets front or back block. HistoryBlock *prepareBlockForAddingItem(); + UniquePointer _msgDraft; + UniquePointer _editDraft; + }; class HistoryGroup; @@ -1425,6 +1452,9 @@ public: // MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag return qFlags(MTPDreplyKeyboardMarkup_ClientFlag::f_zero); } + bool hasSwitchInlineButton() const { + return _flags & MTPDmessage_ClientFlag::f_has_switch_inline_button; + } bool hasTextLinks() const { return _flags & MTPDmessage_ClientFlag::f_has_text_links; } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 203bd7de0..f35442dca 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -2404,6 +2404,23 @@ HistoryHider::HistoryHider(MainWidget *parent) : TWidget(parent) init(); } +HistoryHider::HistoryHider(MainWidget *parent, const QString &botAndQuery) : TWidget(parent) +, _sharedContact(0) +, _forwardSelected(false) +, _sendPath(false) +, _botAndQuery(botAndQuery) +, _send(this, lang(lng_forward_send), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +, offered(0) +, a_opacity(0, 1) +, _a_appearance(animation(this, &HistoryHider::step_appearance)) +, hiding(false) +, _forwardRequest(0) +, toTextWidth(0) +, shadow(st::boxShadow) { + init(); +} + HistoryHider::HistoryHider(MainWidget *parent, const QString &url, const QString &text) : TWidget(parent) , _sharedContact(0) , _forwardSelected(false) @@ -2427,7 +2444,7 @@ void HistoryHider::init() { connect(&_cancel, SIGNAL(clicked()), this, SLOT(startHide())); connect(App::wnd()->getTitle(), SIGNAL(hiderClicked()), this, SLOT(startHide())); - _chooseWidth = st::forwardFont->width(lang(lng_forward_choose)); + _chooseWidth = st::forwardFont->width(lang(_botAndQuery.isEmpty() ? lng_forward_choose : lng_inline_switch_choose)); resizeEvent(0); _a_appearance.start(); @@ -2474,7 +2491,7 @@ void HistoryHider::paintEvent(QPaintEvent *e) { App::roundRect(p, (width() - w) / 2, (height() - h) / 2, w, h, st::forwardBg, ForwardCorners); p.setPen(st::white->p); - p.drawText(box, lang(lng_forward_choose), QTextOption(style::al_center)); + p.drawText(box, lang(_botAndQuery.isEmpty() ? lng_forward_choose : lng_inline_switch_choose), QTextOption(style::al_center)); } } else { p.drawPixmap(box.left(), box.top(), cacheForAnim); @@ -2529,6 +2546,8 @@ void HistoryHider::forward() { parent()->onSendPaths(offered->id); } else if (!_shareUrl.isEmpty()) { parent()->onShareUrl(offered->id, _shareUrl, _shareText); + } else if (!_botAndQuery.isEmpty()) { + parent()->onInlineSwitchChosen(offered->id, _botAndQuery); } else { parent()->onForward(offered->id, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage); } @@ -2593,6 +2612,13 @@ bool HistoryHider::offerPeer(PeerId peer) { startHide(); } return false; + } else if (!_botAndQuery.isEmpty()) { + PeerId to = offered->id; + offered = 0; + if (parent()->onInlineSwitchChosen(to, _botAndQuery)) { + startHide(); + } + return false; } else { PeerId to = offered->id; offered = 0; @@ -2974,7 +3000,8 @@ void HistoryWidget::onDraftSave(bool delayed) { } void HistoryWidget::writeDrafts(HistoryDraft **msgDraft, HistoryEditDraft **editDraft) { - if (!msgDraft && _editMsgId) msgDraft = &_history->msgDraft; + HistoryDraft *historyMsgDraft = _history ? _history->msgDraft() : nullptr; + if (!msgDraft && _editMsgId) msgDraft = &historyMsgDraft; bool save = _peer && (_saveDraftStart > 0); _saveDraftStart = 0; @@ -3029,13 +3056,13 @@ void HistoryWidget::writeDrafts(HistoryDraft **msgDraft, HistoryEditDraft **edit void HistoryWidget::writeDrafts(History *history) { Local::MessageDraft localMsgDraft, localEditDraft; MessageCursor msgCursor, editCursor; - if (history->msgDraft) { - localMsgDraft = Local::MessageDraft(history->msgDraft->msgId, history->msgDraft->text, history->msgDraft->previewCancelled); - msgCursor = history->msgDraft->cursor; + if (auto msgDraft = history->msgDraft()) { + localMsgDraft = Local::MessageDraft(msgDraft->msgId, msgDraft->text, msgDraft->previewCancelled); + msgCursor = msgDraft->cursor; } - if (history->editDraft) { - localEditDraft = Local::MessageDraft(history->editDraft->msgId, history->editDraft->text, history->editDraft->previewCancelled); - editCursor = history->editDraft->cursor; + if (auto editDraft = history->editDraft()) { + localEditDraft = Local::MessageDraft(editDraft->msgId, editDraft->text, editDraft->previewCancelled); + editCursor = editDraft->cursor; } Local::writeDrafts(history->peer->id, localMsgDraft, localEditDraft); Local::writeDraftCursors(history->peer->id, msgCursor, editCursor); @@ -3201,6 +3228,25 @@ void HistoryWidget::notify_inlineKeyboardMoved(const HistoryItem *item, int oldK } } +void HistoryWidget::notify_switchInlineBotButtonReceived(const QString &query) { + if (!_peer) { + return; + } + if (UserData *bot = _peer->asUser()) { + if (!bot->botInfo || !bot->botInfo->inlineReturnPeerId) { + return; + } + History *h = App::history(bot->botInfo->inlineReturnPeerId); + auto text = '@' + bot->username + ' ' + query; + h->setMsgDraft(MakeUnique(text, 0, MessageCursor(text.size(), text.size(), QFIXED_MAX), false)); + if (h == _history) { + applyDraft(); + } else { + Ui::showPeerHistory(bot->botInfo->inlineReturnPeerId, ShowAtUnreadMsgId); + } + } +} + void HistoryWidget::notify_userIsBotChanged(UserData *user) { if (_peer && _peer == user) { _list->notifyIsBotChanged(); @@ -3480,7 +3526,7 @@ void HistoryWidget::fastShowAtEnd(History *h) { } void HistoryWidget::applyDraft(bool parseLinks) { - HistoryDraft *draft = _history ? _history->draft() : 0; + HistoryDraft *draft = _history ? _history->draft() : nullptr; if (!draft) { setFieldText(QString()); _field.setFocus(); @@ -3494,12 +3540,12 @@ void HistoryWidget::applyDraft(bool parseLinks) { draft->cursor.applyTo(_field); _textUpdateEventsFlags = TextUpdateEventsSaveDraft | TextUpdateEventsSendTyping; _previewCancelled = draft->previewCancelled; - if (_history->editDraft) { - _editMsgId = _history->editDraft->msgId; + if (auto editDraft = _history->editDraft()) { + _editMsgId = editDraft->msgId; _replyToId = 0; } else { _editMsgId = 0; - _replyToId = readyToForward() ? 0 : _history->msgDraft->msgId; + _replyToId = readyToForward() ? 0 : _history->msgDraft()->msgId; } if (parseLinks) { onPreviewParse(); @@ -3516,6 +3562,11 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re MsgId wasMsgId = _showAtMsgId; History *wasHistory = _history; + bool startBot = (showAtMsgId == ShowAndStartBotMsgId); + if (startBot) { + showAtMsgId = ShowAtTheEndMsgId; + } + if (_history) { if (_peer->id == peerId && !reload) { _history->forgetScrollState(); @@ -3555,6 +3606,13 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re App::main()->topBar()->update(); update(); + + if (startBot && _peer->isUser() && _peer->asUser()->botInfo) { + if (wasHistory) _peer->asUser()->botInfo->inlineReturnPeerId = wasHistory->peer->id; + onBotStart(); + _history->clearMsgDraft(); + applyDraft(); + } return; } if (_history->mySendActions.contains(SendActionTyping)) { @@ -3571,21 +3629,23 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re if (_history) { if (_editMsgId) { - _history->setEditDraft(new HistoryEditDraft(_field, _editMsgId, _previewCancelled, _saveEditMsgRequestId)); + _history->setEditDraft(MakeUnique(_field, _editMsgId, _previewCancelled, _saveEditMsgRequestId)); } else { if (_replyToId || !_field.getLastText().isEmpty()) { - _history->setMsgDraft(new HistoryDraft(_field, _replyToId, _previewCancelled)); + _history->setMsgDraft(MakeUnique(_field, _replyToId, _previewCancelled)); } else { - _history->setMsgDraft(nullptr); + _history->clearMsgDraft(); } - _history->setEditDraft(nullptr); + _history->clearEditDraft(); } if (_migrated) { - _migrated->setMsgDraft(nullptr); // use migrated draft only once - _migrated->setEditDraft(nullptr); + _migrated->clearEditDraft(); // use migrated draft only once + _migrated->clearEditDraft(); } - writeDrafts(&_history->msgDraft, &_history->editDraft); + auto msgDraft = _history->msgDraft(); + auto editDraft = _history->editDraft(); + writeDrafts(&msgDraft, &editDraft); _history->showAtMsgId = _showAtMsgId; @@ -3618,7 +3678,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re _showAtMsgId = showAtMsgId; _histInited = false; - _peer = peerId ? App::peer(peerId) : 0; + _peer = peerId ? App::peer(peerId) : nullptr; _channel = _peer ? peerToChannel(_peer->id) : NoChannel; _canSendMessages = canSendMessages(_peer); if (_peer && _peer->isChannel()) { @@ -3695,14 +3755,8 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re Local::readDraftsWithCursors(_history); if (_migrated) { Local::readDraftsWithCursors(_migrated); - _migrated->setEditDraft(nullptr); - if (_migrated->msgDraft && !_migrated->msgDraft->text.isEmpty()) { - _migrated->msgDraft->msgId = 0; // edit and reply to drafts can't migrate - if (!_history->msgDraft) { - _history->setMsgDraft(new HistoryDraft(*_migrated->msgDraft)); - } - } - _migrated->setMsgDraft(nullptr); + _migrated->clearEditDraft(); + _history->takeMsgDraft(_migrated); } applyDraft(false); @@ -3713,6 +3767,11 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re connect(&_scroll, SIGNAL(geometryChanged()), _list, SLOT(onParentGeometryChanged())); connect(&_scroll, SIGNAL(scrolled()), _list, SLOT(onUpdateSelected())); + + if (startBot && _peer->isUser() && _peer->asUser()->botInfo) { + if (wasHistory) _peer->asUser()->botInfo->inlineReturnPeerId = wasHistory->peer->id; + onBotStart(); + } } else { setFieldText(QString()); doneShow(); @@ -4636,9 +4695,11 @@ void HistoryWidget::saveEditMsgDone(History *history, const MTPUpdates &updates, _saveEditMsgRequestId = 0; cancelEdit(); } - if (history->editDraft && history->editDraft->saveRequest == req) { - history->setEditDraft(nullptr); - writeDrafts(history); + if (auto editDraft = history->editDraft()) { + if (editDraft->saveRequest == req) { + history->clearEditDraft(); + writeDrafts(history); + } } } @@ -4647,8 +4708,10 @@ bool HistoryWidget::saveEditMsgFail(History *history, const RPCError &error, mtp if (req == _saveEditMsgRequestId) { _saveEditMsgRequestId = 0; } - if (history->editDraft && history->editDraft->saveRequest == req) { - history->editDraft->saveRequest = 0; + if (auto editDraft = history->editDraft()) { + if (editDraft->saveRequest == req) { + editDraft->saveRequest = 0; + } } QString err = error.type(); @@ -7105,10 +7168,10 @@ void HistoryWidget::onReplyToMessage() { App::main()->cancelForwarding(); if (_editMsgId) { - if (!_history->msgDraft) { - _history->setMsgDraft(new HistoryDraft(QString(), to->id, MessageCursor(), false)); + if (auto msgDraft = _history->msgDraft()) { + msgDraft->msgId = to->id; } else { - _history->msgDraft->msgId = to->id; + _history->setMsgDraft(MakeUnique(QString(), to->id, MessageCursor(), false)); } } else { _replyEditMsg = to; @@ -7142,13 +7205,13 @@ void HistoryWidget::onEditMessage() { delete box; if (_replyToId || !_field.getLastText().isEmpty()) { - _history->setMsgDraft(new HistoryDraft(_field, _replyToId, _previewCancelled)); + _history->setMsgDraft(MakeUnique(_field, _replyToId, _previewCancelled)); } else { - _history->setMsgDraft(nullptr); + _history->clearMsgDraft(); } QString text(textApplyEntities(to->originalText(), to->originalEntities())); - _history->setEditDraft(new HistoryEditDraft(text, to->id, MessageCursor(text.size(), text.size(), QFIXED_MAX), false)); + _history->setEditDraft(MakeUnique(text, to->id, MessageCursor(text.size(), text.size(), QFIXED_MAX), false)); applyDraft(false); _previewData = 0; @@ -7249,8 +7312,10 @@ bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const { } void HistoryWidget::cancelReply(bool lastKeyboardUsed) { - bool wasReply = _replyToId || (_history && _history->msgDraft && _history->msgDraft->msgId); + bool wasReply = false; ; if (_replyToId) { + wasReply = true; + _replyEditMsg = 0; _replyToId = 0; mouseMoveEvent(0); @@ -7263,11 +7328,13 @@ void HistoryWidget::cancelReply(bool lastKeyboardUsed) { resizeEvent(0); update(); - } else if (wasReply) { - if (_history->msgDraft->text.isEmpty()) { - _history->setMsgDraft(nullptr); - } else { - _history->msgDraft->msgId = 0; + } else if (auto msgDraft = (_history ? _history->msgDraft() : nullptr)) { + if (msgDraft->msgId) { + if (msgDraft->text.isEmpty()) { + _history->clearMsgDraft(); + } else { + msgDraft->msgId = 0; + } } } if (wasReply) { @@ -7287,7 +7354,7 @@ void HistoryWidget::cancelEdit() { _editMsgId = 0; _replyEditMsg = 0; - _history->setEditDraft(nullptr); + _history->clearEditDraft(); applyDraft(); if (_saveEditMsgRequestId) { diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 6a9ce10ae..e314c6e26 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -398,6 +398,7 @@ public: HistoryHider(MainWidget *parent, UserData *sharedContact); // share contact HistoryHider(MainWidget *parent); // send path from command line argument HistoryHider(MainWidget *parent, const QString &url, const QString &text); // share url + HistoryHider(MainWidget *parent, const QString &botAndQuery); // inline switch button handler void step_appearance(float64 ms, bool timer); bool withConfirm() const; @@ -409,6 +410,9 @@ public: bool offerPeer(PeerId peer); QString offeredText() const; + QString botAndQuery() const { + return _botAndQuery; + } bool wasOffered() const; @@ -434,6 +438,7 @@ private: bool _forwardSelected, _sendPath; QString _shareUrl, _shareText; + QString _botAndQuery; BoxButton _send, _cancel; PeerData *offered; @@ -685,6 +690,7 @@ public: void notify_inlineBotRequesting(bool requesting); void notify_replyMarkupUpdated(const HistoryItem *item); void notify_inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); + void notify_switchInlineBotButtonReceived(const QString &query); void notify_userIsBotChanged(UserData *user); void notify_migrateUpdated(PeerData *peer); void notify_clipStopperHidden(ClipStopperType type); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 035b1b5a3..84c871665 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -2441,14 +2441,14 @@ namespace Local { _readDraftCursors(peer, msgCursor, editCursor); if (msgText.isEmpty() && !msgReplyTo) { - h->setMsgDraft(nullptr); + h->clearMsgDraft(); } else { - h->setMsgDraft(new HistoryDraft(msgText, msgReplyTo, msgCursor, msgPreviewCancelled)); + h->setMsgDraft(MakeUnique(msgText, msgReplyTo, msgCursor, msgPreviewCancelled)); } if (!editMsgId) { - h->setEditDraft(nullptr); + h->clearEditDraft(); } else { - h->setEditDraft(new HistoryEditDraft(editText, editMsgId, editCursor, editPreviewCancelled)); + h->setEditDraft(MakeUnique(editText, editMsgId, editCursor, editPreviewCancelled)); } } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 27c440187..b4243bda6 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -508,8 +508,26 @@ bool MainWidget::onShareUrl(const PeerId &peer, const QString &url, const QStrin return false; } History *h = App::history(peer); - h->setMsgDraft(new HistoryDraft(url + '\n' + text, 0, MessageCursor(url.size() + 1, url.size() + 1 + text.size(), QFIXED_MAX), false)); - h->setEditDraft(nullptr); + h->setMsgDraft(MakeUnique(url + '\n' + text, 0, MessageCursor(url.size() + 1, url.size() + 1 + text.size(), QFIXED_MAX), false)); + h->clearEditDraft(); + bool opened = history.peer() && (history.peer()->id == peer); + if (opened) { + history.applyDraft(); + } else { + Ui::showPeerHistory(peer, ShowAtUnreadMsgId); + } + return true; +} + +bool MainWidget::onInlineSwitchChosen(const PeerId &peer, const QString &botAndQuery) { + PeerData *p = App::peer(peer); + if (!peer || (p->isChannel() && !p->asChannel()->canPublish() && p->asChannel()->isBroadcast()) || (p->isChat() && !p->asChat()->canWrite()) || (p->isUser() && p->asUser()->access == UserNoAccess)) { + Ui::showLayer(new InformBox(lang(lng_inline_switch_cant))); + return false; + } + History *h = App::history(peer); + h->setMsgDraft(MakeUnique(botAndQuery, 0, MessageCursor(botAndQuery.size(), botAndQuery.size(), QFIXED_MAX), false)); + h->clearEditDraft(); bool opened = history.peer() && (history.peer()->id == peer); if (opened) { history.applyDraft(); @@ -752,6 +770,10 @@ void MainWidget::notify_inlineKeyboardMoved(const HistoryItem *item, int oldKeyb history.notify_inlineKeyboardMoved(item, oldKeyboardTop, newKeyboardTop); } +void MainWidget::notify_switchInlineBotButtonReceived(const QString &query) { + history.notify_switchInlineBotButtonReceived(query); +} + void MainWidget::notify_userIsBotChanged(UserData *bot) { history.notify_userIsBotChanged(bot); } @@ -931,10 +953,18 @@ void MainWidget::shareUrlLayer(const QString &url, const QString &text) { hiderLayer(new HistoryHider(this, url, text)); } +void MainWidget::inlineSwitchLayer(const QString &botAndQuery) { + hiderLayer(new HistoryHider(this, botAndQuery)); +} + bool MainWidget::selectingPeer(bool withConfirm) { return _hider ? (withConfirm ? _hider->withConfirm() : true) : false; } +bool MainWidget::selectingPeerForInlineSwitch() { + return selectingPeer() ? !_hider->botAndQuery().isEmpty() : false; +} + void MainWidget::offerPeer(PeerId peer) { Ui::hideLayer(); if (_hider->offerPeer(peer) && Adaptive::OneColumn()) { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index b277eb909..0098355d5 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -303,14 +303,17 @@ public: void deleteLayer(int32 selectedCount = -1); // -1 - context item, else selected, -2 - cancel upload void shareContactLayer(UserData *contact); void shareUrlLayer(const QString &url, const QString &text); + void inlineSwitchLayer(const QString &botAndQuery); void hiderLayer(HistoryHider *h); void noHider(HistoryHider *destroyed); bool onForward(const PeerId &peer, ForwardWhatMessages what); bool onShareUrl(const PeerId &peer, const QString &url, const QString &text); + bool onInlineSwitchChosen(const PeerId &peer, const QString &botAndQuery); void onShareContact(const PeerId &peer, UserData *contact); void onSendPaths(const PeerId &peer); void onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data); bool selectingPeer(bool withConfirm = false); + bool selectingPeerForInlineSwitch(); void offerPeer(PeerId peer); void dialogsActivate(); @@ -454,6 +457,7 @@ public: void notify_inlineBotRequesting(bool requesting); void notify_replyMarkupUpdated(const HistoryItem *item); void notify_inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); + void notify_switchInlineBotButtonReceived(const QString &query); void notify_userIsBotChanged(UserData *bot); void notify_userIsContactChanged(UserData *user, bool fromThisApp); void notify_migrateUpdated(PeerData *peer); diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index fb71cc760..b55857636 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -1024,8 +1024,11 @@ enum class MTPDmessage_ClientFlag : int32 { // message was sent from inline bot, need to re-set media when sent f_from_inline_bot = (1 << 24), + // message has a switch inline keyboard button, need to return to inline + f_has_switch_inline_button = (1 << 23), + // update this when adding new client side flags - MIN_FIELD = (1 << 24), + MIN_FIELD = (1 << 23), }; DEFINE_MTP_CLIENT_FLAGS(MTPDmessage) @@ -1039,8 +1042,11 @@ enum class MTPDreplyKeyboardMarkup_ClientFlag : int32 { // markup keyboard is inline f_inline = (1 << 28), + // markup has a switch inline keyboard button + f_has_switch_inline_button = (1 << 27), + // update this when adding new client side flags - MIN_FIELD = (1 << 28), + MIN_FIELD = (1 << 27), }; DEFINE_MTP_CLIENT_FLAGS(MTPDreplyKeyboardMarkup) diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index fa5201200..740cd6316 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -156,16 +156,17 @@ inline bool operator<(const FullMsgId &a, const FullMsgId &b) { return a.channel < b.channel; } -static const MsgId StartClientMsgId = -0x7FFFFFFF; -static const MsgId EndClientMsgId = -0x40000000; -inline bool isClientMsgId(MsgId id) { +constexpr const MsgId StartClientMsgId = -0x7FFFFFFF; +constexpr const MsgId EndClientMsgId = -0x40000000; +inline constexpr bool isClientMsgId(MsgId id) { return id >= StartClientMsgId && id < EndClientMsgId; } -static const MsgId ShowAtTheEndMsgId = -0x40000000; -static const MsgId SwitchAtTopMsgId = -0x3FFFFFFF; -static const MsgId ShowAtProfileMsgId = -0x3FFFFFFE; -static const MsgId ServerMaxMsgId = 0x3FFFFFFF; -static const MsgId ShowAtUnreadMsgId = 0; +constexpr const MsgId ShowAtTheEndMsgId = -0x40000000; +constexpr const MsgId SwitchAtTopMsgId = -0x3FFFFFFF; +constexpr const MsgId ShowAtProfileMsgId = -0x3FFFFFFE; +constexpr const MsgId ShowAndStartBotMsgId = -0x3FFFFFD; +constexpr const MsgId ServerMaxMsgId = 0x3FFFFFFF; +constexpr const MsgId ShowAtUnreadMsgId = 0; struct NotifySettings { NotifySettings() : flags(MTPDpeerNotifySettings::Flag::f_show_previews), mute(0), sound("default") { @@ -373,16 +374,16 @@ private: }; struct BotInfo { - BotInfo() : inited(false), readsAllHistory(false), cantJoinGroups(false), version(0), text(st::msgMinWidth) { - } - bool inited; - bool readsAllHistory, cantJoinGroups; - int version; + bool inited = false; + bool readsAllHistory = false; + bool cantJoinGroups = false; + int version = 0; QString description, inlinePlaceholder; QList commands; - Text text; // description + Text text = Text{ int(st::msgMinWidth) }; // description QString startToken, startGroupToken; + PeerId inlineReturnPeerId = 0; }; enum UserBlockedStatus { diff --git a/Telegram/SourceFiles/title.cpp b/Telegram/SourceFiles/title.cpp index eafb33ca7..117aa49a2 100644 --- a/Telegram/SourceFiles/title.cpp +++ b/Telegram/SourceFiles/title.cpp @@ -108,7 +108,9 @@ void TitleWidget::paintEvent(QPaintEvent *e) { if (!_cancel.isHidden()) { p.setPen(st::titleTextButton.color->p); p.setFont(st::titleTextButton.font->f); - p.drawText(st::titleMenuOffset - st::titleTextButton.width / 2, st::titleTextButton.textTop + st::titleTextButton.font->ascent, lang(lng_forward_choose)); + bool inlineSwitchChoose = (App::main() && App::main()->selectingPeerForInlineSwitch()); + auto chooseText = lang(inlineSwitchChoose ? lng_inline_switch_choose : lng_forward_choose); + p.drawText(st::titleMenuOffset - st::titleTextButton.width / 2, st::titleTextButton.textTop + st::titleTextButton.font->ascent, chooseText); } p.drawPixmap(st::titleIconPos, App::sprite(), st::titleIconImg); if (Adaptive::OneColumn() && !_counter.isNull() && App::main()) { diff --git a/Telegram/SourceFiles/ui/flatbutton.cpp b/Telegram/SourceFiles/ui/flatbutton.cpp index 7c4053263..a2facf888 100644 --- a/Telegram/SourceFiles/ui/flatbutton.cpp +++ b/Telegram/SourceFiles/ui/flatbutton.cpp @@ -348,6 +348,23 @@ BoxButton::BoxButton(QWidget *parent, const QString &text, const style::BoxButto , a_textBgOverOpacity(0) , a_textFg(st.textFg->c) , _a_over(animation(this, &BoxButton::step_over)) { + resizeToText(); + + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); + + setCursor(style::cur_pointer); + + setAttribute(Qt::WA_OpaquePaintEvent); +} + +void BoxButton::setText(const QString &text) { + _text = text; + _fullText = text; + _textWidth = _st.font->width(_text); + resizeToText(); +} + +void BoxButton::resizeToText() { if (_st.width <= 0) { resize(_textWidth - _st.width, _st.height); } else { @@ -357,12 +374,6 @@ BoxButton::BoxButton(QWidget *parent, const QString &text, const style::BoxButto } resize(_st.width, _st.height); } - - connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); - - setCursor(style::cur_pointer); - - setAttribute(Qt::WA_OpaquePaintEvent); } void BoxButton::paintEvent(QPaintEvent *e) { diff --git a/Telegram/SourceFiles/ui/flatbutton.h b/Telegram/SourceFiles/ui/flatbutton.h index e37fc2f89..e0ac3dd1b 100644 --- a/Telegram/SourceFiles/ui/flatbutton.h +++ b/Telegram/SourceFiles/ui/flatbutton.h @@ -162,18 +162,18 @@ class BoxButton : public Button { Q_OBJECT public: - BoxButton(QWidget *parent, const QString &text, const style::BoxButton &st); - void paintEvent(QPaintEvent *e); + void setText(const QString &text); + void paintEvent(QPaintEvent *e) override; void step_over(float64 ms, bool timer); public slots: - void onStateChange(int oldState, ButtonStateChangeSource source); private: + void resizeToText(); QString _text, _fullText; int32 _textWidth; @@ -183,4 +183,5 @@ private: anim::fvalue a_textBgOverOpacity; anim::cvalue a_textFg; Animation _a_over; + };