diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index c7b01c0b9..733f36938 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "boxes/confirm_box.h" #include "window/themes/window_theme.h" #include "window/notifications_manager.h" +#include "chat_helpers/message_field.h" namespace { @@ -1128,7 +1129,7 @@ void ApiWrap::saveDraftsToCloud() { if (!textWithTags.tags.isEmpty()) { flags |= MTPmessages_SaveDraft::Flag::f_entities; } - auto entities = linksToMTP(entitiesFromTextTags(textWithTags.tags), true); + auto entities = linksToMTP(ConvertTextTagsToEntities(textWithTags.tags), true); cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(MTP_flags(flags), MTP_int(cloudDraft->msgId), history->peer->input, MTP_string(textWithTags.text), entities)).done([this, history](const MTPBool &result, mtpRequestId requestId) { if (auto cloudDraft = history->cloudDraft()) { diff --git a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp new file mode 100644 index 000000000..ecc813e34 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp @@ -0,0 +1,248 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +*/ +#include "chat_helpers/bot_keyboard.h" + +#include "styles/style_widgets.h" +#include "styles/style_history.h" + +BotKeyboard::BotKeyboard(QWidget *parent) : TWidget(parent) +, _st(&st::botKbButton) { + setGeometry(0, 0, _st->margin, st::botKbScroll.deltat); + _height = st::botKbScroll.deltat; + setMouseTracking(true); +} + +void BotKeyboard::paintEvent(QPaintEvent *e) { + Painter p(this); + + auto clip = e->rect(); + p.fillRect(clip, st::historyComposeAreaBg); + + if (_impl) { + int x = rtl() ? st::botKbScroll.width : _st->margin; + p.translate(x, st::botKbScroll.deltat); + _impl->paint(p, width(), clip.translated(-x, -st::botKbScroll.deltat), getms()); + } +} + +void BotKeyboard::Style::startPaint(Painter &p) const { + p.setPen(st::botKbColor); + p.setFont(st::botKbStyle.font); +} + +const style::TextStyle &BotKeyboard::Style::textStyle() const { + return st::botKbStyle; +} + +void BotKeyboard::Style::repaint(const HistoryItem *item) const { + _parent->update(); +} + +int BotKeyboard::Style::buttonRadius() const { + return st::buttonRadius; +} + +void BotKeyboard::Style::paintButtonBg(Painter &p, const QRect &rect, float64 howMuchOver) const { + App::roundRect(p, rect, st::botKbBg, BotKeyboardCorners); +} + +void BotKeyboard::Style::paintButtonIcon(Painter &p, const QRect &rect, int outerWidth, HistoryMessageReplyMarkup::Button::Type type) const { + // Buttons with icons should not appear here. +} + +void BotKeyboard::Style::paintButtonLoading(Painter &p, const QRect &rect) const { + // Buttons with loading progress should not appear here. +} + +int BotKeyboard::Style::minButtonWidth(HistoryMessageReplyMarkup::Button::Type type) const { + int result = 2 * buttonPadding(); + return result; +} + +void BotKeyboard::mousePressEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateSelected(); + + ClickHandler::pressed(); +} + +void BotKeyboard::mouseMoveEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateSelected(); +} + +void BotKeyboard::mouseReleaseEvent(QMouseEvent *e) { + _lastMousePos = e->globalPos(); + updateSelected(); + + if (ClickHandlerPtr activated = ClickHandler::unpressed()) { + App::activateClickHandler(activated, e->button()); + } +} + +void BotKeyboard::enterEventHook(QEvent *e) { + _lastMousePos = QCursor::pos(); + updateSelected(); +} + +void BotKeyboard::leaveEventHook(QEvent *e) { + clearSelection(); +} + +bool BotKeyboard::moderateKeyActivate(int key) { + if (auto item = App::histItemById(_wasForMsgId)) { + if (auto markup = item->Get()) { + if (key >= Qt::Key_1 && key <= Qt::Key_9) { + int index = (key - Qt::Key_1); + if (!markup->rows.isEmpty() && index >= 0 && index < markup->rows.front().size()) { + App::activateBotCommand(item, 0, index); + return true; + } + } else if (key == Qt::Key_Q) { + if (auto user = item->history()->peer->asUser()) { + if (user->botInfo && item->from() == user) { + App::sendBotCommand(user, user, qsl("/translate")); + return true; + } + } + } + } + } + return false; +} + +void BotKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { + if (!_impl) return; + _impl->clickHandlerActiveChanged(p, active); +} + +void BotKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { + if (!_impl) return; + _impl->clickHandlerPressedChanged(p, pressed); +} + +bool BotKeyboard::updateMarkup(HistoryItem *to, bool force) { + if (!to || !to->definesReplyKeyboard()) { + if (_wasForMsgId.msg) { + _maximizeSize = _singleUse = _forceReply = false; + _wasForMsgId = FullMsgId(); + _impl = nullptr; + return true; + } + return false; + } + + if (_wasForMsgId == FullMsgId(to->channelId(), to->id) && !force) { + return false; + } + + _wasForMsgId = FullMsgId(to->channelId(), to->id); + + auto markupFlags = to->replyKeyboardFlags(); + _forceReply = markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply; + _maximizeSize = !(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_resize); + _singleUse = _forceReply || (markupFlags & MTPDreplyKeyboardMarkup::Flag::f_single_use); + + _impl = nullptr; + if (auto markup = to->Get()) { + if (!markup->rows.isEmpty()) { + _impl.reset(new ReplyKeyboard(to, std::make_unique