Suggest inviting by link if privacy disallows adding.
This commit is contained in:
parent
7682ccf6a7
commit
f3e15c7fcd
|
@ -1110,6 +1110,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_profile_copy_phone" = "Copy Phone Number";
|
"lng_profile_copy_phone" = "Copy Phone Number";
|
||||||
"lng_profile_copy_fullname" = "Copy Name";
|
"lng_profile_copy_fullname" = "Copy Name";
|
||||||
|
|
||||||
|
"lng_via_link_group_one" = "**{user}** restricts adding them to groups.\nYou can send them an invite link as message instead.";
|
||||||
|
"lng_via_link_group_many#one" = "**{count} user** restricts adding them to groups.\nYou can send them an invite link as message instead.";
|
||||||
|
"lng_via_link_group_many#other" = "**{count} users** restrict adding them to groups.\nYou can send them an invite link as message instead.";
|
||||||
|
"lng_via_link_channel_one" = "**{user}** restricts adding them to channels.\nYou can send them an invite link as message instead.";
|
||||||
|
"lng_via_link_channel_many#one" = "**{count} user** restricts adding them to channels.\nYou can send them an invite link as message instead.";
|
||||||
|
"lng_via_link_channel_many#other" = "**{count} users** restrict adding them to channels.\nYou can send them an invite link as message instead.";
|
||||||
|
"lng_via_link_send" = "Send Invite Link";
|
||||||
|
"lng_via_link_cant" = "You can't create a link";
|
||||||
|
"lng_via_link_cant_one" = "**{user}** can only by invited via link, but you don't have permission to share invite links to this group.";
|
||||||
|
"lng_via_link_cant_many#one" = "**{count} user** can only by invited via link, but you don't have permission to share invite links to this group.";
|
||||||
|
"lng_via_link_cant_many#other" = "**{count} users** can only by invited via link, but you don't have permission to share invite links to this group.";
|
||||||
|
"lng_via_link_shared_one" = "Link shared with **{user}**.";
|
||||||
|
"lng_via_link_shared_many#one" = "Link shared with **{count} user**.";
|
||||||
|
"lng_via_link_shared_many#other" = "Link shared with **{count} users**.";
|
||||||
|
|
||||||
"lng_info_mobile_label" = "Mobile";
|
"lng_info_mobile_label" = "Mobile";
|
||||||
"lng_info_mobile_context_menu_fragment_about" = "This number is not tied to a SIM card and was acquired on {link}.";
|
"lng_info_mobile_context_menu_fragment_about" = "This number is not tied to a SIM card and was acquired on {link}.";
|
||||||
"lng_info_mobile_context_menu_fragment_about_link" = "Fragment";
|
"lng_info_mobile_context_menu_fragment_about_link" = "Fragment";
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "boxes/add_contact_box.h" // ShowAddParticipantsError
|
#include "boxes/add_contact_box.h" // ShowAddParticipantsError
|
||||||
|
#include "boxes/peers/add_participants_box.h" // ChatInviteForbidden
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_channel_admins.h"
|
#include "data/data_channel_admins.h"
|
||||||
|
@ -463,6 +464,7 @@ void ChatParticipants::requestCountDelayed(
|
||||||
void ChatParticipants::add(
|
void ChatParticipants::add(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const std::vector<not_null<UserData*>> &users,
|
const std::vector<not_null<UserData*>> &users,
|
||||||
|
std::shared_ptr<Ui::Show> show,
|
||||||
bool passGroupHistory,
|
bool passGroupHistory,
|
||||||
Fn<void(bool)> done) {
|
Fn<void(bool)> done) {
|
||||||
if (const auto chat = peer->asChat()) {
|
if (const auto chat = peer->asChat()) {
|
||||||
|
@ -475,14 +477,15 @@ void ChatParticipants::add(
|
||||||
chat->session().api().applyUpdates(result);
|
chat->session().api().applyUpdates(result);
|
||||||
if (done) done(true);
|
if (done) done(true);
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
ShowAddParticipantsError(error.type(), peer, { 1, user });
|
const auto type = error.type();
|
||||||
|
ShowAddParticipantsError(type, peer, { 1, user }, show);
|
||||||
if (done) done(false);
|
if (done) done(false);
|
||||||
}).afterDelay(kSmallDelayMs).send();
|
}).afterDelay(kSmallDelayMs).send();
|
||||||
}
|
}
|
||||||
} else if (const auto channel = peer->asChannel()) {
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
const auto hasBot = ranges::any_of(users, &UserData::isBot);
|
const auto hasBot = ranges::any_of(users, &UserData::isBot);
|
||||||
if (!peer->isMegagroup() && hasBot) {
|
if (!peer->isMegagroup() && hasBot) {
|
||||||
ShowAddParticipantsError("USER_BOT", peer, users);
|
ShowAddParticipantsError("USER_BOT", peer, users, show);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto list = QVector<MTPInputUser>();
|
auto list = QVector<MTPInputUser>();
|
||||||
|
@ -496,8 +499,12 @@ void ChatParticipants::add(
|
||||||
channel->session().api().applyUpdates(result);
|
channel->session().api().applyUpdates(result);
|
||||||
requestCountDelayed(channel);
|
requestCountDelayed(channel);
|
||||||
if (callback) callback(true);
|
if (callback) callback(true);
|
||||||
|
ChatInviteForbidden(
|
||||||
|
show,
|
||||||
|
channel,
|
||||||
|
CollectForbiddenUsers(&channel->session(), result));
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
ShowAddParticipantsError(error.type(), peer, users);
|
ShowAddParticipantsError(error.type(), peer, users, show);
|
||||||
if (callback) callback(false);
|
if (callback) callback(false);
|
||||||
}).afterDelay(kSmallDelayMs).send();
|
}).afterDelay(kSmallDelayMs).send();
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
class ApiWrap;
|
class ApiWrap;
|
||||||
class ChannelData;
|
class ChannelData;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class Show;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
|
|
||||||
class ChatParticipant final {
|
class ChatParticipant final {
|
||||||
|
@ -95,6 +99,7 @@ public:
|
||||||
void add(
|
void add(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const std::vector<not_null<UserData*>> &users,
|
const std::vector<not_null<UserData*>> &users,
|
||||||
|
std::shared_ptr<Ui::Show> show = nullptr,
|
||||||
bool passGroupHistory = true,
|
bool passGroupHistory = true,
|
||||||
Fn<void(bool)> done = nullptr);
|
Fn<void(bool)> done = nullptr);
|
||||||
|
|
||||||
|
|
|
@ -3709,7 +3709,8 @@ void ApiWrap::sendBotStart(
|
||||||
applyUpdates(result);
|
applyUpdates(result);
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
if (chat) {
|
if (chat) {
|
||||||
ShowAddParticipantsError(error.type(), chat, { 1, bot });
|
const auto type = error.type();
|
||||||
|
ShowAddParticipantsError(type, chat, { 1, bot });
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,12 @@ void ChatCreateDone(
|
||||||
if (done) {
|
if (done) {
|
||||||
done(chat);
|
done(chat);
|
||||||
} else {
|
} else {
|
||||||
|
const auto show = std::make_shared<Window::Show>(navigation);
|
||||||
navigation->showPeerHistory(chat);
|
navigation->showPeerHistory(chat);
|
||||||
|
ChatInviteForbidden(
|
||||||
|
show,
|
||||||
|
chat,
|
||||||
|
CollectForbiddenUsers(&chat->session(), updates));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -173,7 +178,8 @@ TextWithEntities PeerFloodErrorText(
|
||||||
void ShowAddParticipantsError(
|
void ShowAddParticipantsError(
|
||||||
const QString &error,
|
const QString &error,
|
||||||
not_null<PeerData*> chat,
|
not_null<PeerData*> chat,
|
||||||
const std::vector<not_null<UserData*>> &users) {
|
const std::vector<not_null<UserData*>> &users,
|
||||||
|
std::shared_ptr<Ui::Show> show) {
|
||||||
if (error == u"USER_BOT"_q) {
|
if (error == u"USER_BOT"_q) {
|
||||||
const auto channel = chat->asChannel();
|
const auto channel = chat->asChannel();
|
||||||
if ((users.size() == 1)
|
if ((users.size() == 1)
|
||||||
|
@ -220,6 +226,9 @@ void ShowAddParticipantsError(
|
||||||
const auto text = PeerFloodErrorText(&chat->session(), type);
|
const auto text = PeerFloodErrorText(&chat->session(), type);
|
||||||
Ui::show(Ui::MakeInformBox(text), Ui::LayerOption::KeepOther);
|
Ui::show(Ui::MakeInformBox(text), Ui::LayerOption::KeepOther);
|
||||||
return;
|
return;
|
||||||
|
} else if (error == u"USER_PRIVACY_RESTRICTED"_q && show) {
|
||||||
|
ChatInviteForbidden(show, chat, users);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const auto text = [&] {
|
const auto text = [&] {
|
||||||
if (error == u"USER_BOT"_q) {
|
if (error == u"USER_BOT"_q) {
|
||||||
|
@ -689,9 +698,6 @@ void GroupInfoBox::createGroup(
|
||||||
inputs.push_back(user->inputUser);
|
inputs.push_back(user->inputUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inputs.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_creationRequestId = _api.request(MTPmessages_CreateChat(
|
_creationRequestId = _api.request(MTPmessages_CreateChat(
|
||||||
MTP_flags(_ttlPeriod
|
MTP_flags(_ttlPeriod
|
||||||
? MTPmessages_CreateChat::Flag::f_ttl_period
|
? MTPmessages_CreateChat::Flag::f_ttl_period
|
||||||
|
@ -703,6 +709,7 @@ void GroupInfoBox::createGroup(
|
||||||
auto image = _photo->takeResultImage();
|
auto image = _photo->takeResultImage();
|
||||||
const auto period = _ttlPeriod;
|
const auto period = _ttlPeriod;
|
||||||
const auto navigation = _navigation;
|
const auto navigation = _navigation;
|
||||||
|
const auto controller = navigation->parentController();
|
||||||
const auto done = _done;
|
const auto done = _done;
|
||||||
|
|
||||||
getDelegate()->hideLayer(); // Destroys 'this'.
|
getDelegate()->hideLayer(); // Destroys 'this'.
|
||||||
|
@ -763,13 +770,10 @@ void GroupInfoBox::submit() {
|
||||||
not_null<PeerListBox*> box) {
|
not_null<PeerListBox*> box) {
|
||||||
auto create = [box, title, weak] {
|
auto create = [box, title, weak] {
|
||||||
if (const auto strong = weak.data()) {
|
if (const auto strong = weak.data()) {
|
||||||
auto rows = box->collectSelectedRows();
|
strong->createGroup(
|
||||||
if (!rows.empty()) {
|
box.get(),
|
||||||
strong->createGroup(
|
title,
|
||||||
box.get(),
|
box->collectSelectedRows());
|
||||||
title,
|
|
||||||
std::move(rows));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
box->addButton(tr::lng_create_group_create(), std::move(create));
|
box->addButton(tr::lng_create_group_create(), std::move(create));
|
||||||
|
|
|
@ -48,7 +48,8 @@ enum class PeerFloodType {
|
||||||
void ShowAddParticipantsError(
|
void ShowAddParticipantsError(
|
||||||
const QString &error,
|
const QString &error,
|
||||||
not_null<PeerData*> chat,
|
not_null<PeerData*> chat,
|
||||||
const std::vector<not_null<UserData*>> &users);
|
const std::vector<not_null<UserData*>> &users,
|
||||||
|
std::shared_ptr<Ui::Show> show = nullptr);
|
||||||
|
|
||||||
class AddContactBox : public Ui::BoxContent {
|
class AddContactBox : public Ui::BoxContent {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/peers/add_participants_box.h"
|
#include "boxes/peers/add_participants_box.h"
|
||||||
|
|
||||||
#include "api/api_chat_participants.h"
|
#include "api/api_chat_participants.h"
|
||||||
|
#include "api/api_invite_links.h"
|
||||||
#include "boxes/peers/edit_participant_box.h"
|
#include "boxes/peers/edit_participant_box.h"
|
||||||
#include "boxes/peers/edit_peer_type_box.h"
|
#include "boxes/peers/edit_peer_type_box.h"
|
||||||
#include "ui/boxes/confirm_box.h"
|
#include "ui/boxes/confirm_box.h"
|
||||||
|
@ -22,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "dialogs/dialogs_indexed_list.h"
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
#include "ui/text/text_utilities.h" // Ui::Text::RichLangValue
|
#include "ui/text/text_utilities.h" // Ui::Text::RichLangValue
|
||||||
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/wrap/padding_wrap.h"
|
#include "ui/wrap/padding_wrap.h"
|
||||||
|
@ -33,12 +35,48 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
|
#include "styles/style_settings.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kParticipantsFirstPageCount = 16;
|
constexpr auto kParticipantsFirstPageCount = 16;
|
||||||
constexpr auto kParticipantsPerPage = 200;
|
constexpr auto kParticipantsPerPage = 200;
|
||||||
|
|
||||||
|
class InviteForbiddenController final : public PeerListController {
|
||||||
|
public:
|
||||||
|
InviteForbiddenController(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
std::vector<not_null<UserData*>> users);
|
||||||
|
|
||||||
|
Main::Session &session() const override;
|
||||||
|
void prepare() override;
|
||||||
|
void rowClicked(not_null<PeerListRow*> row) override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool canInvite() const {
|
||||||
|
return _can;
|
||||||
|
}
|
||||||
|
[[nodiscard]] rpl::producer<int> selectedValue() const {
|
||||||
|
return _selected.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(
|
||||||
|
std::vector<not_null<PeerData*>> list,
|
||||||
|
Ui::ShowPtr show,
|
||||||
|
Fn<void()> close);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void appendRow(not_null<UserData*> user);
|
||||||
|
[[nodiscard]] std::unique_ptr<PeerListRow> createRow(
|
||||||
|
not_null<UserData*> user) const;
|
||||||
|
|
||||||
|
const not_null<PeerData*> _peer;
|
||||||
|
const std::vector<not_null<UserData*>> _users;
|
||||||
|
const bool _can = false;
|
||||||
|
rpl::variable<int> _selected;
|
||||||
|
bool _sending = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
base::flat_set<not_null<UserData*>> GetAlreadyInFromPeer(PeerData *peer) {
|
base::flat_set<not_null<UserData*>> GetAlreadyInFromPeer(PeerData *peer) {
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
return {};
|
return {};
|
||||||
|
@ -54,6 +92,148 @@ base::flat_set<not_null<UserData*>> GetAlreadyInFromPeer(PeerData *peer) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InviteForbiddenController::InviteForbiddenController(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
std::vector<not_null<UserData*>> users)
|
||||||
|
: _peer(peer)
|
||||||
|
, _users(std::move(users))
|
||||||
|
, _can(peer->isChat()
|
||||||
|
? peer->asChat()->canHaveInviteLink()
|
||||||
|
: peer->asChannel()->canHaveInviteLink())
|
||||||
|
, _selected(_can ? int(_users.size()) : 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Main::Session &InviteForbiddenController::session() const {
|
||||||
|
return _peer->session();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InviteForbiddenController::prepare() {
|
||||||
|
const auto broadcast = _peer->isBroadcast();
|
||||||
|
const auto count = int(_users.size());
|
||||||
|
const auto phraseCounted = !_can
|
||||||
|
? tr::lng_via_link_cant_many
|
||||||
|
: broadcast
|
||||||
|
? tr::lng_via_link_channel_many
|
||||||
|
: tr::lng_via_link_group_many;
|
||||||
|
const auto phraseNamed = !_can
|
||||||
|
? tr::lng_via_link_cant_one
|
||||||
|
: broadcast
|
||||||
|
? tr::lng_via_link_channel_one
|
||||||
|
: tr::lng_via_link_group_one;
|
||||||
|
auto text = (count != 1)
|
||||||
|
? phraseCounted(
|
||||||
|
lt_count,
|
||||||
|
rpl::single<float64>(count),
|
||||||
|
Ui::Text::RichLangValue)
|
||||||
|
: phraseNamed(
|
||||||
|
lt_user,
|
||||||
|
rpl::single(TextWithEntities{ _users.front()->name() }),
|
||||||
|
Ui::Text::RichLangValue);
|
||||||
|
delegate()->peerListSetAboveWidget(object_ptr<Ui::PaddingWrap<>>(
|
||||||
|
(QWidget*)nullptr,
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
(QWidget*)nullptr,
|
||||||
|
std::move(text),
|
||||||
|
st::requestPeerRestriction),
|
||||||
|
st::boxRowPadding));
|
||||||
|
delegate()->peerListSetTitle(
|
||||||
|
_can ? tr::lng_profile_add_via_link() : tr::lng_via_link_cant());
|
||||||
|
|
||||||
|
for (const auto &user : _users) {
|
||||||
|
appendRow(user);
|
||||||
|
}
|
||||||
|
delegate()->peerListRefreshRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InviteForbiddenController::rowClicked(not_null<PeerListRow*> row) {
|
||||||
|
if (!_can) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto checked = row->checked();
|
||||||
|
delegate()->peerListSetRowChecked(row, !checked);
|
||||||
|
_selected = _selected.current() + (checked ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InviteForbiddenController::appendRow(not_null<UserData*> user) {
|
||||||
|
if (!delegate()->peerListFindRow(user->id.value)) {
|
||||||
|
auto row = createRow(user);
|
||||||
|
const auto raw = row.get();
|
||||||
|
delegate()->peerListAppendRow(std::move(row));
|
||||||
|
if (_can) {
|
||||||
|
delegate()->peerListSetRowChecked(raw, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InviteForbiddenController::send(
|
||||||
|
std::vector<not_null<PeerData*>> list,
|
||||||
|
Ui::ShowPtr show,
|
||||||
|
Fn<void()> close) {
|
||||||
|
if (_sending || list.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_sending = true;
|
||||||
|
const auto chat = _peer->asChat();
|
||||||
|
const auto channel = _peer->asChannel();
|
||||||
|
const auto sendLink = [=] {
|
||||||
|
const auto link = chat ? chat->inviteLink() : channel->inviteLink();
|
||||||
|
if (link.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto &api = _peer->session().api();
|
||||||
|
auto options = Api::SendOptions();
|
||||||
|
for (const auto &to : list) {
|
||||||
|
const auto history = to->owner().history(to);
|
||||||
|
auto message = Api::MessageToSend(
|
||||||
|
Api::SendAction(history, options));
|
||||||
|
message.textWithTags = { link };
|
||||||
|
message.action.clearDraft = false;
|
||||||
|
api.sendMessage(std::move(message));
|
||||||
|
}
|
||||||
|
auto text = (list.size() == 1)
|
||||||
|
? tr::lng_via_link_shared_one(
|
||||||
|
tr::now,
|
||||||
|
lt_user,
|
||||||
|
TextWithEntities{ list.front()->name() },
|
||||||
|
Ui::Text::RichLangValue)
|
||||||
|
: tr::lng_via_link_shared_many(
|
||||||
|
tr::now,
|
||||||
|
lt_count,
|
||||||
|
int(list.size()),
|
||||||
|
Ui::Text::RichLangValue);
|
||||||
|
close();
|
||||||
|
Ui::Toast::Show(
|
||||||
|
show->toastParent(),
|
||||||
|
{ .text = std::move(text), .st = &st::defaultToast });
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
const auto sendForFull = [=] {
|
||||||
|
if (!sendLink()) {
|
||||||
|
_peer->session().api().inviteLinks().create(_peer, [=](auto) {
|
||||||
|
if (!sendLink()) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (_peer->isFullLoaded()) {
|
||||||
|
sendForFull();
|
||||||
|
} else if (!sendLink()) {
|
||||||
|
_peer->session().api().requestFullPeer(_peer);
|
||||||
|
_peer->session().changes().peerUpdates(
|
||||||
|
_peer,
|
||||||
|
Data::PeerUpdate::Flag::FullInfo
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
sendForFull();
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<PeerListRow> InviteForbiddenController::createRow(
|
||||||
|
not_null<UserData*> user) const {
|
||||||
|
return std::make_unique<PeerListRow>(user);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AddParticipantsBoxController::AddParticipantsBoxController(
|
AddParticipantsBoxController::AddParticipantsBoxController(
|
||||||
|
@ -245,14 +425,19 @@ void AddParticipantsBoxController::inviteSelectedUsers(
|
||||||
if (users.empty()) {
|
if (users.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto show = std::make_shared<Ui::BoxShow>(box);
|
||||||
const auto request = [=](bool checked) {
|
const auto request = [=](bool checked) {
|
||||||
_peer->session().api().chatParticipants().add(_peer, users, checked);
|
_peer->session().api().chatParticipants().add(
|
||||||
|
_peer,
|
||||||
|
users,
|
||||||
|
show,
|
||||||
|
checked);
|
||||||
};
|
};
|
||||||
if (_peer->isChannel()) {
|
if (_peer->isChannel()) {
|
||||||
request(false);
|
request(false);
|
||||||
return done();
|
return done();
|
||||||
}
|
}
|
||||||
Ui::BoxShow(box).showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||||
auto checkbox = object_ptr<Ui::Checkbox>(
|
auto checkbox = object_ptr<Ui::Checkbox>(
|
||||||
box.get(),
|
box.get(),
|
||||||
tr::lng_participant_invite_history(),
|
tr::lng_participant_invite_history(),
|
||||||
|
@ -371,6 +556,81 @@ void AddParticipantsBoxController::Start(
|
||||||
Start(navigation, channel, {}, true);
|
Start(navigation, channel, {}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<not_null<UserData*>> CollectForbiddenUsers(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const MTPUpdates &updates) {
|
||||||
|
const auto owner = &session->data();
|
||||||
|
auto result = std::vector<not_null<UserData*>>();
|
||||||
|
const auto add = [&](const MTPUpdate &update) {
|
||||||
|
if (update.type() == mtpc_updateGroupInvitePrivacyForbidden) {
|
||||||
|
const auto user = owner->userLoaded(UserId(
|
||||||
|
update.c_updateGroupInvitePrivacyForbidden().vuser_id()));
|
||||||
|
if (user) {
|
||||||
|
result.push_back(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto collect = [&](const MTPVector<MTPUpdate> &updates) {
|
||||||
|
for (const auto &update : updates.v) {
|
||||||
|
add(update);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updates.match([&](const MTPDupdates &data) {
|
||||||
|
collect(data.vupdates());
|
||||||
|
}, [&](const MTPDupdatesCombined &data) {
|
||||||
|
collect(data.vupdates());
|
||||||
|
}, [&](const MTPDupdateShort &data) {
|
||||||
|
add(data.vupdate());
|
||||||
|
}, [](const auto &other) {
|
||||||
|
LOG(("Api Error: CollectForbiddenUsers for wrong updates type."));
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatInviteForbidden(
|
||||||
|
std::shared_ptr<Ui::Show> show,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
std::vector<not_null<UserData*>> forbidden) {
|
||||||
|
if (forbidden.empty() || !show || !show->valid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto controller = std::make_unique<InviteForbiddenController>(
|
||||||
|
peer,
|
||||||
|
std::move(forbidden));
|
||||||
|
const auto weak = controller.get();
|
||||||
|
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||||
|
const auto can = weak->canInvite();
|
||||||
|
if (!can) {
|
||||||
|
box->addButton(tr::lng_close(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
weak->selectedValue(
|
||||||
|
) | rpl::map(
|
||||||
|
rpl::mappers::_1 > 0
|
||||||
|
) | rpl::distinct_until_changed(
|
||||||
|
) | rpl::start_with_next([=](bool has) {
|
||||||
|
box->clearButtons();
|
||||||
|
if (has) {
|
||||||
|
box->addButton(tr::lng_via_link_send(), [=] {
|
||||||
|
weak->send(
|
||||||
|
box->collectSelectedRows(),
|
||||||
|
std::make_shared<Ui::BoxShow>(box),
|
||||||
|
crl::guard(box, [=] { box->closeBox(); }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
box->addButton(tr::lng_create_group_skip(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
});
|
||||||
|
}, box->lifetime());
|
||||||
|
};
|
||||||
|
show->showBox(
|
||||||
|
Box<PeerListBox>(std::move(controller), std::move(initBox)),
|
||||||
|
Ui::LayerOption::KeepOther);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
AddSpecialBoxController::AddSpecialBoxController(
|
AddSpecialBoxController::AddSpecialBoxController(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
Role role,
|
Role role,
|
||||||
|
|
|
@ -73,6 +73,14 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<not_null<UserData*>> CollectForbiddenUsers(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const MTPUpdates &updates);
|
||||||
|
bool ChatInviteForbidden(
|
||||||
|
std::shared_ptr<Ui::Show> show,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
std::vector<not_null<UserData*>> forbidden);
|
||||||
|
|
||||||
// Adding an admin, banned or restricted user from channel members
|
// Adding an admin, banned or restricted user from channel members
|
||||||
// with search + contacts search + global search.
|
// with search + contacts search + global search.
|
||||||
class AddSpecialBoxController
|
class AddSpecialBoxController
|
||||||
|
|
|
@ -219,12 +219,14 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto inviteWithAdd = [=](
|
const auto inviteWithAdd = [=](
|
||||||
|
std::shared_ptr<Ui::Show> show,
|
||||||
const std::vector<not_null<UserData*>> &users,
|
const std::vector<not_null<UserData*>> &users,
|
||||||
const std::vector<not_null<UserData*>> &nonMembers,
|
const std::vector<not_null<UserData*>> &nonMembers,
|
||||||
Fn<void()> finish) {
|
Fn<void()> finish) {
|
||||||
peer->session().api().chatParticipants().add(
|
peer->session().api().chatParticipants().add(
|
||||||
peer,
|
peer,
|
||||||
nonMembers,
|
nonMembers,
|
||||||
|
show,
|
||||||
true,
|
true,
|
||||||
[=](bool) { invite(users); finish(); });
|
[=](bool) { invite(users); finish(); });
|
||||||
};
|
};
|
||||||
|
@ -257,7 +259,10 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
finish();
|
finish();
|
||||||
};
|
};
|
||||||
const auto done = [=] {
|
const auto done = [=] {
|
||||||
inviteWithAdd(users, nonMembers, finishWithConfirm);
|
const auto show = (*shared)
|
||||||
|
? std::make_shared<Ui::BoxShow>(*shared)
|
||||||
|
: nullptr;
|
||||||
|
inviteWithAdd(show, users, nonMembers, finishWithConfirm);
|
||||||
};
|
};
|
||||||
auto box = ConfirmBox({
|
auto box = ConfirmBox({
|
||||||
.text = text,
|
.text = text,
|
||||||
|
|
|
@ -360,7 +360,9 @@ void MainWindow::ensureLayerCreated() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_layer = base::make_unique_q<Ui::LayerStackWidget>(
|
_layer = base::make_unique_q<Ui::LayerStackWidget>(
|
||||||
bodyWidget());
|
bodyWidget(),
|
||||||
|
crl::guard(this, [=] {
|
||||||
|
return std::make_shared<Window::Show>(&controller()); }));
|
||||||
|
|
||||||
_layer->hideFinishEvents(
|
_layer->hideFinishEvents(
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit f3744c4ba3ddadd47e280a1ef5fbd002d357d10a
|
Subproject commit 849a84050356a1321eedc36eb5296374e42fadd6
|
Loading…
Reference in New Issue