Game sharing and inline results supported. Qt patch updated.

Qt patch now disables QT_SCALE_FACTOR and other HighDpi
environment variables reading because tdesktop doesn't support them.
This commit is contained in:
John Preston 2016-09-28 19:23:25 +03:00
parent 5529e24000
commit 344890c533
24 changed files with 546 additions and 83 deletions

View File

@ -47,6 +47,20 @@ index 14e4fd1..c31c62b 100644
{ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
{ 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
{ 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 },
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
index b0ef2a2..7d5f7bc 100644
--- a/src/gui/kernel/qhighdpiscaling.cpp
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -51,6 +51,9 @@ static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS";
static inline qreal initialGlobalScaleFactor()
{
+ // Disable environment variable dpi scaling changing.
+ // It is not supported by Telegram Desktop :(
+ return 1.;
qreal result = 1;
if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) {
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
index 5b2f4ec..346a26f 100644
--- a/src/gui/kernel/qplatformdialoghelper.h

View File

@ -580,6 +580,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_action_pinned_media_contact" = "a contact information";
"lng_action_pinned_media_location" = "a location mark";
"lng_action_pinned_media_sticker" = "a sticker";
"lng_action_pinned_media_emoji_sticker" = "a {emoji} sticker";
"lng_action_pinned_media_game" = "a game «{game}»";
"lng_action_game_score" = "{from} scored {count:#|#|#} in {game}";
"lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached";
@ -774,6 +776,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_bot_groups_not_found" = "No groups found";
"lng_bot_sure_invite" = "Add the bot to «{group}»?";
"lng_bot_already_in_group" = "The bot is already a member of the group.";
"lng_bot_choose_chat" = "Choose Chat";
"lng_bot_no_chats" = "You have no chats";
"lng_bot_chats_not_found" = "No chats found";
"lng_bot_sure_share_game" = "Share the game with {user}?";
"lng_bot_sure_share_game_group" = "Share the game with «{group}»?";
"lng_typing" = "typing";
"lng_user_typing" = "{user} is typing";

View File

@ -1856,8 +1856,9 @@ namespace {
gamesData.erase(i);
}
convert->id = game;
convert->accessHash = 0;
}
if (convert->shortName.isEmpty() && !shortName.isEmpty()) {
if (!convert->accessHash && accessHash) {
convert->accessHash = accessHash;
convert->shortName = textClean(shortName);
convert->title = textOneLine(textClean(title));
@ -1879,7 +1880,7 @@ namespace {
} else {
result = i.value();
if (result != convert) {
if (result->shortName.isEmpty() && !shortName.isEmpty()) {
if (!result->accessHash && accessHash) {
result->accessHash = accessHash;
result->shortName = textClean(shortName);
result->title = textOneLine(textClean(title));

View File

@ -650,9 +650,17 @@ namespace Sandbox {
cSetScreenScale(dbisTwo);
}
if (application()->devicePixelRatio() > 1) {
auto devicePixelRatio = application()->devicePixelRatio();
if (devicePixelRatio > 1.) {
if ((cPlatform() != dbipMac && cPlatform() != dbipMacOld) || (devicePixelRatio != 2.)) {
LOG(("Found non-trivial Device Pixel Ratio: %1").arg(devicePixelRatio));
LOG(("Environmental variables: QT_DEVICE_PIXEL_RATIO='%1'").arg(QString::fromLatin1(qgetenv("QT_DEVICE_PIXEL_RATIO"))));
LOG(("Environmental variables: QT_SCALE_FACTOR='%1'").arg(QString::fromLatin1(qgetenv("QT_SCALE_FACTOR"))));
LOG(("Environmental variables: QT_AUTO_SCREEN_SCALE_FACTOR='%1'").arg(QString::fromLatin1(qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR"))));
LOG(("Environmental variables: QT_SCREEN_SCALE_FACTORS='%1'").arg(QString::fromLatin1(qgetenv("QT_SCREEN_SCALE_FACTORS"))));
}
cSetRetina(true);
cSetRetinaFactor(application()->devicePixelRatio());
cSetRetinaFactor(devicePixelRatio);
cSetIntRetinaFactor(int32(cRetinaFactor()));
cSetConfigScale(dbisOne);
cSetRealScale(dbisOne);

View File

@ -86,6 +86,17 @@ ContactsInner::ContactsInner(ChatData *chat, MembersFilter membersFilter) : TWid
init();
}
template <typename FilterCallback>
void ContactsInner::addDialogsToList(FilterCallback callback) {
auto v = App::main()->dialogsList();
for_const (auto row, *v) {
auto peer = row->history()->peer;
if (callback(peer)) {
_contacts->addToEnd(row->history());
}
}
}
ContactsInner::ContactsInner(UserData *bot) : TWidget()
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _bot(bot)
@ -93,14 +104,25 @@ ContactsInner::ContactsInner(UserData *bot) : TWidget()
, _customList(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add))
, _contacts(_customList.get())
, _addContactLnk(this, lang(lng_add_contact_button)) {
auto v = App::main()->dialogsList();
for_const (auto row, *v) {
auto peer = row->history()->peer;
if (peer->isChat() && peer->asChat()->canEdit()) {
_contacts->addToEnd(row->history());
} else if (peer->isMegagroup() && (peer->asChannel()->amCreator() || peer->asChannel()->amEditor())) {
_contacts->addToEnd(row->history());
}
if (sharingBotGame()) {
addDialogsToList([](PeerData *peer) {
if (peer->canWrite()) {
if (auto channel = peer->asChannel()) {
return !channel->isBroadcast();
}
return true;
}
return false;
});
} else {
addDialogsToList([](PeerData *peer) {
if (peer->isChat() && peer->asChat()->canEdit()) {
return true;
} else if (peer->isMegagroup() && (peer->asChannel()->amCreator() || peer->asChannel()->amEditor())) {
return true;
}
return false;
});
}
init();
}
@ -166,8 +188,22 @@ void ContactsInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &old
}
void ContactsInner::onAddBot() {
if (_bot->botInfo && !_bot->botInfo->startGroupToken.isEmpty()) {
MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToPeer->input, MTP_long(rand_value<uint64>()), MTP_string(_bot->botInfo->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _bot));
if (auto &info = _bot->botInfo) {
if (!info->shareGameShortName.isEmpty()) {
MTPmessages_SendMedia::Flags sendFlags = 0;
auto history = App::historyLoaded(_addToPeer);
auto afterRequestId = history ? history->sendRequestId : 0;
auto randomId = rand_value<uint64>();
auto requestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), _addToPeer->input, MTP_int(0), MTP_inputMediaGame(MTP_inputGameShortName(_bot->inputUser, MTP_string(info->shareGameShortName))), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, afterRequestId);
if (history) {
history->sendRequestId = requestId;
}
} else if (!info->startGroupToken.isEmpty()) {
MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToPeer->input, MTP_long(rand_value<uint64>()), MTP_string(info->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _bot));
} else {
App::main()->addParticipants(_addToPeer, QVector<UserData*>(1, _bot));
}
} else {
App::main()->addParticipants(_addToPeer, QVector<UserData*>(1, _bot));
}
@ -511,7 +547,7 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
QString text;
int32 skip = 0;
if (bot()) {
text = lang(cDialogsReceived() ? lng_bot_no_groups : lng_contacts_loading);
text = lang((cDialogsReceived() && !_searching) ? (sharingBotGame() ? lng_bot_no_chats : lng_bot_no_groups) : lng_contacts_loading);
} else if (_chat && _membersFilter == MembersFilterAdmins) {
text = lang(lng_contacts_loading);
p.fillRect(0, 0, width(), _newItemHeight - st::contactsPadding.bottom() - st::lineWidth, st::contactsAboutBg);
@ -538,7 +574,7 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
p.setPen(st::noContactsColor->p);
QString text;
if (bot()) {
text = lang(cDialogsReceived() ? lng_bot_groups_not_found : lng_contacts_loading);
text = lang((cDialogsReceived() && !_searching) ? (sharingBotGame() ? lng_bot_chats_not_found : lng_bot_groups_not_found) : lng_contacts_loading);
} else if (_chat && _membersFilter == MembersFilterAdmins) {
text = lang(_chat->participants.isEmpty() ? lng_contacts_loading : lng_contacts_not_found);
} else {
@ -702,11 +738,22 @@ void ContactsInner::chooseParticipant() {
connect(_addAdminBox, SIGNAL(confirmed()), this, SLOT(onAddAdmin()));
connect(_addAdminBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoAddAdminBox(QObject*)));
Ui::showLayer(_addAdminBox, KeepOtherLayers);
} else if (sharingBotGame()) {
_addToPeer = peer;
auto confirmText = [peer] {
if (peer->isUser()) {
return lng_bot_sure_share_game(lt_user, App::peerName(peer));
}
return lng_bot_sure_share_game_group(lt_group, peer->name);
};
auto box = std_::make_unique<ConfirmBox>(confirmText());
connect(box.get(), SIGNAL(confirmed()), this, SLOT(onAddBot()));
Ui::showLayer(box.release(), KeepOtherLayers);
} else if (bot() && (peer->isChat() || peer->isMegagroup())) {
_addToPeer = peer;
ConfirmBox *box = new ConfirmBox(lng_bot_sure_invite(lt_group, peer->name));
connect(box, SIGNAL(confirmed()), this, SLOT(onAddBot()));
Ui::showLayer(box, KeepOtherLayers);
auto box = std_::make_unique<ConfirmBox>(lng_bot_sure_invite(lt_group, peer->name));
connect(box.get(), SIGNAL(confirmed()), this, SLOT(onAddBot()));
Ui::showLayer(box.release(), KeepOtherLayers);
} else {
Ui::hideSettingsAndLayer(true);
App::main()->choosePeer(peer->id, ShowAtUnreadMsgId);
@ -899,7 +946,7 @@ void ContactsInner::updateFilter(QString filter) {
_mouseSel = false;
refresh();
if (!bot() && (!_chat || _membersFilter != MembersFilterAdmins)) {
if ((!bot() || sharingBotGame()) && (!_chat || _membersFilter != MembersFilterAdmins)) {
_searching = true;
emit searchByUsername();
}
@ -966,6 +1013,15 @@ void ContactsInner::peopleReceived(const QString &query, const QVector<MTPPeer>
} else {
continue; // skip
}
} else if (sharingBotGame()) {
if (!p->canWrite()) {
continue;
}
if (auto channel = p->asChannel()) {
if (channel->isBroadcast()) {
continue;
}
}
}
ContactData *d = new ContactData();
@ -1032,6 +1088,10 @@ UserData *ContactsInner::bot() const {
return _bot;
}
bool ContactsInner::sharingBotGame() const {
return (_bot && _bot->botInfo) ? !_bot->botInfo->shareGameShortName.isEmpty() : false;
}
CreatingGroupType ContactsInner::creating() const {
return _creating;
}
@ -1040,8 +1100,11 @@ ContactsInner::~ContactsInner() {
for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) {
delete *i;
}
if (_bot || (_chat && _membersFilter == MembersFilterAdmins)) {
if (_bot && _bot->botInfo) _bot->botInfo->startGroupToken = QString();
if (_bot) {
if (auto &info = _bot->botInfo) {
info->startGroupToken = QString();
info->shareGameShortName = QString();
}
}
}
@ -1499,6 +1562,8 @@ void ContactsBox::paintEvent(QPaintEvent *e) {
QString title(lang(addingAdmin ? lng_channel_add_admin : lng_profile_add_participant));
QString additional((addingAdmin || (_inner.channel() && !_inner.channel()->isMegagroup())) ? QString() : QString("%1 / %2").arg(_inner.selectedCount()).arg(Global::MegagroupSizeMax()));
paintTitle(p, title, additional);
} else if (_inner.sharingBotGame()) {
paintTitle(p, lang(lng_bot_choose_chat));
} else if (_inner.bot()) {
paintTitle(p, lang(lng_bot_choose_group));
} else {

View File

@ -78,6 +78,8 @@ public:
UserData *bot() const;
CreatingGroupType creating() const;
bool sharingBotGame() const;
int32 selectedCount() const;
bool hasAlreadyMembersInChannel() const {
return !_already.isEmpty();
@ -121,6 +123,9 @@ private:
void addAdminDone(const MTPUpdates &result, mtpRequestId req);
bool addAdminFail(const RPCError &error, mtpRequestId req);
template <typename FilterCallback>
void addDialogsToList(FilterCallback callback);
int32 _rowHeight;
int _newItemHeight = 0;
bool _newItemSel = false;

View File

@ -87,7 +87,7 @@ void ReportBox::onChange() {
_reasonOtherText.destroy();
updateMaxHeight();
}
if (App::wnd()) App::wnd()->setInnerFocus();
_reasonOtherText->setFocus();
}
void ReportBox::doSetInnerFocus() {

View File

@ -32,11 +32,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "boxes/confirmbox.h"
#include "apiwrap.h"
#include "ui/toast/toast.h"
#include "history/history_media_types.h"
ShareBox::ShareBox(CopyCallback &&copyCallback, SubmitCallback &&submitCallback) : ItemListBox(st::boxScroll)
ShareBox::ShareBox(CopyCallback &&copyCallback, SubmitCallback &&submitCallback, FilterCallback &&filterCallback) : ItemListBox(st::boxScroll)
, _copyCallback(std_::move(copyCallback))
, _submitCallback(std_::move(submitCallback))
, _inner(this)
, _inner(this, std_::move(filterCallback))
, _filter(this, st::boxSearchField, lang(lng_participant_filter))
, _filterCancel(this, st::boxSearchCancel)
, _copy(this, lang(lng_share_copy_link), st::defaultBoxButton)
@ -241,7 +242,8 @@ void ShareBox::onScroll() {
namespace internal {
ShareInner::ShareInner(QWidget *parent) : ScrolledWidget(parent)
ShareInner::ShareInner(QWidget *parent, ShareBox::FilterCallback &&filterCallback) : ScrolledWidget(parent)
, _filterCallback(std_::move(filterCallback))
, _chatsIndexed(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add)) {
_rowsTop = st::shareRowsTop;
_rowHeight = st::shareRowHeight;
@ -250,7 +252,7 @@ ShareInner::ShareInner(QWidget *parent) : ScrolledWidget(parent)
auto dialogs = App::main()->dialogsList();
for_const (auto row, dialogs->all()) {
auto history = row->history();
if (history->peer->canWrite()) {
if (_filterCallback(history->peer)) {
_chatsIndexed->addToEnd(history);
}
}
@ -863,7 +865,7 @@ void ShareInner::peopleReceived(const QString &query, const QVector<MTPPeer> &pe
}
if (j == already) {
auto *peer = App::peer(peerId);
if (!peer || !peer->canWrite()) continue;
if (!peer || !_filterCallback(peer)) continue;
auto chat = new Chat(peer);
updateChatName(chat, peer);
@ -958,24 +960,15 @@ void shareGameScoreFromItem(HistoryItem *item) {
if (auto main = App::main()) {
if (auto item = App::histItemById(data->msgId)) {
if (auto bot = item->getMessageBot()) {
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
for (int i = 0, rowsCount = markup->rows.size(); i != rowsCount; ++i) {
auto &row = markup->rows[i];
for (int j = 0, buttonsCount = row.size(); j != buttonsCount; ++j) {
auto &button = row[j];
if (button.type == HistoryMessageReplyMarkup::Button::Type::Game) {
auto strData = QString::fromUtf8(button.data);
auto parts = strData.split(',');
t_assert(parts.size() > 1);
if (auto media = item->getMedia()) {
if (media->type() == MediaTypeGame) {
auto shortName = static_cast<HistoryGame*>(media)->game()->shortName;
QApplication::clipboard()->setText(qsl("https://telegram.me/") + bot->username + qsl("?start=") + parts[1]);
QApplication::clipboard()->setText(qsl("https://telegram.me/") + bot->username + qsl("?game=") + shortName);
Ui::Toast::Config toast;
toast.text = lang(lng_share_game_link_copied);
Ui::Toast::Show(App::wnd(), toast);
return;
}
}
Ui::Toast::Config toast;
toast.text = lang(lng_share_game_link_copied);
Ui::Toast::Show(App::wnd(), toast);
}
}
}
@ -1015,7 +1008,16 @@ void shareGameScoreFromItem(HistoryItem *item) {
}
}
};
Ui::showLayer(new ShareBox(std_::move(copyCallback), std_::move(submitCallback)));
auto filterCallback = [](PeerData *peer) {
if (peer->canWrite()) {
if (auto channel = peer->asChannel()) {
return !channel->isBroadcast();
}
return true;
}
return false;
};
Ui::showLayer(new ShareBox(std_::move(copyCallback), std_::move(submitCallback), std_::move(filterCallback)));
}
} // namespace

View File

@ -47,7 +47,8 @@ class ShareBox : public ItemListBox, public RPCSender {
public:
using CopyCallback = base::lambda_unique<void()>;
using SubmitCallback = base::lambda_unique<void(const QVector<PeerData*> &)>;
ShareBox(CopyCallback &&copyCallback, SubmitCallback &&submitCallback);
using FilterCallback = base::lambda_unique<bool(PeerData*)>;
ShareBox(CopyCallback &&copyCallback, SubmitCallback &&submitCallback, FilterCallback &&filterCallback);
private slots:
void onFilterUpdate();
@ -112,7 +113,7 @@ class ShareInner : public ScrolledWidget, public RPCSender, private base::Subscr
Q_OBJECT
public:
ShareInner(QWidget *parent);
ShareInner(QWidget *parent, ShareBox::FilterCallback &&filterCallback);
QVector<PeerData*> selected() const;
bool hasSelected() const;
@ -197,6 +198,7 @@ private:
int _active = -1;
int _upon = -1;
ShareBox::FilterCallback _filterCallback;
std_::unique_ptr<Dialogs::IndexedList> _chatsIndexed;
QString _filter;
using FilteredDialogs = QVector<Dialogs::Row*>;

View File

@ -881,6 +881,10 @@ HistoryItem *History::createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32
return HistoryMessage::create(this, id, flags, replyTo, viaBotId, date, from, photo, caption, markup);
}
HistoryItem *History::createItemGame(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, GameData *game, const MTPReplyMarkup &markup) {
return HistoryMessage::create(this, id, flags, replyTo, viaBotId, date, from, game, markup);
}
HistoryItem *History::addNewService(MsgId msgId, QDateTime date, const QString &text, MTPDmessage::Flags flags, bool newMsg) {
return addNewItem(HistoryService::create(this, msgId, date, text, flags), newMsg);
}
@ -928,6 +932,10 @@ HistoryItem *History::addNewPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaB
return addNewItem(createItemPhoto(id, flags, viaBotId, replyTo, date, from, photo, caption, markup), true);
}
HistoryItem *History::addNewGame(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, GameData *game, const MTPReplyMarkup &markup) {
return addNewItem(createItemGame(id, flags, viaBotId, replyTo, date, from, game, markup), true);
}
bool History::addToOverview(MediaOverviewType type, MsgId msgId, AddToOverviewMethod method) {
bool adding = false;
switch (method) {

View File

@ -205,6 +205,7 @@ public:
HistoryItem *addNewForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *item);
HistoryItem *addNewDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption, const MTPReplyMarkup &markup);
HistoryItem *addNewPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption, const MTPReplyMarkup &markup);
HistoryItem *addNewGame(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, GameData *game, const MTPReplyMarkup &markup);
void addOlderSlice(const QVector<MTPMessage> &slice);
void addNewerSlice(const QVector<MTPMessage> &slice);
@ -463,6 +464,7 @@ protected:
HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg);
HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption, const MTPReplyMarkup &markup);
HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption, const MTPReplyMarkup &markup);
HistoryItem *createItemGame(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, GameData *game, const MTPReplyMarkup &markup);
HistoryItem *addNewItem(HistoryItem *adding, bool newMsg);
HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex);

View File

@ -69,7 +69,7 @@ inline void initTextOptions() {
bool needReSetInlineResultDocument(const MTPMessageMedia &media, DocumentData *existing) {
if (media.type() == mtpc_messageMediaDocument) {
if (DocumentData *document = App::feedDocument(media.c_messageMediaDocument().vdocument)) {
if (auto document = App::feedDocument(media.c_messageMediaDocument().vdocument)) {
if (document == existing) {
return false;
} else {
@ -1964,8 +1964,6 @@ private:
} // namespace
HistorySticker::HistorySticker(HistoryItem *parent, DocumentData *document) : HistoryMedia(parent)
, _pixw(1)
, _pixh(1)
, _data(document)
, _emoji(_data->sticker()->alt) {
_data->thumb->load();
@ -3103,11 +3101,12 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, uint
p.translate(attachLeft, attachTop);
_attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms);
auto pixwidth = _attach->currentWidth();
auto pixheight = _attach->height();
auto gameX = st::msgDateImgDelta;
auto gameY = st::msgDateImgDelta;
auto gameW = _gameTagWidth + 2 * st::msgDateImgPadding.x();
auto gameH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y();
auto gameX = pixwidth - st::msgDateImgDelta - gameW;
auto gameY = pixheight - st::msgDateImgDelta - gameH;
App::roundRect(p, rtlrect(gameX, gameY, gameW, gameH, pixwidth), selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners);
@ -3214,12 +3213,25 @@ void HistoryGame::detachFromParent() {
if (_attach) _attach->detachFromParent();
}
QString HistoryGame::notificationText() const {
return _data->title;
void HistoryGame::updateSentMedia(const MTPMessageMedia &media) {
if (media.type() == mtpc_messageMediaGame) {
auto &game = media.c_messageMediaGame().vgame;
if (game.type() == mtpc_game) {
App::feedGame(game.c_game(), _data);
}
}
}
QString HistoryGame::inDialogsText() const {
return textcmdLink(1, _data->title);
bool HistoryGame::needReSetInlineResultMedia(const MTPMessageMedia &media) {
updateSentMedia(media);
return false;
}
QString HistoryGame::notificationText() const {
QString result; // add a game controller emoji before game title
result.reserve(_data->title.size() + 3);
result.append(QChar(0xD83C)).append(QChar(0xDFAE)).append(QChar(' ')).append(_data->title);
return result;
}
TextWithEntities HistoryGame::selectedText(TextSelection selection) const {

View File

@ -552,6 +552,9 @@ public:
bool customInfoLayout() const override {
return true;
}
QString emoji() const {
return _emoji;
}
private:
int additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply) const;
@ -560,7 +563,8 @@ private:
}
QString toString() const;
int16 _pixw, _pixh;
int16 _pixw = 1;
int16 _pixh = 1;
ClickHandlerPtr _packLink;
DocumentData *_data;
QString _emoji;
@ -762,7 +766,6 @@ public:
}
QString notificationText() const override;
QString inDialogsText() const override;
TextWithEntities selectedText(TextSelection selection) const override;
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
@ -793,6 +796,9 @@ public:
return _data;
}
void updateSentMedia(const MTPMessageMedia &media) override;
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
bool needsBubble() const override {
return true;
}

View File

@ -49,7 +49,7 @@ MediaOverviewType messageMediaToOverviewType(HistoryMedia *media) {
case MediaTypePhoto: return OverviewPhotos;
case MediaTypeVideo: return OverviewVideos;
case MediaTypeFile: return OverviewFiles;
case MediaTypeMusicFile: return media->getDocument()->isMusic() ? OverviewMusicFiles : OverviewFiles;
case MediaTypeMusicFile: return media->getDocument()->isMusic() ? OverviewMusicFiles : OverviewCount;
case MediaTypeVoiceFile: return OverviewVoiceFiles;
case MediaTypeGif: return media->getDocument()->isGifv() ? OverviewCount : OverviewFiles;
default: break;
@ -465,6 +465,14 @@ HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags
setText(TextWithEntities());
}
HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, GameData *game, const MTPReplyMarkup &markup)
: HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) {
createComponentsHelper(flags, replyTo, viaBotId, markup);
_media.reset(new HistoryGame(this, game));
setText(TextWithEntities());
}
void HistoryMessage::createComponentsHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, const MTPReplyMarkup &markup) {
CreateConfig config;
@ -1899,7 +1907,7 @@ bool HistoryService::preparePinnedText(const QString &from, QString *outText, Li
ClickHandlerPtr second;
auto pinned = Get<HistoryServicePinned>();
if (pinned && pinned->msg) {
HistoryMedia *media = pinned->msg->getMedia();
auto media = pinned->msg->getMedia();
QString mediaText;
switch (media ? media->type() : MediaTypeCount) {
case MediaTypePhoto: mediaText = lang(lng_action_pinned_media_photo); break;
@ -1907,10 +1915,21 @@ bool HistoryService::preparePinnedText(const QString &from, QString *outText, Li
case MediaTypeContact: mediaText = lang(lng_action_pinned_media_contact); break;
case MediaTypeFile: mediaText = lang(lng_action_pinned_media_file); break;
case MediaTypeGif: mediaText = lang(lng_action_pinned_media_gif); break;
case MediaTypeSticker: mediaText = lang(lng_action_pinned_media_sticker); break;
case MediaTypeSticker: {
auto emoji = static_cast<HistorySticker*>(media)->emoji();
if (emoji.isEmpty()) {
mediaText = lang(lng_action_pinned_media_sticker);
} else {
mediaText = lng_action_pinned_media_emoji_sticker(lt_emoji, emoji);
}
} break;
case MediaTypeLocation: mediaText = lang(lng_action_pinned_media_location); break;
case MediaTypeMusicFile: mediaText = lang(lng_action_pinned_media_audio); break;
case MediaTypeVoiceFile: mediaText = lang(lng_action_pinned_media_voice); break;
case MediaTypeGame: {
auto title = static_cast<HistoryGame*>(media)->game()->title;
mediaText = lng_action_pinned_media_game(lt_game, title);
} break;
}
if (mediaText.isEmpty()) {
QString original = pinned->msg->originalText().text;

View File

@ -39,6 +39,9 @@ public:
static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption, const MTPReplyMarkup &markup) {
return _create(history, msgId, flags, replyTo, viaBotId, date, from, photo, caption, markup);
}
static HistoryMessage *create(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, GameData *game, const MTPReplyMarkup &markup) {
return _create(history, msgId, flags, replyTo, viaBotId, date, from, game, markup);
}
void initTime();
void initMedia(const MTPMessageMedia *media);
@ -164,6 +167,7 @@ private:
HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const TextWithEntities &textWithEntities); // local message
HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption, const MTPReplyMarkup &markup); // local document
HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption, const MTPReplyMarkup &markup); // local photo
HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, GameData *game, const MTPReplyMarkup &markup); // local game
friend class HistoryItemInstantiated<HistoryMessage>;
void setEmptyText();

View File

@ -134,7 +134,7 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
if (loaded && !gif() && _gif != Media::Clip::BadReader) {
Gif *that = const_cast<Gif*>(this);
auto that = const_cast<Gif*>(this);
that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
@ -276,7 +276,6 @@ QSize Gif::countFrameSize() const {
Gif::~Gif() {
if (gif()) deleteAndMark(_gif);
deleteAndMark(_animation);
}
void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
@ -306,7 +305,7 @@ void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
void Gif::ensureAnimation() const {
if (!_animation) {
_animation = new AnimationData(animation(const_cast<Gif*>(this), &Gif::step_radial));
_animation = std_::make_unique<AnimationData>(animation(const_cast<Gif*>(this), &Gif::step_radial));
}
}
@ -324,8 +323,7 @@ void Gif::step_radial(uint64 ms, bool timer) {
DocumentData *document = getShownDocument();
_animation->radial.update(document->progress(), !document->loading() || document->loaded(), ms);
if (!_animation->radial.animating() && document->loaded()) {
delete _animation;
_animation = nullptr;
_animation.reset();
}
}
}
@ -1140,6 +1138,239 @@ void Article::prepareThumb(int width, int height) const {
}
}
Game::Game(Result *result) : ItemBase(result)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
countFrameSize();
}
void Game::countFrameSize() {
if (auto document = getResultDocument()) {
if (document->isAnimation()) {
auto documentSize = document->dimensions;
if (documentSize.isEmpty()) {
documentSize = QSize(st::inlineThumbSize, st::inlineThumbSize);
}
auto resizeByHeight1 = (documentSize.width() > documentSize.height()) && (documentSize.height() >= st::inlineThumbSize);
auto resizeByHeight2 = (documentSize.height() >= documentSize.width()) && (documentSize.width() < st::inlineThumbSize);
if (resizeByHeight1 || resizeByHeight2) {
if (documentSize.height() > st::inlineThumbSize) {
_frameSize = QSize((documentSize.width() * st::inlineThumbSize) / documentSize.height(), st::inlineThumbSize);
}
} else {
if (documentSize.width() > st::inlineThumbSize) {
_frameSize = QSize(st::inlineThumbSize, (documentSize.height() * st::inlineThumbSize) / documentSize.width());
}
}
if (!_frameSize.width()) {
_frameSize.setWidth(1);
}
if (!_frameSize.height()) {
_frameSize.setHeight(1);
}
}
}
}
void Game::initDimensions() {
_maxw = st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft;
int32 textWidth = _maxw - (st::inlineThumbSize + st::inlineThumbSkip);
TextParseOptions titleOpts = { 0, _maxw, 2 * st::semiboldFont->height, Qt::LayoutDirectionAuto };
_title.setText(st::semiboldFont, textOneLine(_result->getLayoutTitle()), titleOpts);
int32 titleHeight = qMin(_title.countHeight(_maxw), 2 * st::semiboldFont->height);
int32 descriptionLines = 2;
QString description = _result->getLayoutDescription();
TextParseOptions descriptionOpts = { TextParseMultiline, _maxw, descriptionLines * st::normalFont->height, Qt::LayoutDirectionAuto };
_description.setText(st::normalFont, description, descriptionOpts);
int32 descriptionHeight = qMin(_description.countHeight(_maxw), descriptionLines * st::normalFont->height);
_minh = titleHeight + descriptionHeight;
accumulate_max(_minh, st::inlineThumbSize);
_minh += st::inlineRowMargin * 2 + st::inlineRowBorder;
}
void Game::setPosition(int32 position) {
ItemBase::setPosition(position);
if (_position < 0) {
if (gif()) delete _gif;
_gif = 0;
}
}
void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
left = st::inlineThumbSize + st::inlineThumbSkip;
auto rthumb = rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width);
// Gif thumb
auto thumbDisplayed = false, radial = false;
auto document = getResultDocument();
auto animatedThumb = document && document->isAnimation();
if (animatedThumb) {
document->automaticLoad(nullptr);
bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
if (loaded && !gif() && _gif != Media::Clip::BadReader) {
auto that = const_cast<Game*>(this);
that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
if (gif()) _gif->setAutoplay();
}
bool animating = (gif() && _gif->started());
if (displayLoading) {
if (!_radial) {
_radial = std_::make_unique<Ui::RadialAnimation>(animation(const_cast<Game*>(this), &Game::step_radial));
}
if (!_radial->animating()) {
_radial->start(document->progress());
}
}
radial = isRadialAnimation(context->ms);
if (animating) {
if (!_thumb.isNull()) _thumb = QPixmap();
auto animationThumb = _gif->current(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, context->paused ? 0 : context->ms);
p.drawPixmapLeft(rthumb.topLeft(), _width, animationThumb);
thumbDisplayed = true;
}
}
if (!thumbDisplayed) {
prepareThumb(st::inlineThumbSize, st::inlineThumbSize);
if (_thumb.isNull()) {
p.fillRect(rthumb, st::overviewPhotoBg);
} else {
p.drawPixmapLeft(rthumb.topLeft(), _width, _thumb);
}
}
if (radial) {
p.fillRect(rthumb, st::msgDateImgBg);
QRect inner((st::inlineThumbSize - st::msgFileSize) / 2, (st::inlineThumbSize - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
if (radial) {
p.setOpacity(1);
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
_radial->draw(p, rinner, st::msgFileRadialLine, st::msgInBg);
}
}
p.setPen(st::black);
_title.drawLeftElided(p, left, st::inlineRowMargin, _width - left, _width, 2);
int32 titleHeight = qMin(_title.countHeight(_width - left), st::semiboldFont->height * 2);
p.setPen(st::inlineDescriptionFg);
int32 descriptionLines = 2;
_description.drawLeftElided(p, left, st::inlineRowMargin + titleHeight, _width - left, _width, descriptionLines);
if (!context->lastRow) {
p.fillRect(rtlrect(left, _height - st::inlineRowBorder, _width - left, st::inlineRowBorder, _width), st::inlineRowBorderFg);
}
}
void Game::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const {
int left = st::inlineThumbSize + st::inlineThumbSkip;
if (x >= 0 && x < left - st::inlineThumbSkip && y >= st::inlineRowMargin && y < st::inlineRowMargin + st::inlineThumbSize) {
link = _send;
return;
}
if (x >= left && x < _width && y >= 0 && y < _height) {
link = _send;
return;
}
}
void Game::prepareThumb(int width, int height) const {
auto thumb = ([this]() {
if (auto photo = getResultPhoto()) {
return photo->medium;
} else if (auto document = getResultDocument()) {
return document->thumb;
}
return ImagePtr();
})();
if (thumb->isNull()) {
return;
}
if (thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
int w = qMax(convertScale(thumb->width()), 1), h = qMax(convertScale(thumb->height()), 1);
auto resizeByHeight1 = (w * height > h * width) && (h >= height);
auto resizeByHeight2 = (h * width >= w * height) && (w < width);
if (resizeByHeight1 || resizeByHeight2) {
if (h > height) {
w = w * height / h;
h = height;
}
} else {
if (w > width) {
h = h * width / w;
w = width;
}
}
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height);
}
} else {
thumb->load();
}
}
bool Game::isRadialAnimation(uint64 ms) const {
if (!_radial || !_radial->animating()) return false;
_radial->step(ms);
return _radial && _radial->animating();
}
void Game::step_radial(uint64 ms, bool timer) {
if (timer) {
update();
} else {
auto document = getResultDocument();
_radial->update(document->progress(), !document->loading() || document->loaded(), ms);
if (!_radial->animating() && document->loaded()) {
_radial.reset();
}
}
}
void Game::clipCallback(Media::Clip::Notification notification) {
using namespace Media::Clip;
switch (notification) {
case NotificationReinit: {
if (gif()) {
if (_gif->state() == State::Error) {
delete _gif;
_gif = BadReader;
getResultDocument()->forget();
} else if (_gif->ready() && !_gif->started()) {
_gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None);
} else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) {
delete _gif;
_gif = nullptr;
getResultDocument()->forget();
}
}
update();
} break;
case NotificationRepaint: {
if (gif() && !_gif->currentDisplayed()) {
update();
}
} break;
}
}
Game::~Game() {
if (gif()) deleteAndMark(_gif);
}
} // namespace internal
} // namespace Layout
} // namespace InlineBots

View File

@ -116,7 +116,7 @@ private:
FloatAnimation _a_over;
Ui::RadialAnimation radial;
};
mutable AnimationData *_animation = nullptr;
mutable std_::unique_ptr<AnimationData> _animation;
mutable FloatAnimation _a_deleteOver;
};
@ -339,6 +339,40 @@ private:
};
class Game : public ItemBase {
public:
Game(Result *result);
void setPosition(int32 position) override;
void initDimensions() override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
~Game();
private:
void countFrameSize();
bool gif() const {
return (!_gif || _gif == Media::Clip::BadReader) ? false : true;
}
void prepareThumb(int32 width, int32 height) const;
bool isRadialAnimation(uint64 ms) const;
void step_radial(uint64 ms, bool timer);
void clipCallback(Media::Clip::Notification notification);
Media::Clip::Reader *_gif = nullptr;
mutable QPixmap _thumb;
mutable std_::unique_ptr<Ui::RadialAnimation> _radial;
Text _title, _description;
QSize _frameSize;
};
} // namespace internal
} // namespace Layout
} // namespace InlineBots

