diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 9b9e9e170..35a9597b7 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -914,6 +914,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_profile_block_bot" = "Stop and block bot"; "lng_profile_restart_bot" = "Restart bot"; "lng_profile_invite_to_group" = "Add to Group"; +"lng_profile_add_bot_as_admin" = "Add to Group or Channel"; +"lng_profile_invite_to_channel" = "Add to Channel"; +"lng_profile_invite_to_group_about" = "This bot is able to manage a group."; +"lng_profile_invite_to_channel_about" = "This bot is able to manage a channel."; +"lng_profile_add_bot_as_admin_about" = "This bot is able to manage a group or channel."; "lng_profile_delete_contact" = "Delete"; "lng_profile_set_group_photo" = "Set Photo"; "lng_profile_add_participant" = "Add Members"; @@ -1705,6 +1710,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "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_bot_groups_manage" = "Groups I manage"; +"lng_bot_channels_manage" = "Channels I manage"; +"lng_bot_groups" = "Groups"; +"lng_bot_add_title" = "Add Bot"; +"lng_bot_add_as_admin" = "Add Bot as Admin"; +"lng_bot_add_as_member" = "Add Bot as Member"; +"lng_bot_sure_add_title" = "Add bot as admin"; +"lng_bot_sure_add_text_group" = "Are you sure you want to add this bot as an admin in the group {group}?"; +"lng_bot_sure_add_text_channel" = "Are you sure you want to add this bot as an admin in the channel {group}?"; +"lng_bot_sure_add" = "Add as admin"; "lng_typing" = "typing"; "lng_user_typing" = "{user} is typing"; diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 4980b0455..ba3082025 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -25,6 +25,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwindow.h" #include "lang/lang_keys.h" #include "history/history.h" +#include "boxes/peers/edit_participant_box.h" +#include "boxes/peers/edit_participants_box.h" #include "dialogs/dialogs_main_list.h" #include "window/window_session_controller.h" // showAddContact() #include "base/unixtime.h" @@ -580,12 +582,42 @@ void AddBotToGroupBoxController::addBotToGroup(not_null chat) { return; } } - auto send = crl::guard(this, [bot = _bot, chat] { - AddBotToGroup(bot, chat); - }); - auto confirmText = tr::lng_bot_sure_invite(tr::now, lt_group, chat->name); + const auto bot = _bot; + const auto close = [=](auto&&...) { + Ui::hideLayer(); + Ui::showPeerHistory(chat, ShowAtUnreadMsgId); + }; + const auto saveCallback = SaveAdminCallback( + chat, + bot, + close, + close); + auto box = object_ptr(nullptr); + if (chat->isBroadcast()) { + if (bot->botInfo->channelAdminRights) { + box = Box( + chat, + bot, + ChatAdminRightsInfo(bot->botInfo->channelAdminRights), + QString()); + } + } else if (bot->botInfo->groupAdminRights) { + box = Box( + chat, + bot, + ChatAdminRightsInfo(bot->botInfo->groupAdminRights), + QString()); + } + if (box) { + box->setSaveCallback(saveCallback); + Ui::show(std::move(box)); + return; + } Ui::show( - Ui::MakeConfirmBox({ confirmText, send }), + Ui::MakeConfirmBox({ + tr::lng_bot_sure_invite(tr::now, lt_group, chat->name), + crl::guard(this, [=] { AddBotToGroup(bot, chat); }), + }), Ui::LayerOption::KeepOther); } diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 68b79056c..56696c471 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -239,6 +239,25 @@ void ApplyUserUpdate(not_null user, const MTPDuserFull &update) { user->setCommonChatsCount(update.vcommon_chats_count().v); user->checkFolder(update.vfolder_id().value_or_empty()); user->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty())); + + if (const auto info = user->botInfo.get()) { + const auto group = update.vbot_group_admin_rights() + ? ChatAdminRightsInfo(*update.vbot_group_admin_rights()).flags + : ChatAdminRights(); + const auto channel = update.vbot_broadcast_admin_rights() + ? ChatAdminRightsInfo( + *update.vbot_broadcast_admin_rights()).flags + : ChatAdminRights(); + if (info->groupAdminRights != group + || info->channelAdminRights != channel) { + info->groupAdminRights = group; + info->channelAdminRights = channel; + user->session().changes().peerUpdated( + user, + Data::PeerUpdate::Flag::Rights); + } + } + user->fullUpdated(); } diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index b7e3c6bd9..cfb1348b3 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "data/data_peer.h" +#include "data/data_chat_participant_status.h" #include "dialogs/dialogs_key.h" struct BotInfo { @@ -21,6 +22,9 @@ struct BotInfo { QString startToken, startGroupToken, shareGameShortName; Dialogs::EntryState inlineReturnTo; + + ChatAdminRights groupAdminRights; + ChatAdminRights channelAdminRights; }; enum class UserDataFlag { diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index 6a1af9fa8..f46731e2f 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "core/application.h" #include "core/click_handler_types.h" +#include "settings/settings_common.h" #include "apiwrap.h" #include "api/api_blocked_peers.h" #include "facades.h" @@ -507,12 +508,26 @@ ActionsFiller::ActionsFiller( void ActionsFiller::addInviteToGroupAction( not_null user) { + const auto notEmpty = [](const QString &value) { + return !value.isEmpty(); + }; AddActionButton( _wrap, - tr::lng_profile_invite_to_group(), - CanInviteBotToGroupValue(user), + InviteToChatButton(user) | rpl::filter(notEmpty), + InviteToChatButton(user) | rpl::map(notEmpty), [=] { AddBotToGroupBoxController::Start(user); }, &st::infoIconRequests); + const auto about = _wrap->add( + object_ptr>( + _wrap.data(), + object_ptr(_wrap.data()))); + about->toggleOn(InviteToChatAbout(user) | rpl::map(notEmpty)); + ::Settings::AddSkip(about->entity()); + ::Settings::AddDividerText( + about->entity(), + InviteToChatAbout(user) | rpl::filter(notEmpty)); + ::Settings::AddSkip(about->entity()); + about->finishAnimating(); } void ActionsFiller::addShareContactAction(not_null user) { diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index 0e2048891..1a431f6bc 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -186,15 +186,45 @@ rpl::producer IsContactValue(not_null user) { }); } -rpl::producer CanInviteBotToGroupValue(not_null user) { - if (!user->isBot() || user->isSupport()) { - return rpl::single(false); +[[nodiscard]] rpl::producer InviteToChatButton( + not_null user) { + if (!user->isBot() || user->isRepliesChat() || user->isSupport()) { + return rpl::single(QString()); } + using Flag = Data::PeerUpdate::Flag; return user->session().changes().peerFlagsValue( user, - UpdateFlag::BotCanBeInvited + Flag::BotCanBeInvited | Flag::Rights ) | rpl::map([=] { - return !user->botInfo->cantJoinGroups; + const auto info = user->botInfo.get(); + return info->cantJoinGroups + ? (info->channelAdminRights + ? tr::lng_profile_invite_to_channel(tr::now) + : QString()) + : (info->channelAdminRights + ? tr::lng_profile_add_bot_as_admin(tr::now) + : tr::lng_profile_invite_to_group(tr::now)); + }); +} + +[[nodiscard]] rpl::producer InviteToChatAbout( + not_null user) { + if (!user->isBot() || user->isRepliesChat() || user->isSupport()) { + return rpl::single(QString()); + } + using Flag = Data::PeerUpdate::Flag; + return user->session().changes().peerFlagsValue( + user, + Flag::BotCanBeInvited | Flag::Rights + ) | rpl::map([=] { + const auto info = user->botInfo.get(); + return (info->cantJoinGroups || !info->groupAdminRights) + ? (info->channelAdminRights + ? tr::lng_profile_invite_to_channel_about(tr::now) + : QString()) + : (info->channelAdminRights + ? tr::lng_profile_add_bot_as_admin_about(tr::now) + : tr::lng_profile_invite_to_group_about(tr::now)); }); } diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h index 90791754d..07bc10fb4 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -57,7 +57,9 @@ rpl::producer> MigratedOrMeValue( [[nodiscard]] rpl::producer NotificationsEnabledValue( not_null peer); [[nodiscard]] rpl::producer IsContactValue(not_null user); -[[nodiscard]] rpl::producer CanInviteBotToGroupValue( +[[nodiscard]] rpl::producer InviteToChatButton( + not_null user); +[[nodiscard]] rpl::producer InviteToChatAbout( not_null user); [[nodiscard]] rpl::producer CanShareContactValue( not_null user); diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 958148396..c1ad24104 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -617,17 +617,19 @@ void Filler::addEditContact() { void Filler::addBotToGroup() { const auto user = _peer->asUser(); - if (!user - || !user->isBot() - || user->isRepliesChat() - || user->botInfo->cantJoinGroups) { + if (!user) { return; } - using AddBotToGroup = AddBotToGroupBoxController; - _addAction( - tr::lng_profile_invite_to_group(tr::now), - [=] { AddBotToGroup::Start(user); }, - &st::menuIconInvite); + [[maybe_unused]] const auto lifetime = Info::Profile::InviteToChatButton( + user + ) | rpl::take(1) | rpl::start_with_next([=](QString label) { + if (!label.isEmpty()) { + _addAction( + label, + [=] { AddBotToGroupBoxController::Start(user); }, + &st::menuIconInvite); + } + }); } void Filler::addNewMembers() {