Allow creating approve-only invite links.

This commit is contained in:
John Preston 2021-10-12 12:39:07 +04:00
parent e471d61d7a
commit 3af3f85f82
20 changed files with 259 additions and 52 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -978,6 +978,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_removed_users" = "Removed users";
"lng_manage_peer_permissions" = "Permissions";
"lng_manage_peer_invite_links" = "Invite links";
"lng_manage_peer_requests" = "Member Requests";
"lng_manage_peer_requests_channel" = "Subscriber Requests";
"lng_manage_peer_group_type" = "Group type";
"lng_manage_peer_channel_type" = "Channel type";
@ -1158,8 +1160,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_user_left" = "{from} left the group";
"lng_action_user_joined" = "{from} joined the group";
"lng_action_user_joined_by_link" = "{from} joined the group via invite link";
"lng_action_user_joined_by_request" = "{from} joined the group by request";
"lng_action_user_joined_by_request" = "{from} was accepted to the group";
"lng_action_you_joined_by_request" = "Your request to join the group was approved";
"lng_action_you_joined_by_request_channel" = "Your request to join the channel was approved";
"lng_action_user_registered" = "{from} just joined Telegram";
"lng_action_removed_photo" = "{from} removed group photo";
"lng_action_removed_photo_channel" = "Channel photo removed";
@ -1271,6 +1274,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_invite_joined#other" = "{count} joined";
"lng_group_invite_remaining#one" = "{count} remaining";
"lng_group_invite_remaining#other" = "{count} remaining";
"lng_group_invite_requested#one" = "{count} requested";
"lng_group_invite_requested#other" = "{count} requested";
"lng_group_invite_requested_full#one" = "{count} requested to join";
"lng_group_invite_requested_full#other" = "{count} requested to join";
"lng_group_invite_can_join#one" = "{count} can join";
"lng_group_invite_can_join#other" = "{count} can join";
"lng_group_invite_days_left#one" = "{count} day left";
@ -1322,6 +1329,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_invite_qr_title" = "Invite by QR Code";
"lng_group_invite_qr_about" = "Everyone on Telegram can scan this code to join your group.";
"lng_group_invite_qr_copied" = "QR Code copied to clipboard.";
"lng_group_invite_request_approve" = "Request admin approval";
"lng_group_invite_about_approve" = "New users will be able to join the group only after having been approved by the admins.";
"lng_group_invite_about_no_approve" = "New users will be able to join the group without being approved by the admins.";
"lng_group_invite_about_approve_channel" = "New users will be able to join the channel only after having been approved by the admins.";
"lng_group_invite_about_no_approve_channel" = "New users will be able to join the channel without being approved by the admins.";
"lng_group_request_to_join" = "Request to Join";
"lng_group_request_about" = "This group accepts new members only after they are approved by its admins.";
"lng_group_request_about_channel" = "This channel accepts new subscribers only after they are approved by its admins.";
"lng_group_request_sent" = "You will be added to the group once its admins approve your request.";
"lng_group_request_sent_channel" = "You will be added to the channel once its admins approve your request.";
"lng_group_requests_pending#one" = "{count} pending member request";
"lng_group_requests_pending#other" = "{count} pending member requests";
"lng_group_requests_pending_channel#one" = "{count} pending subscriber request";
"lng_group_requests_pending_channel#other" = "{count} pending subscriber requests";
"lng_group_requests_status" = "requested to join {date}";
"lng_group_requests_add" = "Add to Group";
"lng_group_requests_add_channel" = "Add to Channel";
"lng_group_requests_dismiss" = "Dismiss";
"lng_group_requests_was_added" = "{user} has been added to the group.";
"lng_group_requests_none" = "No member requests";
"lng_group_requests_none_channel" = "No subscriber requests";
"lng_channel_public_link_copied" = "Link copied to clipboard.";
"lng_context_about_private_link" = "This link will only work for members of this chat.";
@ -2497,6 +2526,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_edited_invite_link" = "edited invite link {link}";
"lng_admin_log_invite_link_expire_date" = "Expire date: {previous} -> {limit}";
"lng_admin_log_invite_link_usage_limit" = "Usage limit: {previous} -> {limit}";
"lng_admin_log_invite_link_request_needed" = "Now admin approval is required to join.";
"lng_admin_log_invite_link_request_not_needed" = "Now admin approval is not required to join.";
"lng_admin_log_restricted_forever" = "indefinitely";
"lng_admin_log_restricted_until" = "until {date}";
"lng_admin_log_banned_view_messages" = "Read messages";