View File

@ -113,6 +113,7 @@ std_::unique_ptr<ItemBase> ItemBase::createLayout(Result *result, bool forceThum
case Type::Article:
case Type::Geo:
case Type::Venue: return std_::make_unique<internal::Article>(result, forceThumb); break;
case Type::Game: return std_::make_unique<internal::Game>(result); break;
case Type::Contact: return std_::make_unique<internal::Contact>(result); break;
}
return std_::unique_ptr<ItemBase>();

View File

@ -47,6 +47,7 @@ std_::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
result->insert(qsl("contact"), Result::Type::Contact);
result->insert(qsl("venue"), Result::Type::Venue);
result->insert(qsl("geo"), Result::Type::Geo);
result->insert(qsl("game"), Result::Type::Game);
return result.release();
})() };
@ -122,6 +123,9 @@ std_::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
if (result->_type == Type::Photo) {
result->createPhoto();
result->sendData.reset(new internal::SendPhoto(result->_photo, qs(r.vcaption)));
} else if (result->_type == Type::Game) {
result->createGame();
result->sendData.reset(new internal::SendGame(result->_game));
} else {
result->createDocument();
result->sendData.reset(new internal::SendFile(result->_document, qs(r.vcaption)));
@ -313,7 +317,7 @@ void Result::createPhoto() {
ImagePtr medium = ImagePtr(mediumsize.width(), mediumsize.height());
ImagePtr full = ImagePtr(_content_url, _width, _height);
uint64 photoId = rand_value<uint64>();
auto photoId = rand_value<PhotoId>();
_photo = App::photoSet(photoId, 0, 0, unixtime(), _thumb, medium, full);
_photo->thumb = _thumb;
}
@ -321,8 +325,6 @@ void Result::createPhoto() {
void Result::createDocument() {
if (_document) return;
uint64 docId = rand_value<uint64>();
if (!_thumb_url.isEmpty()) {
_thumb = ImagePtr(_thumb_url, QSize(90, 90));
}
@ -352,16 +354,16 @@ void Result::createDocument() {
attributes.push_back(MTP_documentAttributeAudio(MTP_flags(flags), MTP_int(_duration), MTPstring(), MTPstring(), MTPbytes()));
}
MTPDocument document = MTP_document(MTP_long(docId), MTP_long(0), MTP_int(unixtime()), MTP_string(mime), MTP_int(0), MTP_photoSizeEmpty(MTP_string("")), MTP_int(MTP::maindc()), MTP_int(0), MTP_vector<MTPDocumentAttribute>(attributes));
_document = App::feedDocument(document);
auto documentId = rand_value<DocumentId>();
_document = App::documentSet(documentId, nullptr, 0, 0, unixtime(), attributes, mime, _thumb, MTP::maindc(), 0, StorageImageLocation());
_document->setContentUrl(_content_url);
if (!_thumb->isNull()) {
_document->thumb = _thumb;
}
}
Result::~Result() {
void Result::createGame() {
if (_game) return;
auto gameId = rand_value<GameId>();
_game = App::gameSet(gameId, nullptr, 0, QString(), _title, _description, _photo, _document);
}
} // namespace InlineBots

View File

@ -74,11 +74,10 @@ public:
QString getLayoutTitle() const;
QString getLayoutDescription() const;
~Result();
private:
void createPhoto();
void createDocument();
void createGame();
enum class Type {
Unknown,
@ -92,6 +91,7 @@ private:
Contact,
Geo,
Venue,
Game,
};
friend class internal::SendData;
@ -112,6 +112,7 @@ private:
DocumentData *_document = nullptr;
PhotoData *_photo = nullptr;
GameData *_game = nullptr;
std_::unique_ptr<MTPReplyMarkup> _mtpKeyboard;

View File

@ -90,5 +90,11 @@ UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const {
history->addNewDocument(msgId, flags, viaBotId, replyToId, date(mtpDate), fromId, _document, _caption, markup);
}
void SendGame::addToHistory(const Result *owner, History *history,
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const {
history->addNewGame(msgId, flags, viaBotId, replyToId, date(mtpDate), fromId, _game, markup);
}
} // namespace internal
} // namespace InlineBots

View File

@ -221,5 +221,25 @@ private:
};
// Message with game.
class SendGame : public SendData {
public:
SendGame(GameData *game)
: _game(game) {
}
bool isValid() const override {
return _game != nullptr;
}
void addToHistory(const Result *owner, History *history,
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const override;
private:
GameData *_game;
};
} // namespace internal
} // namespace InlineBots

