Inline switch to pm and back support added for inline bots.

This commit is contained in:
John Preston 2016-04-08 18:16:52 +04:00
parent 8e89486fbc
commit fa0c700ca6
18 changed files with 430 additions and 193 deletions

View File

@ -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 :(";

View File

@ -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;

View File

@ -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<BoxButton>(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<InlineBots::Result> 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) {

View File

@ -173,6 +173,16 @@ using InlineResult = InlineBots::Result;
using InlineResults = QList<InlineBots::Result*>;
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<int32, uint64> Animations; // index - showing, -index - hiding
Animations _animations;
Animation _a_selected;
@ -449,6 +462,9 @@ private:
QTimer _updateInlineItems;
bool _inlineWithThumb;
UniquePointer<BoxButton> _switchPmButton;
QString _switchPmStartToken;
typedef QVector<InlineItem*> 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<QString, InlineCacheEntry*> InlineCache;
typedef QMap<QString, internal::InlineCacheEntry*> InlineCache;
InlineCache _inlineCache;
QTimer _inlineRequestTimer;

View File

@ -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);
}

View File

@ -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);

View File

@ -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<HistoryMessageReplyMarkup>()) {
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<MTPKeyboardBu
case mtpc_keyboardButtonSwitchInline: {
const auto &buttonData(button.c_keyboardButtonSwitchInline());
buttonRow.push_back({ Button::SwitchInline, qs(buttonData.vtext), qba(buttonData.vquery), 0 });
flags |= MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button;
} break;
}
}
@ -6699,11 +6704,13 @@ void HistoryMessage::KeyboardStyle::paintButtonBg(Painter &p, const QRect &rect,
}
void HistoryMessage::KeyboardStyle::paintButtonIcon(Painter &p, const QRect &rect, HistoryMessageReplyMarkup::Button::Type type) const {
using Button = HistoryMessageReplyMarkup::Button;
style::sprite sprite;
switch (type) {
case HistoryMessageReplyMarkup::Button::Url: sprite = st::msgBotKbUrlIcon; break;
case HistoryMessageReplyMarkup::Button::RequestPhone: sprite = st::msgBotKbRequestPhoneIcon; break;
case HistoryMessageReplyMarkup::Button::RequestLocation: sprite = st::msgBotKbRequestLocationIcon; break;
case Button::Url: sprite = st::msgBotKbUrlIcon; break;
// case Button::RequestPhone: sprite = st::msgBotKbRequestPhoneIcon; break;
// case Button::RequestLocation: sprite = st::msgBotKbRequestLocationIcon; break;
case Button::SwitchInline: sprite = st::msgBotKbSwitchPmIcon; break;
}
if (!sprite.isEmpty()) {
p.drawSprite(rect.x() + rect.width() - sprite.pxWidth() - st::msgBotKbIconPadding, rect.y() + st::msgBotKbIconPadding, sprite);
@ -6716,12 +6723,14 @@ void HistoryMessage::KeyboardStyle::paintButtonLoading(Painter &p, const QRect &
}
int HistoryMessage::KeyboardStyle::minButtonWidth(HistoryMessageReplyMarkup::Button::Type type) const {
using Button = HistoryMessageReplyMarkup::Button;
int result = 2 * buttonPadding(), iconWidth = 0;
switch (type) {
case HistoryMessageReplyMarkup::Button::Url: iconWidth = st::msgBotKbUrlIcon.pxWidth(); break;
case HistoryMessageReplyMarkup::Button::RequestPhone: iconWidth = st::msgBotKbRequestPhoneIcon.pxWidth(); break;
case HistoryMessageReplyMarkup::Button::RequestLocation: iconWidth = st::msgBotKbRequestLocationIcon.pxWidth(); break;
case HistoryMessageReplyMarkup::Button::Callback: iconWidth = st::msgInvSendingImg.pxWidth(); break;
case Button::Url: iconWidth = st::msgBotKbUrlIcon.pxWidth(); break;
//case Button::RequestPhone: iconWidth = st::msgBotKbRequestPhoneIcon.pxWidth(); break;
//case Button::RequestLocation: iconWidth = st::msgBotKbRequestLocationIcon.pxWidth(); break;
case Button::SwitchInline: iconWidth = st::msgBotKbSwitchPmIcon.pxWidth(); break;
case Button::Callback: iconWidth = st::msgInvSendingImg.pxWidth(); break;
}
if (iconWidth > 0) {
result = std::min(result, iconWidth + 2 * int(st::msgBotKbIconPadding));
@ -6855,6 +6864,9 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
}
if (auto markup = Get<HistoryMessageReplyMarkup>()) {
markup->create(*config.markup);
if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button) {
_flags |= MTPDmessage_ClientFlag::f_has_switch_inline_button;
}
}
initTime();
}

View File

@ -351,31 +351,53 @@ public:
typedef QList<HistoryBlock*> 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<HistoryItem*> NotifyQueue;
NotifyQueue notifies;
HistoryDraft *msgDraft;
HistoryEditDraft *editDraft;
HistoryDraft *msgDraft() {
return _msgDraft.data();
}
HistoryEditDraft *editDraft() {
return _editDraft.data();
}
void setMsgDraft(UniquePointer<HistoryDraft> &&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<HistoryEditDraft> &&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<UserData*, uint64> TypingUsers;
TypingUsers typing;
typedef QMap<UserData*, SendAction> SendActionUsers;
SendActionUsers sendActions;
QString typingStr;
Text typingText;
Text typingText = Text{ int(st::dlgRichMinWidth) };
uint32 typingDots;
QMap<SendActionType, uint64> 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<MsgId, NullType> MediaOverviewIds;
MediaOverviewIds overviewIds[OverviewCount];
@ -555,6 +579,9 @@ private:
// Depending on isBuildingFrontBlock() gets front or back block.
HistoryBlock *prepareBlockForAddingItem();
UniquePointer<HistoryDraft> _msgDraft;
UniquePointer<HistoryEditDraft> _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;
}

View File

@ -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<HistoryDraft>(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<HistoryEditDraft>(_field, _editMsgId, _previewCancelled, _saveEditMsgRequestId));
} else {
if (_replyToId || !_field.getLastText().isEmpty()) {
_history->setMsgDraft(new HistoryDraft(_field, _replyToId, _previewCancelled));
_history->setMsgDraft(MakeUnique<HistoryDraft>(_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<HistoryDraft>(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<HistoryDraft>(_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<HistoryEditDraft>(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) {

View File

@ -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);

View File

@ -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<HistoryDraft>(msgText, msgReplyTo, msgCursor, msgPreviewCancelled));
}
if (!editMsgId) {
h->setEditDraft(nullptr);
h->clearEditDraft();
} else {
h->setEditDraft(new HistoryEditDraft(editText, editMsgId, editCursor, editPreviewCancelled));
h->setEditDraft(MakeUnique<HistoryEditDraft>(editText, editMsgId, editCursor, editPreviewCancelled));
}
}

View File

@ -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<HistoryDraft>(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<HistoryDraft>(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()) {

View File

@ -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);

View File

@ -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)

View File

@ -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<BotCommand> commands;
Text text; // description
Text text = Text{ int(st::msgMinWidth) }; // description
QString startToken, startGroupToken;
PeerId inlineReturnPeerId = 0;
};
enum UserBlockedStatus {

View File

@ -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()) {

View File

@ -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) {

View File

@ -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;
};