mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Migrate games to AttachWebView.
This commit is contained in:
parent
78093173a9
commit
6effac7915
11 changed files with 223 additions and 223 deletions
|
@ -127,11 +127,7 @@ void SendBotCallbackData(
|
||||||
UrlClickHandler::Open(link);
|
UrlClickHandler::Open(link);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto scoreLink = AppendShareGameScoreUrl(
|
BotGameUrlClickHandler(bot, link).onClick({
|
||||||
session,
|
|
||||||
link,
|
|
||||||
item->fullId());
|
|
||||||
BotGameUrlClickHandler(bot, scoreLink).onClick({
|
|
||||||
Qt::LeftButton,
|
Qt::LeftButton,
|
||||||
QVariant::fromValue(ClickHandlerContext{
|
QVariant::fromValue(ClickHandlerContext{
|
||||||
.itemId = item->fullId(),
|
.itemId = item->fullId(),
|
||||||
|
|
|
@ -1409,55 +1409,6 @@ std::vector<not_null<Data::Thread*>> ShareBox::Inner::selected() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AppendShareGameScoreUrl(
|
|
||||||
not_null<Main::Session*> session,
|
|
||||||
const QString &url,
|
|
||||||
const FullMsgId &fullId) {
|
|
||||||
auto shareHashData = QByteArray(0x20, Qt::Uninitialized);
|
|
||||||
auto shareHashDataInts = reinterpret_cast<uint64*>(shareHashData.data());
|
|
||||||
const auto peer = fullId.peer
|
|
||||||
? session->data().peerLoaded(fullId.peer)
|
|
||||||
: static_cast<PeerData*>(nullptr);
|
|
||||||
const auto channelAccessHash = uint64((peer && peer->isChannel())
|
|
||||||
? peer->asChannel()->access
|
|
||||||
: 0);
|
|
||||||
shareHashDataInts[0] = session->userId().bare;
|
|
||||||
shareHashDataInts[1] = fullId.peer.value;
|
|
||||||
shareHashDataInts[2] = uint64(fullId.msg.bare);
|
|
||||||
shareHashDataInts[3] = channelAccessHash;
|
|
||||||
|
|
||||||
// Count SHA1() of data.
|
|
||||||
auto key128Size = 0x10;
|
|
||||||
auto shareHashEncrypted = QByteArray(key128Size + shareHashData.size(), Qt::Uninitialized);
|
|
||||||
hashSha1(shareHashData.constData(), shareHashData.size(), shareHashEncrypted.data());
|
|
||||||
|
|
||||||
//// Mix in channel access hash to the first 64 bits of SHA1 of data.
|
|
||||||
//*reinterpret_cast<uint64*>(shareHashEncrypted.data()) ^= channelAccessHash;
|
|
||||||
|
|
||||||
// Encrypt data.
|
|
||||||
if (!session->local().encrypt(shareHashData.constData(), shareHashEncrypted.data() + key128Size, shareHashData.size(), shareHashEncrypted.constData())) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto shareHash = shareHashEncrypted.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
|
||||||
auto shareUrl = u"tg://share_game_score?hash="_q + QString::fromLatin1(shareHash);
|
|
||||||
|
|
||||||
auto shareComponent = u"tgShareScoreUrl="_q + qthelp::url_encode(shareUrl);
|
|
||||||
|
|
||||||
auto hashPosition = url.indexOf('#');
|
|
||||||
if (hashPosition < 0) {
|
|
||||||
return url + '#' + shareComponent;
|
|
||||||
}
|
|
||||||
auto hash = url.mid(hashPosition + 1);
|
|
||||||
if (hash.indexOf('=') >= 0 || hash.indexOf('?') >= 0) {
|
|
||||||
return url + '&' + shareComponent;
|
|
||||||
}
|
|
||||||
if (!hash.isEmpty()) {
|
|
||||||
return url + '?' + shareComponent;
|
|
||||||
}
|
|
||||||
return url + shareComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatHelpers::ForwardedMessagePhraseArgs CreateForwardedMessagePhraseArgs(
|
ChatHelpers::ForwardedMessagePhraseArgs CreateForwardedMessagePhraseArgs(
|
||||||
const std::vector<not_null<Data::Thread*>> &result,
|
const std::vector<not_null<Data::Thread*>> &result,
|
||||||
const MessageIdsList &msgIds) {
|
const MessageIdsList &msgIds) {
|
||||||
|
@ -1612,9 +1563,8 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastShareMessage(
|
void FastShareMessage(
|
||||||
not_null<Window::SessionController*> controller,
|
std::shared_ptr<Main::SessionShow> show,
|
||||||
not_null<HistoryItem*> item) {
|
not_null<HistoryItem*> item) {
|
||||||
const auto show = controller->uiShow();
|
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
const auto owner = &history->owner();
|
const auto owner = &history->owner();
|
||||||
const auto session = &history->session();
|
const auto session = &history->session();
|
||||||
|
@ -1643,7 +1593,7 @@ void FastShareMessage(
|
||||||
}
|
}
|
||||||
if (item->hasDirectLink()) {
|
if (item->hasDirectLink()) {
|
||||||
using namespace HistoryView;
|
using namespace HistoryView;
|
||||||
CopyPostLink(controller, item->fullId(), Context::History);
|
CopyPostLink(show, item->fullId(), Context::History);
|
||||||
} else if (const auto bot = item->getMessageBot()) {
|
} else if (const auto bot = item->getMessageBot()) {
|
||||||
if (const auto media = item->media()) {
|
if (const auto media = item->media()) {
|
||||||
if (const auto game = media->game()) {
|
if (const auto game = media->game()) {
|
||||||
|
@ -1675,23 +1625,27 @@ void FastShareMessage(
|
||||||
auto copyLinkCallback = canCopyLink
|
auto copyLinkCallback = canCopyLink
|
||||||
? Fn<void()>(std::move(copyCallback))
|
? Fn<void()>(std::move(copyCallback))
|
||||||
: Fn<void()>();
|
: Fn<void()>();
|
||||||
controller->show(
|
show->show(Box<ShareBox>(ShareBox::Descriptor{
|
||||||
Box<ShareBox>(ShareBox::Descriptor{
|
.session = session,
|
||||||
.session = session,
|
.copyCallback = std::move(copyLinkCallback),
|
||||||
.copyCallback = std::move(copyLinkCallback),
|
.submitCallback = ShareBox::DefaultForwardCallback(
|
||||||
.submitCallback = ShareBox::DefaultForwardCallback(
|
show,
|
||||||
show,
|
history,
|
||||||
history,
|
msgIds),
|
||||||
msgIds),
|
.filterCallback = std::move(filterCallback),
|
||||||
.filterCallback = std::move(filterCallback),
|
.forwardOptions = {
|
||||||
.forwardOptions = {
|
.sendersCount = ItemsForwardSendersCount(items),
|
||||||
.sendersCount = ItemsForwardSendersCount(items),
|
.captionsCount = ItemsForwardCaptionsCount(items),
|
||||||
.captionsCount = ItemsForwardCaptionsCount(items),
|
.show = !hasOnlyForcedForwardedInfo,
|
||||||
.show = !hasOnlyForcedForwardedInfo,
|
},
|
||||||
},
|
.premiumRequiredError = SharePremiumRequiredError(),
|
||||||
.premiumRequiredError = SharePremiumRequiredError(),
|
}), Ui::LayerOption::CloseOther);
|
||||||
}),
|
}
|
||||||
Ui::LayerOption::CloseOther);
|
|
||||||
|
void FastShareMessage(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<HistoryItem*> item) {
|
||||||
|
FastShareMessage(controller->uiShow(), item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastShareLink(
|
void FastShareLink(
|
||||||
|
@ -1793,111 +1747,3 @@ auto SharePremiumRequiredError()
|
||||||
-> Fn<RecipientPremiumRequiredError(not_null<UserData*>)> {
|
-> Fn<RecipientPremiumRequiredError(not_null<UserData*>)> {
|
||||||
return WritePremiumRequiredError;
|
return WritePremiumRequiredError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareGameScoreByHash(
|
|
||||||
not_null<Window::SessionController*> controller,
|
|
||||||
const QString &hash) {
|
|
||||||
auto &session = controller->session();
|
|
||||||
auto key128Size = 0x10;
|
|
||||||
|
|
||||||
auto hashEncrypted = QByteArray::fromBase64(hash.toLatin1(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
|
||||||
if (hashEncrypted.size() <= key128Size || (hashEncrypted.size() != key128Size + 0x20)) {
|
|
||||||
controller->show(
|
|
||||||
Ui::MakeInformBox(tr::lng_confirm_phone_link_invalid()),
|
|
||||||
Ui::LayerOption::CloseOther);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt data.
|
|
||||||
auto hashData = QByteArray(hashEncrypted.size() - key128Size, Qt::Uninitialized);
|
|
||||||
if (!session.local().decrypt(hashEncrypted.constData() + key128Size, hashData.data(), hashEncrypted.size() - key128Size, hashEncrypted.constData())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count SHA1() of data.
|
|
||||||
char dataSha1[20] = { 0 };
|
|
||||||
hashSha1(hashData.constData(), hashData.size(), dataSha1);
|
|
||||||
|
|
||||||
//// Mix out channel access hash from the first 64 bits of SHA1 of data.
|
|
||||||
//auto channelAccessHash = *reinterpret_cast<uint64*>(hashEncrypted.data()) ^ *reinterpret_cast<uint64*>(dataSha1);
|
|
||||||
|
|
||||||
//// Check next 64 bits of SHA1() of data.
|
|
||||||
//auto skipSha1Part = sizeof(channelAccessHash);
|
|
||||||
//if (memcmp(dataSha1 + skipSha1Part, hashEncrypted.constData() + skipSha1Part, key128Size - skipSha1Part) != 0) {
|
|
||||||
// Ui::show(Box<Ui::InformBox>(tr::lng_share_wrong_user(tr::now)));
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Check 128 bits of SHA1() of data.
|
|
||||||
if (memcmp(dataSha1, hashEncrypted.constData(), key128Size) != 0) {
|
|
||||||
controller->show(
|
|
||||||
Ui::MakeInformBox(tr::lng_share_wrong_user()),
|
|
||||||
Ui::LayerOption::CloseOther);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hashDataInts = reinterpret_cast<uint64*>(hashData.data());
|
|
||||||
if (hashDataInts[0] != session.userId().bare) {
|
|
||||||
controller->show(
|
|
||||||
Ui::MakeInformBox(tr::lng_share_wrong_user()),
|
|
||||||
Ui::LayerOption::CloseOther);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto peerId = PeerId(hashDataInts[1]);
|
|
||||||
const auto channelAccessHash = hashDataInts[3];
|
|
||||||
if (!peerIsChannel(peerId) && channelAccessHash) {
|
|
||||||
// If there is no channel id, there should be no channel access_hash.
|
|
||||||
controller->show(
|
|
||||||
Ui::MakeInformBox(tr::lng_share_wrong_user()),
|
|
||||||
Ui::LayerOption::CloseOther);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto msgId = MsgId(int64(hashDataInts[2]));
|
|
||||||
if (const auto item = session.data().message(peerId, msgId)) {
|
|
||||||
FastShareMessage(controller, item);
|
|
||||||
} else {
|
|
||||||
const auto weak = base::make_weak(controller);
|
|
||||||
const auto resolveMessageAndShareScore = crl::guard(weak, [=](
|
|
||||||
PeerData *peer) {
|
|
||||||
auto done = crl::guard(weak, [=] {
|
|
||||||
const auto item = weak->session().data().message(
|
|
||||||
peerId,
|
|
||||||
msgId);
|
|
||||||
if (item) {
|
|
||||||
FastShareMessage(weak.get(), item);
|
|
||||||
} else {
|
|
||||||
weak->show(
|
|
||||||
Ui::MakeInformBox(tr::lng_edit_deleted()),
|
|
||||||
Ui::LayerOption::CloseOther);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
auto &api = weak->session().api();
|
|
||||||
api.requestMessageData(peer, msgId, std::move(done));
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto peer = peerIsChannel(peerId)
|
|
||||||
? controller->session().data().peerLoaded(peerId)
|
|
||||||
: nullptr;
|
|
||||||
if (peer || !peerIsChannel(peerId)) {
|
|
||||||
resolveMessageAndShareScore(peer);
|
|
||||||
} else {
|
|
||||||
const auto owner = &controller->session().data();
|
|
||||||
controller->session().api().request(MTPchannels_GetChannels(
|
|
||||||
MTP_vector<MTPInputChannel>(
|
|
||||||
1,
|
|
||||||
MTP_inputChannel(
|
|
||||||
MTP_long(peerToChannel(peerId).bare),
|
|
||||||
MTP_long(channelAccessHash)))
|
|
||||||
)).done([=](const MTPmessages_Chats &result) {
|
|
||||||
result.match([&](const auto &data) {
|
|
||||||
owner->processChats(data.vchats());
|
|
||||||
});
|
|
||||||
if (const auto peer = owner->peerLoaded(peerId)) {
|
|
||||||
resolveMessageAndShareScore(peer);
|
|
||||||
}
|
|
||||||
}).send();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -59,13 +59,11 @@ class SlideWrap;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
QString AppendShareGameScoreUrl(
|
class ShareBox;
|
||||||
not_null<Main::Session*> session,
|
|
||||||
const QString &url,
|
void FastShareMessage(
|
||||||
const FullMsgId &fullId);
|
std::shared_ptr<Main::SessionShow> show,
|
||||||
void ShareGameScoreByHash(
|
not_null<HistoryItem*> item);
|
||||||
not_null<Window::SessionController*> controller,
|
|
||||||
const QString &hash);
|
|
||||||
void FastShareMessage(
|
void FastShareMessage(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<HistoryItem*> item);
|
not_null<HistoryItem*> item);
|
||||||
|
|
|
@ -20,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/view/history_view_element.h"
|
#include "history/view/history_view_element.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
#include "inline_bots/bot_attach_web_view.h"
|
||||||
|
#include "data/data_game.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "window/window_controller.h"
|
#include "window/window_controller.h"
|
||||||
|
@ -171,23 +173,40 @@ void BotGameUrlClickHandler::onClick(ClickContext context) const {
|
||||||
if (Core::InternalPassportLink(url)) {
|
if (Core::InternalPassportLink(url)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto openLink = [=] {
|
||||||
const auto open = [=] {
|
|
||||||
UrlClickHandler::Open(url, context.other);
|
UrlClickHandler::Open(url, context.other);
|
||||||
};
|
};
|
||||||
if (url.startsWith(u"tg://"_q, Qt::CaseInsensitive)) {
|
const auto my = context.other.value<ClickHandlerContext>();
|
||||||
open();
|
const auto weakController = my.sessionWindow;
|
||||||
} else if (!_bot
|
const auto controller = weakController.get();
|
||||||
|| _bot->isVerified()
|
const auto item = controller
|
||||||
|
? controller->session().data().message(my.itemId)
|
||||||
|
: nullptr;
|
||||||
|
const auto media = item ? item->media() : nullptr;
|
||||||
|
const auto game = media ? media->game() : nullptr;
|
||||||
|
if (url.startsWith(u"tg://"_q, Qt::CaseInsensitive) || !_bot || !game) {
|
||||||
|
openLink();
|
||||||
|
}
|
||||||
|
const auto bot = _bot;
|
||||||
|
const auto title = game->title;
|
||||||
|
const auto itemId = my.itemId;
|
||||||
|
const auto openGame = [=] {
|
||||||
|
bot->session().attachWebView().showGame({
|
||||||
|
.bot = bot,
|
||||||
|
.context = itemId,
|
||||||
|
.url = url,
|
||||||
|
.title = title,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (_bot->isVerified()
|
||||||
|| _bot->session().local().isBotTrustedOpenGame(_bot->id)) {
|
|| _bot->session().local().isBotTrustedOpenGame(_bot->id)) {
|
||||||
open();
|
openGame();
|
||||||
} else {
|
} else {
|
||||||
const auto my = context.other.value<ClickHandlerContext>();
|
|
||||||
if (const auto controller = my.sessionWindow.get()) {
|
if (const auto controller = my.sessionWindow.get()) {
|
||||||
const auto callback = [=, bot = _bot](Fn<void()> close) {
|
const auto callback = [=, bot = _bot](Fn<void()> close) {
|
||||||
close();
|
close();
|
||||||
bot->session().local().markBotTrustedOpenGame(bot->id);
|
bot->session().local().markBotTrustedOpenGame(bot->id);
|
||||||
open();
|
openGame();
|
||||||
};
|
};
|
||||||
controller->show(Ui::MakeConfirmBox({
|
controller->show(Ui::MakeConfirmBox({
|
||||||
.text = tr::lng_allow_bot_pass(
|
.text = tr::lng_allow_bot_pass(
|
||||||
|
|
|
@ -327,21 +327,6 @@ bool ConfirmPhone(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShareGameScore(
|
|
||||||
Window::SessionController *controller,
|
|
||||||
const Match &match,
|
|
||||||
const QVariant &context) {
|
|
||||||
if (!controller) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto params = url_parse_params(
|
|
||||||
match->captured(1),
|
|
||||||
qthelp::UrlParamNameTransform::ToLower);
|
|
||||||
ShareGameScoreByHash(controller, params.value(u"hash"_q));
|
|
||||||
controller->window().activate();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ApplySocksProxy(
|
bool ApplySocksProxy(
|
||||||
Window::SessionController *controller,
|
Window::SessionController *controller,
|
||||||
const Match &match,
|
const Match &match,
|
||||||
|
@ -1230,10 +1215,6 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
||||||
u"^confirmphone/?\\?(.+)(#|$)"_q,
|
u"^confirmphone/?\\?(.+)(#|$)"_q,
|
||||||
ConfirmPhone
|
ConfirmPhone
|
||||||
},
|
},
|
||||||
{
|
|
||||||
u"^share_game_score/?\\?(.+)(#|$)"_q,
|
|
||||||
ShareGameScore
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
u"^socks/?\\?(.+)(#|$)"_q,
|
u"^socks/?\\?(.+)(#|$)"_q,
|
||||||
ApplySocksProxy
|
ApplySocksProxy
|
||||||
|
|
|
@ -1284,7 +1284,14 @@ void CopyPostLink(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
FullMsgId itemId,
|
FullMsgId itemId,
|
||||||
Context context) {
|
Context context) {
|
||||||
const auto item = controller->session().data().message(itemId);
|
CopyPostLink(controller->uiShow(), itemId, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyPostLink(
|
||||||
|
std::shared_ptr<Main::SessionShow> show,
|
||||||
|
FullMsgId itemId,
|
||||||
|
Context context) {
|
||||||
|
const auto item = show->session().data().message(itemId);
|
||||||
if (!item || !item->hasDirectLink()) {
|
if (!item || !item->hasDirectLink()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1311,7 +1318,7 @@ void CopyPostLink(
|
||||||
return channel->hasUsername();
|
return channel->hasUsername();
|
||||||
}();
|
}();
|
||||||
|
|
||||||
controller->showToast(isPublicLink
|
show->showToast(isPublicLink
|
||||||
? tr::lng_channel_public_link_copied(tr::now)
|
? tr::lng_channel_public_link_copied(tr::now)
|
||||||
: tr::lng_context_about_private_link(tr::now));
|
: tr::lng_context_about_private_link(tr::now));
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@ void CopyPostLink(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
FullMsgId itemId,
|
FullMsgId itemId,
|
||||||
Context context);
|
Context context);
|
||||||
|
void CopyPostLink(
|
||||||
|
std::shared_ptr<Main::SessionShow> show,
|
||||||
|
FullMsgId itemId,
|
||||||
|
Context context);
|
||||||
void CopyStoryLink(
|
void CopyStoryLink(
|
||||||
std::shared_ptr<Main::SessionShow> show,
|
std::shared_ptr<Main::SessionShow> show,
|
||||||
FullStoryId storyId);
|
FullStoryId storyId);
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_blocked_peers.h"
|
#include "api/api_blocked_peers.h"
|
||||||
#include "api/api_common.h"
|
#include "api/api_common.h"
|
||||||
#include "base/qthelp_url.h"
|
#include "base/qthelp_url.h"
|
||||||
|
#include "boxes/share_box.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
#include "data/data_bot_app.h"
|
#include "data/data_bot_app.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
@ -802,6 +803,16 @@ void AttachWebView::botInvokeCustomMethod(
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AttachWebView::botShareGameScore() {
|
||||||
|
if (!_panel || !_gameContext) {
|
||||||
|
return;
|
||||||
|
} else if (const auto item = _session->data().message(_gameContext)) {
|
||||||
|
FastShareMessage(uiShow(), item);
|
||||||
|
} else {
|
||||||
|
_panel->showToast({ tr::lng_message_not_found(tr::now) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AttachWebView::botClose() {
|
void AttachWebView::botClose() {
|
||||||
crl::on_main(this, [=] { cancel(); });
|
crl::on_main(this, [=] { cancel(); });
|
||||||
}
|
}
|
||||||
|
@ -1547,6 +1558,7 @@ void AttachWebView::show(
|
||||||
_lastShownUrl = url;
|
_lastShownUrl = url;
|
||||||
_lastShownQueryId = queryId;
|
_lastShownQueryId = queryId;
|
||||||
_lastShownButtonText = buttonText;
|
_lastShownButtonText = buttonText;
|
||||||
|
_gameContext = {};
|
||||||
base::take(_panel);
|
base::take(_panel);
|
||||||
_catchingCancelInShowCall = true;
|
_catchingCancelInShowCall = true;
|
||||||
_panel = Ui::BotWebView::Show({
|
_panel = Ui::BotWebView::Show({
|
||||||
|
@ -1562,6 +1574,24 @@ void AttachWebView::show(
|
||||||
started(queryId);
|
started(queryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AttachWebView::showGame(ShowGameParams &¶ms) {
|
||||||
|
ActiveWebViews().emplace(this);
|
||||||
|
|
||||||
|
base::take(_panel);
|
||||||
|
_gameContext = params.context;
|
||||||
|
|
||||||
|
_catchingCancelInShowCall = true;
|
||||||
|
_panel = Ui::BotWebView::Show({
|
||||||
|
.url = params.url,
|
||||||
|
.storageId = _session->local().resolveStorageIdBots(),
|
||||||
|
.title = rpl::single(params.title),
|
||||||
|
.bottom = rpl::single('@' + params.bot->username()),
|
||||||
|
.delegate = static_cast<Ui::BotWebView::Delegate*>(this),
|
||||||
|
.menuButtons = Ui::BotWebView::MenuButton::ShareGame,
|
||||||
|
});
|
||||||
|
_catchingCancelInShowCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
void AttachWebView::started(uint64 queryId) {
|
void AttachWebView::started(uint64 queryId) {
|
||||||
Expects(_bot != nullptr);
|
Expects(_bot != nullptr);
|
||||||
Expects(_context != nullptr);
|
Expects(_context != nullptr);
|
||||||
|
@ -1601,6 +1631,57 @@ void AttachWebView::started(uint64 queryId) {
|
||||||
}, _panel->lifetime());
|
}, _panel->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Main::SessionShow> AttachWebView::uiShow() {
|
||||||
|
class Show final : public Main::SessionShow {
|
||||||
|
public:
|
||||||
|
explicit Show(not_null<AttachWebView*> that) : _that(that) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void showOrHideBoxOrLayer(
|
||||||
|
std::variant<
|
||||||
|
v::null_t,
|
||||||
|
object_ptr<Ui::BoxContent>,
|
||||||
|
std::unique_ptr<Ui::LayerWidget>> &&layer,
|
||||||
|
Ui::LayerOptions options,
|
||||||
|
anim::type animated) const override {
|
||||||
|
using UniqueLayer = std::unique_ptr<Ui::LayerWidget>;
|
||||||
|
using ObjectBox = object_ptr<Ui::BoxContent>;
|
||||||
|
const auto panel = _that ? _that->_panel.get() : nullptr;
|
||||||
|
if (auto layerWidget = std::get_if<UniqueLayer>(&layer)) {
|
||||||
|
Unexpected("Layers in AttachWebView are not implemented.");
|
||||||
|
} else if (auto box = std::get_if<ObjectBox>(&layer)) {
|
||||||
|
if (panel) {
|
||||||
|
panel->showBox(std::move(*box), options, animated);
|
||||||
|
}
|
||||||
|
} else if (panel) {
|
||||||
|
panel->hideLayer(animated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[[nodiscard]] not_null<QWidget*> toastParent() const override {
|
||||||
|
const auto panel = _that ? _that->_panel.get() : nullptr;
|
||||||
|
|
||||||
|
Ensures(panel != nullptr);
|
||||||
|
return panel->toastParent();
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool valid() const override {
|
||||||
|
return _that && (_that->_panel != nullptr);
|
||||||
|
}
|
||||||
|
operator bool() const override {
|
||||||
|
return valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Main::Session &session() const override {
|
||||||
|
Expects(_that.get() != nullptr);
|
||||||
|
return *_that->_session;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const base::weak_ptr<AttachWebView> _that;
|
||||||
|
|
||||||
|
};
|
||||||
|
return std::make_shared<Show>(this);
|
||||||
|
}
|
||||||
|
|
||||||
void AttachWebView::showToast(
|
void AttachWebView::showToast(
|
||||||
const QString &text,
|
const QString &text,
|
||||||
Window::SessionController *controller) {
|
Window::SessionController *controller) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ class Panel;
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
|
class SessionShow;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
@ -155,12 +156,21 @@ public:
|
||||||
[[nodiscard]] std::optional<Api::SendAction> lookupLastAction(
|
[[nodiscard]] std::optional<Api::SendAction> lookupLastAction(
|
||||||
const QString &url) const;
|
const QString &url) const;
|
||||||
|
|
||||||
|
struct ShowGameParams {
|
||||||
|
not_null<UserData*> bot;
|
||||||
|
FullMsgId context;
|
||||||
|
QString url;
|
||||||
|
QString title;
|
||||||
|
};
|
||||||
|
void showGame(ShowGameParams &¶ms);
|
||||||
|
|
||||||
|
[[nodiscard]] std::shared_ptr<Main::SessionShow> uiShow();
|
||||||
|
|
||||||
static void ClearAll();
|
static void ClearAll();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Context;
|
struct Context;
|
||||||
|
|
||||||
|
|
||||||
Webview::ThemeParams botThemeParams() override;
|
Webview::ThemeParams botThemeParams() override;
|
||||||
bool botHandleLocalUri(QString uri, bool keepOpen) override;
|
bool botHandleLocalUri(QString uri, bool keepOpen) override;
|
||||||
void botHandleInvoice(QString slug) override;
|
void botHandleInvoice(QString slug) override;
|
||||||
|
@ -176,6 +186,7 @@ private:
|
||||||
void botSharePhone(Fn<void(bool shared)> callback) override;
|
void botSharePhone(Fn<void(bool shared)> callback) override;
|
||||||
void botInvokeCustomMethod(
|
void botInvokeCustomMethod(
|
||||||
Ui::BotWebView::CustomMethodRequest request) override;
|
Ui::BotWebView::CustomMethodRequest request) override;
|
||||||
|
void botShareGameScore() override;
|
||||||
void botClose() override;
|
void botClose() override;
|
||||||
|
|
||||||
[[nodiscard]] static Context LookupContext(
|
[[nodiscard]] static Context LookupContext(
|
||||||
|
@ -271,6 +282,8 @@ private:
|
||||||
rpl::event_stream<> _attachBotsUpdates;
|
rpl::event_stream<> _attachBotsUpdates;
|
||||||
base::flat_set<not_null<UserData*>> _disclaimerAccepted;
|
base::flat_set<not_null<UserData*>> _disclaimerAccepted;
|
||||||
|
|
||||||
|
FullMsgId _gameContext;
|
||||||
|
|
||||||
std::unique_ptr<Ui::BotWebView::Panel> _panel;
|
std::unique_ptr<Ui::BotWebView::Panel> _panel;
|
||||||
bool _catchingCancelInShowCall = false;
|
bool _catchingCancelInShowCall = false;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "webview/webview_interface.h"
|
#include "webview/webview_interface.h"
|
||||||
#include "base/debug_log.h"
|
#include "base/debug_log.h"
|
||||||
#include "base/invoke_queued.h"
|
#include "base/invoke_queued.h"
|
||||||
|
#include "base/qt_signal_producer.h"
|
||||||
#include "styles/style_payments.h"
|
#include "styles/style_payments.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_menu_icons.h"
|
#include "styles/style_menu_icons.h"
|
||||||
|
@ -34,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtCore/QJsonArray>
|
#include <QtCore/QJsonArray>
|
||||||
#include <QtGui/QGuiApplication>
|
#include <QtGui/QGuiApplication>
|
||||||
#include <QtGui/QClipboard>
|
#include <QtGui/QClipboard>
|
||||||
|
#include <QtGui/QWindow>
|
||||||
|
|
||||||
namespace Ui::BotWebView {
|
namespace Ui::BotWebView {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -373,6 +375,13 @@ Panel::~Panel() {
|
||||||
|
|
||||||
void Panel::requestActivate() {
|
void Panel::requestActivate() {
|
||||||
_widget->showAndActivate();
|
_widget->showAndActivate();
|
||||||
|
if (const auto widget = _webview ? _webview->window.widget() : nullptr) {
|
||||||
|
InvokeQueued(widget, [=] {
|
||||||
|
if (widget->isVisible()) {
|
||||||
|
_webview->window.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::toggleProgress(bool shown) {
|
void Panel::toggleProgress(bool shown) {
|
||||||
|
@ -527,9 +536,15 @@ bool Panel::showWebview(
|
||||||
_webview->window.navigate(url);
|
_webview->window.navigate(url);
|
||||||
}
|
}
|
||||||
}, &st::menuIconRestore);
|
}, &st::menuIconRestore);
|
||||||
callback(tr::lng_bot_terms(tr::now), [=] {
|
if (_menuButtons & MenuButton::ShareGame) {
|
||||||
File::OpenUrl(tr::lng_mini_apps_tos_url(tr::now));
|
callback(tr::lng_iv_share(tr::now), [=] {
|
||||||
}, &st::menuIconGroupLog);
|
_delegate->botShareGameScore();
|
||||||
|
}, &st::menuIconShare);
|
||||||
|
} else {
|
||||||
|
callback(tr::lng_bot_terms(tr::now), [=] {
|
||||||
|
File::OpenUrl(tr::lng_mini_apps_tos_url(tr::now));
|
||||||
|
}, &st::menuIconGroupLog);
|
||||||
|
}
|
||||||
const auto main = (_menuButtons & MenuButton::RemoveFromMainMenu);
|
const auto main = (_menuButtons & MenuButton::RemoveFromMainMenu);
|
||||||
if (main || (_menuButtons & MenuButton::RemoveFromMenu)) {
|
if (main || (_menuButtons & MenuButton::RemoveFromMenu)) {
|
||||||
const auto handler = [=] {
|
const auto handler = [=] {
|
||||||
|
@ -691,6 +706,8 @@ bool Panel::createWebview(const Webview::ThemeParams ¶ms) {
|
||||||
requestClipboardText(arguments);
|
requestClipboardText(arguments);
|
||||||
} else if (command == "web_app_set_header_color") {
|
} else if (command == "web_app_set_header_color") {
|
||||||
processHeaderColor(arguments);
|
processHeaderColor(arguments);
|
||||||
|
} else if (command == "share_score") {
|
||||||
|
_delegate->botShareGameScore();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -722,6 +739,17 @@ postEvent: function(eventType, eventData) {
|
||||||
|
|
||||||
setupProgressGeometry();
|
setupProgressGeometry();
|
||||||
|
|
||||||
|
base::qt_signal_producer(
|
||||||
|
_widget->window()->windowHandle(),
|
||||||
|
&QWindow::activeChanged
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return _webview && _widget->window()->windowHandle()->isActive();
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
if (_webview && !_webview->window.widget()->isHidden()) {
|
||||||
|
_webview->window.focus();
|
||||||
|
}
|
||||||
|
}, _webview->lifetime);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1207,6 +1235,13 @@ void Panel::updateFooterHeight() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::showBox(object_ptr<BoxContent> box) {
|
void Panel::showBox(object_ptr<BoxContent> box) {
|
||||||
|
showBox(std::move(box), LayerOption::KeepOther, anim::type::normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::showBox(
|
||||||
|
object_ptr<BoxContent> box,
|
||||||
|
LayerOptions options,
|
||||||
|
anim::type animated) {
|
||||||
if (const auto widget = _webview ? _webview->window.widget() : nullptr) {
|
if (const auto widget = _webview ? _webview->window.widget() : nullptr) {
|
||||||
const auto hideNow = !widget->isHidden();
|
const auto hideNow = !widget->isHidden();
|
||||||
if (hideNow || _webview->lastHidingBox) {
|
if (hideNow || _webview->lastHidingBox) {
|
||||||
|
@ -1220,10 +1255,12 @@ void Panel::showBox(object_ptr<BoxContent> box) {
|
||||||
&& widget->isHidden()
|
&& widget->isHidden()
|
||||||
&& _webview->lastHidingBox == raw) {
|
&& _webview->lastHidingBox == raw) {
|
||||||
widget->show();
|
widget->show();
|
||||||
|
_webviewBottom->show();
|
||||||
}
|
}
|
||||||
}, _webview->lifetime);
|
}, _webview->lifetime);
|
||||||
if (hideNow) {
|
if (hideNow) {
|
||||||
widget->hide();
|
widget->hide();
|
||||||
|
_webviewBottom->hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1237,6 +1274,14 @@ void Panel::showToast(TextWithEntities &&text) {
|
||||||
_widget->showToast(std::move(text));
|
_widget->showToast(std::move(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<QWidget*> Panel::toastParent() const {
|
||||||
|
return _widget->uiShow()->toastParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::hideLayer(anim::type animated) {
|
||||||
|
_widget->hideLayer(animated);
|
||||||
|
}
|
||||||
|
|
||||||
void Panel::showCriticalError(const TextWithEntities &text) {
|
void Panel::showCriticalError(const TextWithEntities &text) {
|
||||||
_progress = nullptr;
|
_progress = nullptr;
|
||||||
_webviewProgress = false;
|
_webviewProgress = false;
|
||||||
|
|
|
@ -20,6 +20,8 @@ namespace Ui {
|
||||||
class BoxContent;
|
class BoxContent;
|
||||||
class RpWidget;
|
class RpWidget;
|
||||||
class SeparatePanel;
|
class SeparatePanel;
|
||||||
|
enum class LayerOption;
|
||||||
|
using LayerOptions = base::flags<LayerOption>;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Webview {
|
namespace Webview {
|
||||||
|
@ -40,6 +42,7 @@ enum class MenuButton {
|
||||||
OpenBot = 0x01,
|
OpenBot = 0x01,
|
||||||
RemoveFromMenu = 0x02,
|
RemoveFromMenu = 0x02,
|
||||||
RemoveFromMainMenu = 0x04,
|
RemoveFromMainMenu = 0x04,
|
||||||
|
ShareGame = 0x08,
|
||||||
};
|
};
|
||||||
inline constexpr bool is_flag_type(MenuButton) { return true; }
|
inline constexpr bool is_flag_type(MenuButton) { return true; }
|
||||||
using MenuButtons = base::flags<MenuButton>;
|
using MenuButtons = base::flags<MenuButton>;
|
||||||
|
@ -67,6 +70,7 @@ public:
|
||||||
virtual void botAllowWriteAccess(Fn<void(bool allowed)> callback) = 0;
|
virtual void botAllowWriteAccess(Fn<void(bool allowed)> callback) = 0;
|
||||||
virtual void botSharePhone(Fn<void(bool shared)> callback) = 0;
|
virtual void botSharePhone(Fn<void(bool shared)> callback) = 0;
|
||||||
virtual void botInvokeCustomMethod(CustomMethodRequest request) = 0;
|
virtual void botInvokeCustomMethod(CustomMethodRequest request) = 0;
|
||||||
|
virtual void botShareGameScore() = 0;
|
||||||
virtual void botClose() = 0;
|
virtual void botClose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,7 +93,13 @@ public:
|
||||||
rpl::producer<QString> bottomText);
|
rpl::producer<QString> bottomText);
|
||||||
|
|
||||||
void showBox(object_ptr<BoxContent> box);
|
void showBox(object_ptr<BoxContent> box);
|
||||||
|
void showBox(
|
||||||
|
object_ptr<BoxContent> box,
|
||||||
|
LayerOptions options,
|
||||||
|
anim::type animated);
|
||||||
|
void hideLayer(anim::type animated);
|
||||||
void showToast(TextWithEntities &&text);
|
void showToast(TextWithEntities &&text);
|
||||||
|
not_null<QWidget*> toastParent() const;
|
||||||
void showCriticalError(const TextWithEntities &text);
|
void showCriticalError(const TextWithEntities &text);
|
||||||
void showWebviewError(
|
void showWebviewError(
|
||||||
const QString &text,
|
const QString &text,
|
||||||
|
|
Loading…
Add table
Reference in a new issue