View file

@ -70,8 +70,15 @@ void InviteLinks::create(
not_null<PeerData*> peer,
Fn<void(Link)> done,
TimeId expireDate,
int usageLimit) {
performCreate(peer, std::move(done), false, expireDate, usageLimit);
int usageLimit,
bool requestApproval) {
performCreate(
peer,
std::move(done),
false,
expireDate,
usageLimit,
requestApproval);
}
void InviteLinks::performCreate(
@ -79,7 +86,8 @@ void InviteLinks::performCreate(
Fn<void(Link)> done,
bool revokeLegacyPermanent,
TimeId expireDate,
int usageLimit) {
int usageLimit,
bool requestApproval) {
if (const auto i = _createCallbacks.find(peer)
; i != end(_createCallbacks)) {
if (done) {
@ -98,7 +106,8 @@ void InviteLinks::performCreate(
? Flag::f_legacy_revoke_permanent
: Flag(0))
| (expireDate ? Flag::f_expire_date : Flag(0))
| (usageLimit ? Flag::f_usage_limit : Flag(0))),
| (usageLimit ? Flag::f_usage_limit : Flag(0))
| (requestApproval ? Flag::f_request_needed : Flag(0))),
peer->input,
MTP_int(expireDate),
MTP_int(usageLimit)
@ -201,6 +210,7 @@ void InviteLinks::edit(
const QString &link,
TimeId expireDate,
int usageLimit,
bool requestApproval,
Fn<void(Link)> done) {
performEdit(
peer,
@ -209,7 +219,8 @@ void InviteLinks::edit(
std::move(done),
false,
expireDate,
usageLimit);
usageLimit,
requestApproval);
}
void InviteLinks::performEdit(
@ -219,7 +230,8 @@ void InviteLinks::performEdit(
Fn<void(Link)> done,
bool revoke,
TimeId expireDate,
int usageLimit) {
int usageLimit,
bool requestApproval) {
const auto key = LinkKey{ peer, link };
if (_deleteCallbacks.contains(key)) {
return;
@ -239,12 +251,13 @@ void InviteLinks::performEdit(
_api->request(MTPmessages_EditExportedChatInvite(
MTP_flags((revoke ? Flag::f_revoked : Flag(0))
| (!revoke ? Flag::f_expire_date : Flag(0))
| (!revoke ? Flag::f_usage_limit : Flag(0))),
| (!revoke ? Flag::f_usage_limit : Flag(0))
| (!revoke ? Flag::f_request_needed : Flag(0))),
peer->input,
MTP_string(link),
MTP_int(expireDate),
MTP_int(usageLimit),
MTPbool() // request_needed // #TODO requests
MTP_bool(requestApproval)
)).done([=](const MTPmessages_ExportedChatInvite &result) {
const auto callbacks = _editCallbacks.take(key);
const auto peer = key.peer;
@ -632,6 +645,7 @@ auto InviteLinks::parse(
.expireDate = data.vexpire_date().value_or_empty(),
.usageLimit = data.vusage_limit().value_or_empty(),
.usage = data.vusage().value_or_empty(),
.requestApproval = data.is_request_needed(),
.permanent = data.is_permanent(),
.revoked = data.is_revoked(),
};

View file

@ -19,6 +19,7 @@ struct InviteLink {
TimeId expireDate = 0;
int usageLimit = 0;
int usage = 0;
bool requestApproval = false;
bool permanent = false;
bool revoked = false;
};
@ -61,13 +62,15 @@ public:
not_null<PeerData*> peer,
Fn<void(Link)> done = nullptr,
TimeId expireDate = 0,
int usageLimit = 0);
int usageLimit = 0,
bool requestApproval = false);
void edit(
not_null<PeerData*> peer,
not_null<UserData*> admin,
const QString &link,
TimeId expireDate,
int usageLimit,
bool requestApproval,
Fn<void(Link)> done = nullptr);
void revoke(
not_null<PeerData*> peer,
@ -164,13 +167,15 @@ private:
Fn<void(Link)> done,
bool revoke,
TimeId expireDate = 0,
int usageLimit = 0);
int usageLimit = 0,
bool requestApproval = false);
void performCreate(
not_null<PeerData*> peer,
Fn<void(Link)> done,
bool revokeLegacyPermanent,
TimeId expireDate = 0,
int usageLimit = 0);
int usageLimit = 0,
bool requestApproval = false);
void requestJoinedFirstSlice(LinkKey key);
[[nodiscard]] std::optional<JoinedByLinkSlice> lookupJoinedFirstSlice(

View file

@ -1965,6 +1965,18 @@ void Updates::feedUpdate(const MTPUpdate &update) {
}
} break;
case mtpc_updatePendingJoinRequests: {
const auto &d = update.c_updatePendingJoinRequests();
if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer()))) {
const auto count = d.vrequests_pending().v;
if (const auto chat = peer->asChat()) {
chat->setPendingRequestsCount(count);
} else if (const auto channel = peer->asChannel()) {
channel->setPendingRequestsCount(count);
}
}
} break;
case mtpc_updateServiceNotification: {
const auto &d = update.c_updateServiceNotification();
const auto text = TextWithEntities {

View file

@ -297,6 +297,7 @@ private:
void fillSignaturesButton();
void fillHistoryVisibilityButton();
void fillManageSection();
void fillPendingRequestsButton();
void submitTitle();
void submitDescription();
@ -845,6 +846,8 @@ void Controller::fillHistoryVisibilityButton() {
void Controller::fillManageSection() {
Expects(_controls.buttonsLayout != nullptr);
using namespace rpl::mappers;
const auto chat = _peer->asChat();
const auto channel = _peer->asChannel();
const auto isChannel = (!chat);
@ -1042,6 +1045,9 @@ void Controller::fillManageSection() {
},
st::infoIconMembers);
}
fillPendingRequestsButton();
if (canViewKicked) {
AddButtonWithCount(
_controls.buttonsLayout,
@ -1089,6 +1095,42 @@ void Controller::fillManageSection() {
}
}
void Controller::fillPendingRequestsButton() {
auto pendingRequestsCount = Info::Profile::MigratedOrMeValue(
_peer
) | rpl::map(
Info::Profile::PendingRequestsCountValue
) | rpl::flatten_latest(
) | rpl::start_spawning(_controls.buttonsLayout->lifetime());
const auto wrap = _controls.buttonsLayout->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_controls.buttonsLayout,
object_ptr<Ui::VerticalLayout>(
_controls.buttonsLayout)));
AddButtonWithCount(
wrap->entity(),
(_isGroup
? tr::lng_manage_peer_requests()
: tr::lng_manage_peer_requests_channel()),
rpl::duplicate(pendingRequestsCount) | ToPositiveNumberString(),
[=] {
_navigation->parentController()->show(
Box( // #TODO requests
ManageInviteLinksBox,
_peer,
_peer->session().user(),
0,
0),
Ui::LayerOption::KeepOther);
},
st::infoIconRequests);
std::move(
pendingRequestsCount
) | rpl::start_with_next([=](int count) {
wrap->toggle(count > 0, anim::type::instant);
}, wrap->lifetime());
}
void Controller::submitTitle() {
Expects(_controls.title != nullptr);

View file

@ -943,7 +943,8 @@ void EditLink(
peer,
finish,
result.expireDate,
result.usageLimit);
result.usageLimit,
result.requestApproval);
} else {
peer->session().api().inviteLinks().edit(
peer,
@ -951,18 +952,22 @@ void EditLink(
result.link,
result.expireDate,
result.usageLimit,
result.requestApproval,
finish);
}
};
const auto isGroup = !peer->isBroadcast();
*box = Ui::show(
(creating
? Box(Ui::CreateInviteLinkBox, done)
? Box(Ui::CreateInviteLinkBox, isGroup, done)
: Box(
Ui::EditInviteLinkBox,
Fields{
.link = data.link,
.expireDate = data.expireDate,
.usageLimit = data.usageLimit
.usageLimit = data.usageLimit,
.requestApproval = data.requestApproval,
.isGroup = isGroup,
},
done)),
Ui::LayerOption::KeepOther);