View File

@ -3349,7 +3349,7 @@ void MainWidget::openLocalUrl(const QString &url) {
} else if (auto usernameMatch = regex_match(qsl("^resolve/?\\?(.+)(#|$)"), command, matchOptions)) {
auto params = url_parse_params(usernameMatch->captured(1), UrlParamNameTransform::ToLower);
auto domain = params.value(qsl("domain"));
if (auto domainMatch = regex_match(qsl("^[a-zA-Z0-9\\.\\_]+$"), domain, matchOptions)) {
if (regex_match(qsl("^[a-zA-Z0-9\\.\\_]+$"), domain, matchOptions)) {
auto start = qsl("start");
auto startToken = params.value(start);
if (startToken.isEmpty()) {
@ -3364,6 +3364,11 @@ void MainWidget::openLocalUrl(const QString &url) {
if (auto postId = postParam.toInt()) {
post = postId;
}
auto gameParam = params.value(qsl("game"));
if (!gameParam.isEmpty() && regex_match(qsl("^[a-zA-Z0-9\\.\\_]+$"), gameParam, matchOptions)) {
startToken = gameParam;
post = ShowAtGameShareMsgId;
}
openPeerByName(domain, post, startToken);
}
} else if (auto shareGameScoreMatch = regex_match(qsl("^share_game_score/?\\?(.+)(#|$)"), command, matchOptions)) {
@ -3377,7 +3382,14 @@ void MainWidget::openPeerByName(const QString &username, MsgId msgId, const QStr
PeerData *peer = App::peerByName(username);
if (peer) {
if (msgId == ShowAtProfileMsgId && !peer->isChannel()) {
if (msgId == ShowAtGameShareMsgId) {
if (peer->isUser() && peer->asUser()->botInfo && !startToken.isEmpty()) {
peer->asUser()->botInfo->shareGameShortName = startToken;
Ui::showLayer(new ContactsBox(peer->asUser()));
} else {
Ui::showPeerHistoryAsync(peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Forward);
}
} else if (msgId == ShowAtProfileMsgId && !peer->isChannel()) {
if (peer->isUser() && peer->asUser()->botInfo && !peer->asUser()->botInfo->cantJoinGroups && !startToken.isEmpty()) {
peer->asUser()->botInfo->startGroupToken = startToken;
Ui::showLayer(new ContactsBox(peer->asUser()));

View File

@ -163,6 +163,7 @@ constexpr const MsgId ShowAtTheEndMsgId = -0x40000000;
constexpr const MsgId SwitchAtTopMsgId = -0x3FFFFFFF;
constexpr const MsgId ShowAtProfileMsgId = -0x3FFFFFFE;
constexpr const MsgId ShowAndStartBotMsgId = -0x3FFFFFD;
constexpr const MsgId ShowAtGameShareMsgId = -0x3FFFFFC;
constexpr const MsgId ServerMaxMsgId = 0x3FFFFFFF;
constexpr const MsgId ShowAtUnreadMsgId = 0;
@ -385,7 +386,7 @@ struct BotInfo {
QList<BotCommand> commands;
Text text = Text{ int(st::msgMinWidth) }; // description
QString startToken, startGroupToken;
QString startToken, startGroupToken, shareGameShortName;
PeerId inlineReturnPeerId = 0;
};
@ -1141,7 +1142,7 @@ public:
return (type == AnimatedDocument) && !mime.compare(qstr("video/mp4"), Qt::CaseInsensitive);
}
bool isMusic() const {
return (type == SongDocument) ? !static_cast<SongData*>(_additional.get())->title.isEmpty() : false;
return (type == SongDocument) ? (static_cast<SongData*>(_additional.get())->duration != 0) : false;
}
bool isVideo() const {
return (type == VideoDocument);