diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 1f579cc31..741c3c577 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3526,9 +3526,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) { finishForwarding(action); } -void ApiWrap::sendBotStart(not_null bot, PeerData *chat) { +void ApiWrap::sendBotStart( + not_null bot, + PeerData *chat, + const QString &startTokenForChat) { Expects(bot->isBot()); - Expects(chat == nullptr || !bot->botInfo->startGroupToken.isEmpty()); if (chat && chat->isChannel() && !chat->isMegagroup()) { ShowAddParticipantsError("USER_BOT", chat, { 1, bot }); @@ -3536,20 +3538,28 @@ void ApiWrap::sendBotStart(not_null bot, PeerData *chat) { } auto &info = bot->botInfo; - auto &token = chat ? info->startGroupToken : info->startToken; + auto &token = chat ? startTokenForChat : info->startToken; if (token.isEmpty()) { auto message = MessageToSend( - Api::SendAction(_session->data().history(bot))); - message.textWithTags = { qsl("/start"), TextWithTags::Tags() }; + Api::SendAction(_session->data().history(chat + ? chat + : bot.get()))); + message.textWithTags = { u"/start"_q, TextWithTags::Tags() }; + if (chat) { + message.textWithTags.text += '@' + bot->username; + } sendMessage(std::move(message)); return; } const auto randomId = base::RandomValue(); + if (!chat) { + info->startToken = QString(); + } request(MTPmessages_StartBot( bot->inputUser, chat ? chat->input : MTP_inputPeerEmpty(), MTP_long(randomId), - MTP_string(base::take(token)) + MTP_string(token) )).done([=](const MTPUpdates &result) { applyUpdates(result); }).fail([=](const MTP::Error &error) { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index df431ba74..93870829d 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -320,7 +320,10 @@ public: void cancelLocalItem(not_null item); void sendMessage(MessageToSend &&message); - void sendBotStart(not_null bot, PeerData *chat = nullptr); + void sendBotStart( + not_null bot, + PeerData *chat = nullptr, + const QString &startTokenForChat = QString()); void sendInlineResult( not_null bot, not_null data, diff --git a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp index c6f182adc..6509064f8 100644 --- a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.cpp @@ -19,6 +19,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_participants_box.h" #include "boxes/filters/edit_filter_chats_list.h" #include "ui/boxes/confirm_box.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/wrap/slide_wrap.h" #include "base/random.h" #include "base/weak_ptr.h" #include "api/api_chat_participants.h" @@ -54,7 +56,10 @@ private: }; -void ShareBotGame(not_null bot, not_null chat) { +void ShareBotGame( + not_null bot, + not_null chat, + const QString &shortName) { const auto history = chat->owner().history(chat); auto &histories = history->owner().histories(); const auto requestType = Data::Histories::RequestType::Send; @@ -68,7 +73,7 @@ void ShareBotGame(not_null bot, not_null chat) { MTP_inputMediaGame( MTP_inputGameShortName( bot->inputUser, - MTP_string(bot->botInfo->shareGameShortName))), + MTP_string(shortName))), MTP_string(), MTP_long(randomId), MTPReplyMarkup(), @@ -138,23 +143,40 @@ void Controller::addRow(not_null peer) { } // namespace -void AddBotToGroupBoxController::Start(not_null bot) { +void AddBotToGroupBoxController::Start( + not_null bot, + Scope scope, + const QString &token, + ChatAdminRights requestedRights) { auto initBox = [=](not_null box) { box->addButton(tr::lng_cancel(), [box] { box->closeBox(); }); }; Ui::show(Box( - std::make_unique(bot), + std::make_unique( + bot, + scope, + token, + requestedRights), std::move(initBox))); } AddBotToGroupBoxController::AddBotToGroupBoxController( - not_null bot) -: ChatsListBoxController(SharingBotGame(bot) + not_null bot, + Scope scope, + const QString &token, + ChatAdminRights requestedRights) +: ChatsListBoxController((scope == Scope::ShareGame) ? std::make_unique(&bot->session()) : nullptr) , _bot(bot) -, _adminToGroup(_bot->botInfo->groupAdminRights != 0) -, _adminToChannel(_bot->botInfo->channelAdminRights != 0) { +, _scope(scope) +, _token(token) +, _requestedRights(requestedRights) +, _adminToGroup((scope == Scope::GroupAdmin) + || (scope == Scope::All && _bot->botInfo->groupAdminRights != 0)) +, _adminToChannel((scope == Scope::ChannelAdmin) + || (scope == Scope::All && _bot->botInfo->channelAdminRights != 0)) +, _memberToGroup(scope == Scope::All) { } Main::Session &AddBotToGroupBoxController::session() const { @@ -170,8 +192,8 @@ void AddBotToGroupBoxController::rowClicked(not_null row) { } void AddBotToGroupBoxController::shareBotGame(not_null chat) { - auto send = crl::guard(this, [bot = _bot, chat] { - ShareBotGame(bot, chat); + auto send = crl::guard(this, [bot = _bot, chat, token = _token] { + ShareBotGame(bot, chat, token); }); auto confirmText = [chat] { if (chat->isUser()) { @@ -187,6 +209,34 @@ void AddBotToGroupBoxController::shareBotGame(not_null chat) { Ui::LayerOption::KeepOther); } +void AddBotToGroupBoxController::requestExistingRights( + not_null channel) { + if (_existingRightsChannel == channel) { + return; + } + _existingRightsChannel = channel; + _bot->session().api().request(_existingRightsRequestId).cancel(); + _existingRightsRequestId = _bot->session().api().request( + MTPchannels_GetParticipant( + _existingRightsChannel->inputChannel, + _bot->input) + ).done([=](const MTPchannels_ChannelParticipant &result) { + result.match([&](const MTPDchannels_channelParticipant &data) { + channel->owner().processUsers(data.vusers()); + const auto participant = Api::ChatParticipant( + data.vparticipant(), + channel); + _existingRights = participant.rights().flags; + _existingRank = participant.rank(); + addBotToGroup(_existingRightsChannel); + }); + }).fail([=] { + _existingRights = ChatAdminRights(); + _existingRank = QString(); + addBotToGroup(_existingRightsChannel); + }).send(); +} + void AddBotToGroupBoxController::addBotToGroup(not_null chat) { if (const auto megagroup = chat->asMegagroup()) { if (!megagroup->canAddMembers()) { @@ -196,38 +246,66 @@ void AddBotToGroupBoxController::addBotToGroup(not_null chat) { return; } } + if (_existingRightsChannel != chat) { + _existingRights = {}; + _existingRank = QString(); + _existingRightsChannel = nullptr; + _bot->session().api().request(_existingRightsRequestId).cancel(); + } + const auto requestedAddAdmin = (_scope == Scope::GroupAdmin) + || (_scope == Scope::ChannelAdmin); + if (chat->isChannel() + && requestedAddAdmin + && !_existingRights.has_value()) { + requestExistingRights(chat->asChannel()); + return; + } const auto bot = _bot; const auto close = [=](auto&&...) { Ui::hideLayer(); Ui::showPeerHistory(chat, ShowAtUnreadMsgId); }; - const auto rights = (chat->isBroadcast() - && chat->asBroadcast()->canAddAdmins()) + const auto rights = requestedAddAdmin + ? _requestedRights + : (chat->isBroadcast() + && chat->asBroadcast()->canAddAdmins()) ? bot->botInfo->channelAdminRights : ((chat->isMegagroup() && chat->asMegagroup()->canAddAdmins()) || (chat->isChat() && chat->asChat()->canAddAdmins())) ? bot->botInfo->groupAdminRights : ChatAdminRights(); - if (rights) { + const auto addingAdmin = requestedAddAdmin || (rights != 0); + if (addingAdmin) { + const auto scope = _scope; + const auto token = _token; + const auto done = [=]( + ChatAdminRightsInfo newRights, + const QString &rank) { + if (scope == Scope::GroupAdmin) { + chat->session().api().sendBotStart(bot, chat, token); + } + close(); + }; const auto saveCallback = SaveAdminCallback( chat, bot, - close, + done, close); - auto box = object_ptr(nullptr); - box = Box( + auto box = Box( chat, bot, ChatAdminRightsInfo(rights), - QString(), - true); + _existingRank, + EditAdminBotFields{ + _token, + _existingRights.value_or(ChatAdminRights()) }); box->setSaveCallback(saveCallback); Ui::show(std::move(box), Ui::LayerOption::KeepOther); } else { Ui::show( Ui::MakeConfirmBox({ tr::lng_bot_sure_invite(tr::now, lt_group, chat->name), - crl::guard(this, [=] { AddBotToGroup(bot, chat); }), + crl::guard(this, [=] { AddBotToGroup(bot, chat, _token); }), }), Ui::LayerOption::KeepOther); } @@ -251,32 +329,33 @@ bool AddBotToGroupBoxController::needToCreateRow( return true; } if (const auto chat = peer->asChat()) { - if (_adminToGroup && chat->canAddAdmins()) { + if (onlyAdminToGroup()) { + return chat->canAddAdmins(); + } else if (_adminToGroup && chat->canAddAdmins()) { _groups.fire_copy(peer); - } else { + } else if (!onlyAdminToChannel()) { return chat->canAddMembers(); } } else if (const auto group = peer->asMegagroup()) { - if (_adminToGroup && group->canAddAdmins()) { + if (onlyAdminToGroup()) { + return group->canAddAdmins(); + } else if (_adminToGroup && group->canAddAdmins()) { _groups.fire_copy(peer); - } else { + } else if (!onlyAdminToChannel()) { return group->canAddMembers(); } } else if (const auto channel = peer->asBroadcast()) { - if (_adminToChannel && channel->canAddAdmins()) { + if (onlyAdminToChannel()) { + return channel->canAddAdmins(); + } else if (_adminToChannel && channel->canAddAdmins()) { _channels.fire_copy(peer); } } return false; } -bool AddBotToGroupBoxController::SharingBotGame(not_null bot) { - const auto &info = bot->botInfo; - return (info && !info->shareGameShortName.isEmpty()); -} - bool AddBotToGroupBoxController::sharingBotGame() const { - return SharingBotGame(_bot); + return (_scope == Scope::ShareGame); } QString AddBotToGroupBoxController::emptyBoxText() const { @@ -310,29 +389,31 @@ object_ptr AddBotToGroupBoxController::prepareAdminnedChats() { const auto addList = [&]( tr::phrase<> subtitle, rpl::event_stream> &items) { - container->add(CreatePeerListSectionSubtitle( - container, - subtitle())); - container->add(object_ptr( - container, - st::membersMarginTop)); + const auto wrap = container->add( + object_ptr>( + container, + object_ptr(container))); + wrap->hide(anim::type::instant); - const auto delegate = container->lifetime().make_state< + const auto inner = wrap->entity(); + inner->add(CreatePeerListSectionSubtitle(inner, subtitle())); + + const auto delegate = inner->lifetime().make_state< PeerListContentDelegateSimple >(); - const auto controller = container->lifetime().make_state( + const auto controller = inner->lifetime().make_state( &session(), items.events(), callback); - const auto content = result->add(object_ptr( + const auto content = inner->add(object_ptr( container, controller)); delegate->setContent(content); controller->setDelegate(delegate); - container->add(object_ptr( - container, - st::membersMarginBottom)); + items.events() | rpl::take(1) | rpl::start_with_next([=] { + wrap->show(anim::type::instant); + }, inner->lifetime()); }; if (_adminToChannel) { addList(tr::lng_bot_channels_manage, _channels); @@ -353,11 +434,20 @@ object_ptr AddBotToGroupBoxController::prepareAdminnedChats() { return result; } +bool AddBotToGroupBoxController::onlyAdminToGroup() const { + return _adminToGroup && !_memberToGroup && !_adminToChannel; +} + +bool AddBotToGroupBoxController::onlyAdminToChannel() const { + return _adminToChannel && !_memberToGroup && !_adminToGroup; +} + void AddBotToGroupBoxController::prepareViewHook() { delegate()->peerListSetTitle((sharingBotGame() || _adminToChannel) ? tr::lng_bot_choose_chat() : tr::lng_bot_choose_group()); - if (_adminToGroup || _adminToChannel) { + if ((_adminToGroup && !onlyAdminToGroup()) + || (_adminToChannel && !onlyAdminToChannel())) { delegate()->peerListSetAboveWidget(prepareAdminnedChats()); } @@ -370,9 +460,12 @@ void AddBotToGroupBoxController::prepareViewHook() { }, lifetime()); } -void AddBotToGroup(not_null bot, not_null chat) { - if (bot->isBot() && !bot->botInfo->startGroupToken.isEmpty()) { - chat->session().api().sendBotStart(bot, chat); +void AddBotToGroup( + not_null bot, + not_null chat, + const QString &startToken) { + if (!startToken.isEmpty()) { + chat->session().api().sendBotStart(bot, chat, startToken); } else { chat->session().api().chatParticipants().add(chat, { 1, bot }); } diff --git a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.h b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.h index 4a2b3ae40..51f6cbbfe 100644 --- a/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.h +++ b/Telegram/SourceFiles/boxes/peers/add_bot_to_chat_box.h @@ -8,14 +8,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "boxes/peer_list_controllers.h" +#include "data/data_chat_participant_status.h" class AddBotToGroupBoxController : public ChatsListBoxController , public base::has_weak_ptr { public: - static void Start(not_null bot); + enum class Scope { + None, + GroupAdmin, + ChannelAdmin, + ShareGame, + All, + }; + static void Start( + not_null bot, + Scope scope = Scope::All, + const QString &token = QString(), + ChatAdminRights requestedRights = {}); - explicit AddBotToGroupBoxController(not_null bot); + AddBotToGroupBoxController( + not_null bot, + Scope scope, + const QString &token, + ChatAdminRights requestedRights); Main::Session &session() const override; void rowClicked(not_null row) override; @@ -26,9 +42,10 @@ protected: QString emptyBoxText() const override; private: - static bool SharingBotGame(not_null bot); + [[nodiscard]] object_ptr prepareAdminnedChats(); - object_ptr prepareAdminnedChats(); + [[nodiscard]] bool onlyAdminToGroup() const; + [[nodiscard]] bool onlyAdminToChannel() const; bool needToCreateRow(not_null peer) const; bool sharingBotGame() const; @@ -37,13 +54,28 @@ private: void shareBotGame(not_null chat); void addBotToGroup(not_null chat); + void requestExistingRights(not_null channel); const not_null _bot; + const Scope _scope = Scope::None; + const QString _token; + const ChatAdminRights _requestedRights; + + ChannelData *_existingRightsChannel = nullptr; + mtpRequestId _existingRightsRequestId = 0; + std::optional _existingRights; + QString _existingRank; + rpl::event_stream> _groups; rpl::event_stream> _channels; + bool _adminToGroup = false; bool _adminToChannel = false; + bool _memberToGroup = false; }; -void AddBotToGroup(not_null bot, not_null chat); +void AddBotToGroup( + not_null bot, + not_null chat, + const QString &startToken); diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp index 9134a1d49..c823481c1 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp @@ -200,7 +200,7 @@ EditAdminBox::EditAdminBox( not_null user, ChatAdminRightsInfo rights, const QString &rank, - bool addingBot) + std::optional addingBot) : EditParticipantBox( nullptr, peer, @@ -209,7 +209,7 @@ EditAdminBox::EditAdminBox( , _show(this) , _oldRights(rights) , _oldRank(rank) -, _addingBot(addingBot) { +, _addingBot(std::move(addingBot)) { } ChatAdminRightsInfo EditAdminBox::defaultRights() const { @@ -240,12 +240,17 @@ void EditAdminBox::prepare() { EditParticipantBox::prepare(); setTitle(_addingBot - ? tr::lng_bot_add_title() + ? (_addingBot->existing + ? tr::lng_rights_edit_admin() + : tr::lng_bot_add_title()) : _oldRights.flags ? tr::lng_rights_edit_admin() : tr::lng_channel_add_admin()); - if (_addingBot && !peer()->isBroadcast() && _saveCallback) { + if (_addingBot + && !_addingBot->existing + && !peer()->isBroadcast() + && _saveCallback) { addControl( object_ptr(this), st::rightsDividerMargin / 2); @@ -277,7 +282,9 @@ void EditAdminBox::prepare() { const auto chat = peer()->asChat(); const auto channel = peer()->asChannel(); - const auto prepareRights = _oldRights.flags + const auto prepareRights = _addingBot + ? ChatAdminRightsInfo(_oldRights.flags | _addingBot->existing) + : _oldRights.flags ? _oldRights : defaultRights(); const auto disabledByDefaults = (channel && !channel->isMegagroup()) @@ -368,7 +375,7 @@ void EditAdminBox::prepare() { ? ~Flags(0) : channel->adminRights()); _saveCallback( - _addingBot ? ChatAdminRightsInfo() : _oldRights, + _oldRights, ChatAdminRightsInfo(newFlags), _rank ? _rank->getLastText().trimmed() : QString()); }; @@ -376,9 +383,9 @@ void EditAdminBox::prepare() { if (!_saveCallback) { return; } else if (_addAsAdmin && !_addAsAdmin->checked()) { - AddBotToGroup(user(), peer()); + AddBotToGroup(user(), peer(), _addingBot->token); return; - } else if (_addingBot) { + } else if (_addingBot && !_addingBot->existing) { const auto phrase = peer()->isBroadcast() ? tr::lng_bot_sure_add_text_channel : tr::lng_bot_sure_add_text_group; @@ -409,7 +416,7 @@ void EditAdminBox::finishAddAdmin() { void EditAdminBox::refreshButtons() { clearButtons(); if (canSave()) { - addButton(!_addingBot + addButton((!_addingBot || _addingBot->existing) ? tr::lng_settings_save() : _adminControlsWrap->toggled() ? tr::lng_bot_add_as_admin() diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.h b/Telegram/SourceFiles/boxes/peers/edit_participant_box.h index a7cf34121..6fc73a93d 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.h @@ -65,6 +65,11 @@ private: }; +struct EditAdminBotFields { + QString token; + ChatAdminRights existing; +}; + class EditAdminBox : public EditParticipantBox { public: EditAdminBox( @@ -73,7 +78,7 @@ public: not_null user, ChatAdminRightsInfo rights, const QString &rank, - bool addingBot = false); + std::optional addingBot = {}); void setSaveCallback( Fn _save, _finishSave; - bool _addingBot = false; + std::optional _addingBot; }; diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 8ad1a71d6..86f3a98ee 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -251,6 +251,39 @@ bool ShowWallPaper( params); } +[[nodiscard]] ChatAdminRights ParseRequestedAdminRights( + const QString &value) { + auto result = ChatAdminRights(); + for (const auto &element : value.split(QRegularExpression("[+ ]"))) { + if (element == u"change_info"_q) { + result |= ChatAdminRight::ChangeInfo; + } else if (element == u"post_messages"_q) { + result |= ChatAdminRight::PostMessages; + } else if (element == u"edit_messages"_q) { + result |= ChatAdminRight::EditMessages; + } else if (element == u"delete_messages"_q) { + result |= ChatAdminRight::DeleteMessages; + } else if (element == u"restrict_members"_q) { + result |= ChatAdminRight::BanUsers; + } else if (element == u"invite_users"_q) { + result |= ChatAdminRight::InviteUsers; + } else if (element == u"pin_messages"_q) { + result |= ChatAdminRight::PinMessages; + } else if (element == u"promote_members"_q) { + result |= ChatAdminRight::AddAdmins; + } else if (element == u"manage_video_chats"_q) { + result |= ChatAdminRight::ManageCall; + } else if (element == u"anonymous"_q) { + result |= ChatAdminRight::Anonymous; + } else if (element == u"manage_chat"_q) { + result |= ChatAdminRight::Other; + } else { + return {}; + } + } + return result; +} + bool ResolveUsernameOrPhone( Window::SessionController *controller, const Match &match, @@ -278,18 +311,24 @@ bool ResolveUsernameOrPhone( } else if (!validDomain(domain) && !validPhone(phone)) { return false; } - auto start = qsl("start"); - auto startToken = params.value(start); - if (startToken.isEmpty()) { - start = qsl("startgroup"); - startToken = params.value(start); - if (startToken.isEmpty()) { - start = QString(); - } + using BotStartType = Window::BotStartType; + auto startType = BotStartType::None; + auto startToken = params.value(u"start"_q); + if (!startToken.isEmpty()) { + startType = BotStartType::Personal; + } else if (params.contains(u"startgroup"_q)) { + startType = BotStartType::Group; + startToken = params.value(u"startgroup"_q); + } else if (params.contains(u"startchannel"_q)) { + startType = BotStartType::Channel; + } + auto post = ShowAtUnreadMsgId; + auto adminRights = ChatAdminRights(); + if (startType == BotStartType::Group + || startType == BotStartType::Channel) { + post = ShowAtProfileMsgId; + adminRights = ParseRequestedAdminRights(params.value(u"admin"_q)); } - auto post = (start == qsl("startgroup")) - ? ShowAtProfileMsgId - : ShowAtUnreadMsgId; const auto postParam = params.value(qsl("post")); if (const auto postId = postParam.toInt()) { post = postId; @@ -301,7 +340,8 @@ bool ResolveUsernameOrPhone( const auto gameParam = params.value(qsl("game")); if (!gameParam.isEmpty() && validDomain(gameParam)) { startToken = gameParam; - post = ShowAtGameShareMsgId; + post = ShowAtProfileMsgId; + startType = BotStartType::ShareGame; } const auto fromMessageId = context.value().itemId; using Navigation = Window::SessionNavigation; @@ -318,7 +358,9 @@ bool ResolveUsernameOrPhone( Navigation::ThreadId{ threadId } } : Navigation::RepliesByLinkInfo{ v::null }, + .startType = startType, .startToken = startToken, + .startAdminRights = adminRights, .voicechatHash = (params.contains(u"livestream"_q) ? std::make_optional(params.value(u"livestream"_q)) : params.contains(u"videochat"_q) diff --git a/Telegram/SourceFiles/data/data_msg_id.h b/Telegram/SourceFiles/data/data_msg_id.h index 24e1c5325..018722046 100644 --- a/Telegram/SourceFiles/data/data_msg_id.h +++ b/Telegram/SourceFiles/data/data_msg_id.h @@ -84,7 +84,6 @@ constexpr auto ShowAtTheEndMsgId = MsgId(SpecialMsgIdShift + 1); constexpr auto SwitchAtTopMsgId = MsgId(SpecialMsgIdShift + 2); constexpr auto ShowAtProfileMsgId = MsgId(SpecialMsgIdShift + 3); constexpr auto ShowAndStartBotMsgId = MsgId(SpecialMsgIdShift + 4); -constexpr auto ShowAtGameShareMsgId = MsgId(SpecialMsgIdShift + 5); constexpr auto ShowForChooseMessagesMsgId = MsgId(SpecialMsgIdShift + 6); static_assert(SpecialMsgIdShift + 0xFF < 0); diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index cfb1348b3..04fe28760 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -20,7 +20,7 @@ struct BotInfo { std::vector commands; Ui::Text::String text = { int(st::msgMinWidth) }; // description - QString startToken, startGroupToken, shareGameShortName; + QString startToken; Dialogs::EntryState inlineReturnTo; ChatAdminRights groupAdminRights; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 264f91b60..6f16eb04f 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -338,6 +338,7 @@ void SessionNavigation::showPeerByLinkResolved( }).send(); return; } + using Scope = AddBotToGroupBoxController::Scope; const auto &replies = info.repliesInfo; if (const auto threadId = std::get_if(&replies)) { showRepliesForMessage( @@ -351,31 +352,28 @@ void SessionNavigation::showPeerByLinkResolved( info.messageId, commentId->id, params); - } else if (info.messageId == ShowAtGameShareMsgId) { - const auto user = peer->asUser(); - if (user && user->isBot() && !info.startToken.isEmpty()) { - user->botInfo->shareGameShortName = info.startToken; - AddBotToGroupBoxController::Start(user); - } else { - crl::on_main(this, [=] { - showPeerHistory(peer->id, params); - }); - } } else if (info.messageId == ShowAtProfileMsgId && !peer->isChannel()) { const auto user = peer->asUser(); - if (user - && user->isBot() - && !user->botInfo->cantJoinGroups - && !info.startToken.isEmpty()) { - user->botInfo->startGroupToken = info.startToken; - AddBotToGroupBoxController::Start(user); - } else if (user && user->isBot()) { + const auto scope = (info.startType == BotStartType::ShareGame) + ? Scope::ShareGame + : (info.startType == BotStartType::Group) + ? (info.startAdminRights ? Scope::GroupAdmin : Scope::All) + : (info.startType == BotStartType::Channel) + ? Scope::ChannelAdmin + : Scope::None; + if (!user || !user->isBot()) { + showPeerInfo(peer, params); + } else if (scope != Scope::None) { + AddBotToGroupBoxController::Start( + user, + scope, + info.startToken, + info.startAdminRights); + } else { // Always open bot chats, even from mention links. crl::on_main(this, [=] { showPeerHistory(peer->id, params); }); - } else { - showPeerInfo(peer, params); } } else { const auto user = peer->asUser(); diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index f22f34033..f610eae85 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/observer.h" #include "base/weak_ptr.h" #include "base/timer.h" +#include "data/data_chat_participant_status.h" #include "dialogs/dialogs_key.h" #include "ui/layers/layer_widget.h" #include "ui/layers/show.h" @@ -86,6 +87,14 @@ enum class GifPauseReason { using GifPauseReasons = base::flags; inline constexpr bool is_flag_type(GifPauseReason) { return true; }; +enum class BotStartType { + None, + Personal, + Group, + Channel, + ShareGame, +}; + struct PeerThemeOverride { PeerData *peer = nullptr; std::shared_ptr theme; @@ -178,7 +187,9 @@ public: QString phone; MsgId messageId = ShowAtUnreadMsgId; RepliesByLinkInfo repliesInfo; + BotStartType startType = BotStartType::None; QString startToken; + ChatAdminRights startAdminRights; std::optional voicechatHash; FullMsgId clickFromMessageId; };