View file

@ -50,51 +50,52 @@ struct NameUpdate {
};
struct PeerUpdate {
enum class Flag : uint32 {
enum class Flag : uint64 {
None = 0,
// Common flags
Name = (1U << 0),
Username = (1U << 1),
Photo = (1U << 2),
About = (1U << 3),
Notifications = (1U << 4),
Migration = (1U << 5),
UnavailableReason = (1U << 6),
ChatThemeEmoji = (1U << 7),
IsBlocked = (1U << 8),
MessagesTTL = (1U << 9),
Name = (1ULL << 0),
Username = (1ULL << 1),
Photo = (1ULL << 2),
About = (1ULL << 3),
Notifications = (1ULL << 4),
Migration = (1ULL << 5),
UnavailableReason = (1ULL << 6),
ChatThemeEmoji = (1ULL << 7),
IsBlocked = (1ULL << 8),
MessagesTTL = (1ULL << 9),
// For users
CanShareContact = (1U << 10),
IsContact = (1U << 11),
PhoneNumber = (1U << 12),
OnlineStatus = (1U << 13),
BotCommands = (1U << 14),
BotCanBeInvited = (1U << 15),
BotStartToken = (1U << 16),
CommonChats = (1U << 17),
HasCalls = (1U << 18),
SupportInfo = (1U << 19),
IsBot = (1U << 20),
CanShareContact = (1ULL << 10),
IsContact = (1ULL << 11),
PhoneNumber = (1ULL << 12),
OnlineStatus = (1ULL << 13),
BotCommands = (1ULL << 14),
BotCanBeInvited = (1ULL << 15),
BotStartToken = (1ULL << 16),
CommonChats = (1ULL << 17),
HasCalls = (1ULL << 18),
SupportInfo = (1ULL << 19),
IsBot = (1ULL << 20),
// For chats and channels
InviteLinks = (1U << 21),
Members = (1U << 22),
Admins = (1U << 23),
BannedUsers = (1U << 24),
Rights = (1U << 25),
InviteLinks = (1ULL << 21),
Members = (1ULL << 22),
Admins = (1ULL << 23),
BannedUsers = (1ULL << 24),
Rights = (1ULL << 25),
PendingRequests = (1ULL << 26),
// For channels
ChannelAmIn = (1U << 26),
StickersSet = (1U << 27),
ChannelLinkedChat = (1U << 28),
ChannelLocation = (1U << 29),
Slowmode = (1U << 30),
GroupCall = (1U << 31),
ChannelAmIn = (1ULL << 27),
StickersSet = (1ULL << 28),
ChannelLinkedChat = (1ULL << 29),
ChannelLocation = (1ULL << 30),
Slowmode = (1ULL << 31),
GroupCall = (1ULL << 32),
// For iteration
LastUsedBit = (1U << 31),
LastUsedBit = (1ULL << 32),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }

View file

@ -195,6 +195,13 @@ void ChannelData::setKickedCount(int newKickedCount) {
}
}
void ChannelData::setPendingRequestsCount(int count) {
if (_pendingRequestsCount != count) {
_pendingRequestsCount = count;
session().changes().peerUpdated(this, UpdateFlag::PendingRequests);
}
}
ChatRestrictionsInfo ChannelData::KickedRestrictedRights(
not_null<PeerData*> participant) {
using Flag = ChatRestriction;
@ -542,6 +549,9 @@ void ChannelData::setAdminRights(ChatAdminRights rights) {
return;
}
_adminRights.set(rights);
if (!canHaveInviteLink()) {
setPendingRequestsCount(0);
}
if (isMegagroup()) {
const auto self = session().user();
if (hasAdminRights()) {
@ -874,6 +884,8 @@ void ApplyChannelUpdate(
}
channel->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty()));
channel->fullUpdated();
channel->setPendingRequestsCount(
update.vrequests_pending().value_or_empty());
if (canViewAdmins != channel->canViewAdmins()
|| canViewMembers != channel->canViewMembers()) {

View file

@ -177,6 +177,11 @@ public:
}
void setKickedCount(int newKickedCount);
[[nodiscard]] int pendingRequestsCount() const {
return _pendingRequestsCount;
}
void setPendingRequestsCount(int count);
[[nodiscard]] bool haveLeft() const {
return flags() & Flag::Left;
}
@ -426,6 +431,7 @@ private:
int _adminsCount = 1;
int _restrictedCount = 0;
int _kickedCount = 0;
int _pendingRequestsCount = 0;
MsgId _availableMinId = 0;
RestrictionFlags _defaultRestrictions;

View file

@ -146,6 +146,9 @@ void ChatData::setAdminRights(ChatAdminRights rights) {
return;
}
_adminRights.set(rights);
if (!canHaveInviteLink()) {
setPendingRequestsCount(0);
}
session().changes().peerUpdated(
this,
UpdateFlag::Rights | UpdateFlag::Admins | UpdateFlag::BannedUsers);
@ -258,6 +261,13 @@ void ChatData::setBotCommands(
}
}
void ChatData::setPendingRequestsCount(int count) {
if (_pendingRequestsCount != count) {
_pendingRequestsCount = count;
session().changes().peerUpdated(this, UpdateFlag::PendingRequests);
}
}
namespace Data {
void ApplyChatUpdate(
@ -431,6 +441,8 @@ void ApplyChatUpdate(not_null<ChatData*> chat, const MTPDchatFull &update) {
chat->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty()));
chat->fullUpdated();
chat->setAbout(qs(update.vabout()));
chat->setPendingRequestsCount(
update.vrequests_pending().value_or_empty());
chat->session().api().applyNotifySettings(
MTP_inputNotifyPeer(chat->input),

View file

@ -164,6 +164,11 @@ public:
return _botCommands;
}
[[nodiscard]] int pendingRequestsCount() const {
return _pendingRequestsCount;
}
void setPendingRequestsCount(int count);
// Still public data members.
const MTPlong inputChat;
@ -185,6 +190,7 @@ private:
RestrictionFlags _defaultRestrictions;
AdminRightFlags _adminRights;
int _version = 0;
int _pendingRequestsCount = 0;
std::unique_ptr<Data::GroupCall> _call;
PeerId _callDefaultJoinAs = 0;

View file

@ -312,6 +312,11 @@ TextWithEntities GenerateInviteLinkChangeText(
return data.vusage_limit().value_or_empty();
});
};
const auto requestApproval = [](const MTPExportedChatInvite &link) {
return link.match([](const MTPDchatInviteExported &data) {
return data.is_request_needed();
});
};
const auto wrapDate = [](TimeId date) {
return date
? langDateTime(base::unixtime::parse(date))
@ -326,12 +331,17 @@ TextWithEntities GenerateInviteLinkChangeText(
const auto nowExpireDate = expireDate(newLink);
const auto wasUsageLimit = usageLimit(prevLink);
const auto nowUsageLimit = usageLimit(newLink);
const auto wasRequestApproval = requestApproval(prevLink);
const auto nowRequestApproval = requestApproval(newLink);
if (wasExpireDate != nowExpireDate) {
result.text.append('\n').append(tr::lng_admin_log_invite_link_expire_date(tr::now, lt_previous, wrapDate(wasExpireDate), lt_limit, wrapDate(nowExpireDate)));
}
if (wasUsageLimit != nowUsageLimit) {
result.text.append('\n').append(tr::lng_admin_log_invite_link_usage_limit(tr::now, lt_previous, wrapUsage(wasUsageLimit), lt_limit, wrapUsage(nowUsageLimit)));
}
if (wasRequestApproval != nowRequestApproval) {
result.text.append('\n').append(nowRequestApproval ? tr::lng_admin_log_invite_link_request_needed(tr::now) : tr::lng_admin_log_invite_link_request_not_needed(tr::now));
}
result.entities.push_front(EntityInText(EntityType::Italic, 0, result.text.size()));
return result;

View file

@ -345,6 +345,7 @@ infoProfileSeparatorPadding: margins(
infoIconFg: menuIconFg;
infoIconInformation: icon {{ "info_information", infoIconFg }};
infoIconMembers: icon {{ "info/edit/group_manage_members", infoIconFg, point(-2px, 0px) }};
infoIconRequests: icon {{ "info/edit/group_manage_requests", infoIconFg, point(-2px, 0px) }};
infoIconNotifications: icon {{ "info_notifications", infoIconFg }};
infoIconActions: icon {{ "info_actions", infoIconFg }};
infoIconMediaPhoto: icon {{ "info_media_photo", infoIconFg }};

View file

@ -239,6 +239,25 @@ rpl::producer<int> MembersCountValue(not_null<PeerData*> peer) {
Unexpected("User in MembersCountViewer().");
}
rpl::producer<int> PendingRequestsCountValue(not_null<PeerData*> peer) {
if (const auto chat = peer->asChat()) {
return peer->session().changes().peerFlagsValue(
peer,
UpdateFlag::PendingRequests
) | rpl::map([=] {
return chat->pendingRequestsCount();
});
} else if (const auto channel = peer->asChannel()) {
return peer->session().changes().peerFlagsValue(
peer,
UpdateFlag::PendingRequests
) | rpl::map([=] {
return channel->pendingRequestsCount();
});
}
Unexpected("User in MembersCountViewer().");
}
rpl::producer<int> AdminsCountValue(not_null<PeerData*> peer) {
if (const auto chat = peer->asChat()) {
return peer->session().changes().peerFlagsValue(

View file

@ -49,6 +49,7 @@ rpl::producer<bool> CanShareContactValue(not_null<UserData*> user);
rpl::producer<bool> CanAddContactValue(not_null<UserData*> user);
rpl::producer<bool> AmInChannelValue(not_null<ChannelData*> channel);
rpl::producer<int> MembersCountValue(not_null<PeerData*> peer);
rpl::producer<int> PendingRequestsCountValue(not_null<PeerData*> peer);
rpl::producer<int> AdminsCountValue(not_null<PeerData*> peer);
rpl::producer<int> RestrictionsCountValue(not_null<PeerData*> peer);
rpl::producer<int> RestrictedCountValue(not_null<ChannelData*> channel);

View file

@ -52,6 +52,7 @@ void EditInviteLinkBox(
const InviteLinkFields &data,
Fn<void(InviteLinkFields)> done) {
const auto link = data.link;
const auto isGroup = data.isGroup;
box->setTitle(link.isEmpty()
? tr::lng_group_invite_new_title()
: tr::lng_group_invite_edit_title());
@ -119,10 +120,12 @@ void EditInviteLinkBox(
Buttons usageButtons;
int expireValue = 0;
int usageValue = 0;
rpl::variable<bool> requestApproval = false;
};
const auto state = box->lifetime().make_state<State>(State{
.expireValue = expire,
.usageValue = usage
.usageValue = usage,
.requestApproval = data.requestApproval,
});
const auto regenerate = [=] {
expireGroup->setValue(state->expireValue);
@ -260,6 +263,24 @@ void EditInviteLinkBox(
regenerate();
const auto buttonSkip = st::settingsSectionSkip;
const auto requestApproval = container->add(
object_ptr<SettingsButton>(
container,
tr::lng_group_invite_request_approve(),
st::settingsButton),
style::margins{ 0, buttonSkip, 0, buttonSkip });
requestApproval->toggleOn(state->requestApproval.value());
state->requestApproval = requestApproval->toggledValue();
addDivider(rpl::conditional(
state->requestApproval.value(),
(isGroup
? tr::lng_group_invite_about_approve()
: tr::lng_group_invite_about_approve_channel()),
(isGroup
? tr::lng_group_invite_about_no_approve()
: tr::lng_group_invite_about_no_approve_channel())));
const auto &saveLabel = link.isEmpty()
? tr::lng_formatting_link_create
: tr::lng_settings_save;
@ -275,7 +296,9 @@ void EditInviteLinkBox(
done(InviteLinkFields{
.link = link,
.expireDate = expireDate,
.usageLimit = usageLimit
.usageLimit = usageLimit,
.requestApproval = state->requestApproval.current(),
.isGroup = isGroup,
});
});
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
@ -283,8 +306,12 @@ void EditInviteLinkBox(
void CreateInviteLinkBox(
not_null<GenericBox*> box,
bool isGroup,
Fn<void(InviteLinkFields)> done) {
EditInviteLinkBox(box, InviteLinkFields(), std::move(done));
EditInviteLinkBox(
box,
InviteLinkFields{ .isGroup = isGroup },
std::move(done));
}
} // namespace Ui

View file

@ -15,6 +15,8 @@ struct InviteLinkFields {
QString link;
TimeId expireDate = 0;
int usageLimit = 0;
bool requestApproval = false;
bool isGroup = false;
};
void EditInviteLinkBox(
@ -24,6 +26,7 @@ void EditInviteLinkBox(
void CreateInviteLinkBox(
not_null<Ui::GenericBox*> box,
bool isGroup,
Fn<void(InviteLinkFields)> done);
} // namespace Ui