Edit join public group request requirement.

This commit is contained in:
John Preston 2022-04-15 20:57:03 +04:00
parent a752c4d9f3
commit c3386fba52
8 changed files with 275 additions and 89 deletions

View file

@ -1000,6 +1000,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_view_discussion" = "View discussion"; "lng_profile_view_discussion" = "View discussion";
"lng_profile_join_channel" = "Join Channel"; "lng_profile_join_channel" = "Join Channel";
"lng_profile_join_group" = "Join Group"; "lng_profile_join_group" = "Join Group";
"lng_profile_apply_to_join_group" = "Apply to Join Group";
"lng_profile_delete_and_exit" = "Leave"; "lng_profile_delete_and_exit" = "Leave";
"lng_profile_kick" = "Remove"; "lng_profile_kick" = "Remove";
"lng_profile_delete_removed" = "Delete"; "lng_profile_delete_removed" = "Delete";
@ -1128,6 +1129,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_public_group_title" = "Public"; "lng_manage_public_group_title" = "Public";
"lng_manage_private_peer_title" = "Private"; "lng_manage_private_peer_title" = "Private";
"lng_manage_public_peer_title" = "Public"; "lng_manage_public_peer_title" = "Public";
"lng_manage_peer_send_title" = "Who can send new messages?";
"lng_manage_peer_send_only_members" = "Only members";
"lng_manage_peer_send_only_members_about" = "Turn this on if you expect users to join your group before being able to send messages.";
"lng_manage_peer_send_approve_members" = "Approve new members";
"lng_manage_peer_send_approve_members_about" = "Turn this on if you want users to join the group only after they are approved by an admin.";
"lng_manage_peer_no_forwards_title" = "Saving content"; "lng_manage_peer_no_forwards_title" = "Saving content";
"lng_manage_peer_no_forwards" = "Restrict saving content"; "lng_manage_peer_no_forwards" = "Restrict saving content";
"lng_manage_peer_no_forwards_about" = "Members won't be able to forward messages from this group or save media files."; "lng_manage_peer_no_forwards_about" = "Members won't be able to forward messages from this group or save media files.";

View file

@ -269,6 +269,8 @@ private:
std::optional<bool> hiddenPreHistory; std::optional<bool> hiddenPreHistory;
std::optional<bool> signatures; std::optional<bool> signatures;
std::optional<bool> noForwards; std::optional<bool> noForwards;
std::optional<bool> joinToWrite;
std::optional<bool> requestToJoin;
std::optional<ChannelData*> linkedChat; std::optional<ChannelData*> linkedChat;
}; };
@ -306,6 +308,8 @@ private:
[[nodiscard]] bool validateHistoryVisibility(Saving &to) const; [[nodiscard]] bool validateHistoryVisibility(Saving &to) const;
[[nodiscard]] bool validateSignatures(Saving &to) const; [[nodiscard]] bool validateSignatures(Saving &to) const;
[[nodiscard]] bool validateForwards(Saving &to) const; [[nodiscard]] bool validateForwards(Saving &to) const;
[[nodiscard]] bool validateJoinToWrite(Saving &to) const;
[[nodiscard]] bool validateRequestToJoin(Saving &to) const;
void save(); void save();
void saveUsername(); void saveUsername();
@ -315,6 +319,8 @@ private:
void saveHistoryVisibility(); void saveHistoryVisibility();
void saveSignatures(); void saveSignatures();
void saveForwards(); void saveForwards();
void saveJoinToWrite();
void saveRequestToJoin();
void savePhoto(); void savePhoto();
void pushSaveStage(FnMut<void()> &&lambda); void pushSaveStage(FnMut<void()> &&lambda);
void continueSave(); void continueSave();
@ -329,14 +335,12 @@ private:
void subscribeToMigration(); void subscribeToMigration();
void migrate(not_null<ChannelData*> channel); void migrate(not_null<ChannelData*> channel);
std::optional<Privacy> _privacySavedValue;
std::optional<ChannelData*> _linkedChatSavedValue; std::optional<ChannelData*> _linkedChatSavedValue;
ChannelData *_linkedChatOriginalValue = nullptr; ChannelData *_linkedChatOriginalValue = nullptr;
bool _channelHasLocationOriginalValue = false; bool _channelHasLocationOriginalValue = false;
std::optional<HistoryVisibility> _historyVisibilitySavedValue; std::optional<HistoryVisibility> _historyVisibilitySavedValue;
std::optional<QString> _usernameSavedValue; std::optional<EditPeerTypeData> _typeDataSavedValue;
std::optional<bool> _signaturesSavedValue; std::optional<bool> _signaturesSavedValue;
std::optional<bool> _noForwardsSavedValue;
const not_null<Window::SessionNavigation*> _navigation; const not_null<Window::SessionNavigation*> _navigation;
const not_null<Ui::BoxContent*> _box; const not_null<Ui::BoxContent*> _box;
@ -602,8 +606,10 @@ void Controller::refreshHistoryVisibility() {
if (!_controls.historyVisibilityWrap) { if (!_controls.historyVisibilityWrap) {
return; return;
} }
const auto withUsername = _typeDataSavedValue
&& (_typeDataSavedValue->privacy == Privacy::HasUsername);
_controls.historyVisibilityWrap->toggle( _controls.historyVisibilityWrap->toggle(
(_privacySavedValue != Privacy::HasUsername (withUsername
&& !_channelHasLocationOriginalValue && !_channelHasLocationOriginalValue
&& (!_linkedChatSavedValue || !*_linkedChatSavedValue)), && (!_linkedChatSavedValue || !*_linkedChatSavedValue)),
anim::type::instant); anim::type::instant);
@ -611,22 +617,19 @@ void Controller::refreshHistoryVisibility() {
void Controller::showEditPeerTypeBox( void Controller::showEditPeerTypeBox(
std::optional<rpl::producer<QString>> error) { std::optional<rpl::producer<QString>> error) {
const auto boxCallback = crl::guard(this, [=]( const auto boxCallback = crl::guard(this, [=](EditPeerTypeData data) {
Privacy checked, QString publicLink, bool noForwards) { _privacyTypeUpdates.fire_copy(data.privacy);
_privacyTypeUpdates.fire(std::move(checked)); _typeDataSavedValue = data;
_privacySavedValue = checked;
_usernameSavedValue = publicLink;
_noForwardsSavedValue = noForwards;
refreshHistoryVisibility(); refreshHistoryVisibility();
}); });
_typeDataSavedValue->hasLinkedChat
= (_linkedChatSavedValue.value_or(nullptr) != nullptr);
_navigation->parentController()->show( _navigation->parentController()->show(
Box<EditPeerTypeBox>( Box<EditPeerTypeBox>(
_peer, _peer,
_channelHasLocationOriginalValue, _channelHasLocationOriginalValue,
boxCallback, boxCallback,
_privacySavedValue, _typeDataSavedValue,
_usernameSavedValue,
_noForwardsSavedValue,
error), error),
Ui::LayerOption::KeepOther); Ui::LayerOption::KeepOther);
} }
@ -698,12 +701,20 @@ void Controller::fillPrivacyTypeButton() {
// Create Privacy Button. // Create Privacy Button.
const auto hasLocation = _peer->isChannel() const auto hasLocation = _peer->isChannel()
&& _peer->asChannel()->hasLocation(); && _peer->asChannel()->hasLocation();
_privacySavedValue = (_peer->isChannel() _typeDataSavedValue = EditPeerTypeData{
&& _peer->asChannel()->hasUsername()) .privacy = ((_peer->isChannel()
? Privacy::HasUsername && _peer->asChannel()->hasUsername())
: Privacy::NoUsername; ? Privacy::HasUsername
_noForwardsSavedValue = !_peer->allowsForwarding(); : Privacy::NoUsername),
.username = (_peer->isChannel()
? _peer->asChannel()->username
: QString()),
.noForwards = !_peer->allowsForwarding(),
.joinToWrite = (_peer->isMegagroup()
&& _peer->asChannel()->joinToWrite()),
.requestToJoin = (_peer->isMegagroup()
&& _peer->asChannel()->requestToJoin()),
};
const auto isGroup = (_peer->isChat() || _peer->isMegagroup()); const auto isGroup = (_peer->isChat() || _peer->isMegagroup());
const auto icon = isGroup const auto icon = isGroup
? &st::settingsIconGroup ? &st::settingsIconGroup
@ -732,7 +743,7 @@ void Controller::fillPrivacyTypeButton() {
[=] { showEditPeerTypeBox(); }, [=] { showEditPeerTypeBox(); },
{ icon, Settings::kIconLightBlue }); { icon, Settings::kIconLightBlue });
_privacyTypeUpdates.fire_copy(*_privacySavedValue); _privacyTypeUpdates.fire_copy(_typeDataSavedValue->privacy);
} }
void Controller::fillLinkedChatButton() { void Controller::fillLinkedChatButton() {
@ -1060,9 +1071,9 @@ void Controller::fillManageSection() {
}, },
{ &st::infoRoundedIconInviteLinks, Settings::kIconLightOrange }); { &st::infoRoundedIconInviteLinks, Settings::kIconLightOrange });
if (_privacySavedValue) { if (_typeDataSavedValue) {
_privacyTypeUpdates.events_starting_with_copy( _privacyTypeUpdates.events_starting_with_copy(
*_privacySavedValue _typeDataSavedValue->privacy
) | rpl::start_with_next([=](Privacy flag) { ) | rpl::start_with_next([=](Privacy flag) {
wrap->toggle( wrap->toggle(
flag != Privacy::HasUsername, flag != Privacy::HasUsername,
@ -1217,24 +1228,22 @@ std::optional<Controller::Saving> Controller::validate() const {
&& validateDescription(result) && validateDescription(result)
&& validateHistoryVisibility(result) && validateHistoryVisibility(result)
&& validateSignatures(result) && validateSignatures(result)
&& validateForwards(result)) { && validateForwards(result)
&& validateJoinToWrite(result)
&& validateRequestToJoin(result)) {
return result; return result;
} }
return {}; return {};
} }
bool Controller::validateUsername(Saving &to) const { bool Controller::validateUsername(Saving &to) const {
if (!_privacySavedValue) { if (!_typeDataSavedValue) {
return true; return true;
} else if (_privacySavedValue != Privacy::HasUsername) { } else if (_typeDataSavedValue->privacy != Privacy::HasUsername) {
to.username = QString(); to.username = QString();
return true; return true;
} }
const auto username = _usernameSavedValue.value_or( const auto username = _typeDataSavedValue->username;
_peer->isChannel()
? _peer->asChannel()->username
: QString()
);
if (username.isEmpty()) { if (username.isEmpty()) {
return false; return false;
} }
@ -1276,7 +1285,8 @@ bool Controller::validateHistoryVisibility(Saving &to) const {
if (!_controls.historyVisibilityWrap if (!_controls.historyVisibilityWrap
|| !_controls.historyVisibilityWrap->toggled() || !_controls.historyVisibilityWrap->toggled()
|| _channelHasLocationOriginalValue || _channelHasLocationOriginalValue
|| (_privacySavedValue == Privacy::HasUsername)) { || (_typeDataSavedValue
&& _typeDataSavedValue->privacy == Privacy::HasUsername)) {
return true; return true;
} }
to.hiddenPreHistory to.hiddenPreHistory
@ -1293,10 +1303,26 @@ bool Controller::validateSignatures(Saving &to) const {
} }
bool Controller::validateForwards(Saving &to) const { bool Controller::validateForwards(Saving &to) const {
if (!_noForwardsSavedValue.has_value()) { if (!_typeDataSavedValue) {
return true; return true;
} }
to.noForwards = _noForwardsSavedValue; to.noForwards = _typeDataSavedValue->noForwards;
return true;
}
bool Controller::validateJoinToWrite(Saving &to) const {
if (!_typeDataSavedValue) {
return true;
}
to.joinToWrite = _typeDataSavedValue->joinToWrite;
return true;
}
bool Controller::validateRequestToJoin(Saving &to) const {
if (!_typeDataSavedValue) {
return true;
}
to.requestToJoin = _typeDataSavedValue->requestToJoin;
return true; return true;
} }
@ -1315,6 +1341,8 @@ void Controller::save() {
pushSaveStage([=] { saveHistoryVisibility(); }); pushSaveStage([=] { saveHistoryVisibility(); });
pushSaveStage([=] { saveSignatures(); }); pushSaveStage([=] { saveSignatures(); });
pushSaveStage([=] { saveForwards(); }); pushSaveStage([=] { saveForwards(); });
pushSaveStage([=] { saveJoinToWrite(); });
pushSaveStage([=] { saveRequestToJoin(); });
pushSaveStage([=] { savePhoto(); }); pushSaveStage([=] { savePhoto(); });
continueSave(); continueSave();
} }
@ -1591,6 +1619,50 @@ void Controller::saveForwards() {
}).send(); }).send();
} }
void Controller::saveJoinToWrite() {
const auto joinToWrite = _peer->isMegagroup()
&& _peer->asChannel()->joinToWrite();
if (!_savingData.joinToWrite
|| *_savingData.joinToWrite == joinToWrite) {
return continueSave();
}
_api.request(MTPchannels_ToggleJoinToSend(
_peer->asChannel()->inputChannel,
MTP_bool(*_savingData.joinToWrite)
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
continueSave();
}).fail([=](const MTP::Error &error) {
if (error.type() == qstr("CHAT_NOT_MODIFIED")) {
continueSave();
} else {
cancelSave();
}
}).send();
}
void Controller::saveRequestToJoin() {
const auto requestToJoin = _peer->isMegagroup()
&& _peer->asChannel()->requestToJoin();
if (!_savingData.requestToJoin
|| *_savingData.requestToJoin == requestToJoin) {
return continueSave();
}
_api.request(MTPchannels_ToggleJoinRequest(
_peer->asChannel()->inputChannel,
MTP_bool(*_savingData.requestToJoin)
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
continueSave();
}).fail([=](const MTP::Error &error) {
if (error.type() == qstr("CHAT_NOT_MODIFIED")) {
continueSave();
} else {
cancelSave();
}
}).send();
}
void Controller::savePhoto() { void Controller::savePhoto() {
auto image = _controls.photo auto image = _controls.photo
? _controls.photo->takeResultImage() ? _controls.photo->takeResultImage()

View file

@ -52,16 +52,14 @@ public:
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer, not_null<PeerData*> peer,
bool useLocationPhrases, bool useLocationPhrases,
std::optional<Privacy> privacySavedValue, std::optional<EditPeerTypeData> dataSavedValue);
std::optional<QString> usernameSavedValue,
std::optional<bool> noForwardsSavedValue);
void createContent(); void createContent();
[[nodiscard]] QString getUsernameInput() const; [[nodiscard]] QString getUsernameInput() const;
void setFocusUsername(); void setFocusUsername();
[[nodiscard]] rpl::producer<QString> getTitle() const { [[nodiscard]] rpl::producer<QString> getTitle() const {
return !_privacySavedValue return !_dataSavedValue
? tr::lng_create_invite_link_title() ? tr::lng_create_invite_link_title()
: _isGroup : _isGroup
? tr::lng_manage_peer_group_type() ? tr::lng_manage_peer_group_type()
@ -79,6 +77,12 @@ public:
[[nodiscard]] bool noForwards() const { [[nodiscard]] bool noForwards() const {
return _controls.noForwards->toggled(); return _controls.noForwards->toggled();
} }
[[nodiscard]] bool joinToWrite() const {
return _controls.joinToWrite && _controls.joinToWrite->toggled();
}
[[nodiscard]] bool requestToJoin() const {
return _controls.requestToJoin && _controls.requestToJoin->toggled();
}
void showError(rpl::producer<QString> text) { void showError(rpl::producer<QString> text) {
_controls.usernameInput->showError(); _controls.usernameInput->showError();
@ -93,10 +97,13 @@ private:
base::unique_qptr<Ui::FlatLabel> usernameResult; base::unique_qptr<Ui::FlatLabel> usernameResult;
const style::FlatLabel *usernameResultStyle = nullptr; const style::FlatLabel *usernameResultStyle = nullptr;
Ui::SlideWrap<Ui::RpWidget> *inviteLinkWrap = nullptr; Ui::SlideWrap<> *inviteLinkWrap = nullptr;
Ui::FlatLabel *inviteLink = nullptr; Ui::FlatLabel *inviteLink = nullptr;
Ui::SlideWrap<Ui::VerticalLayout> *whoSendWrap = nullptr;
Ui::SettingsButton *noForwards = nullptr; Ui::SettingsButton *noForwards = nullptr;
Ui::SettingsButton *joinToWrite = nullptr;
Ui::SettingsButton *requestToJoin = nullptr;
}; };
Controls _controls; Controls _controls;
@ -130,9 +137,7 @@ private:
bool _linkOnly = false; bool _linkOnly = false;
MTP::Sender _api; MTP::Sender _api;
std::optional<Privacy> _privacySavedValue; std::optional<EditPeerTypeData> _dataSavedValue;
std::optional<QString> _usernameSavedValue;
std::optional<bool> _noForwardsSavedValue;
bool _useLocationPhrases = false; bool _useLocationPhrases = false;
bool _isGroup = false; bool _isGroup = false;
@ -153,20 +158,17 @@ Controller::Controller(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer, not_null<PeerData*> peer,
bool useLocationPhrases, bool useLocationPhrases,
std::optional<Privacy> privacySavedValue, std::optional<EditPeerTypeData> dataSavedValue)
std::optional<QString> usernameSavedValue,
std::optional<bool> noForwardsSavedValue)
: _show(show) : _show(show)
, _peer(peer) , _peer(peer)
, _linkOnly(!privacySavedValue.has_value()) , _linkOnly(!dataSavedValue.has_value())
, _api(&_peer->session().mtp()) , _api(&_peer->session().mtp())
, _privacySavedValue(privacySavedValue) , _dataSavedValue(dataSavedValue)
, _usernameSavedValue(usernameSavedValue)
, _noForwardsSavedValue(noForwardsSavedValue)
, _useLocationPhrases(useLocationPhrases) , _useLocationPhrases(useLocationPhrases)
, _isGroup(_peer->isChat() || _peer->isMegagroup()) , _isGroup(_peer->isChat() || _peer->isMegagroup())
, _goodUsername(!_usernameSavedValue.value_or( , _goodUsername(_dataSavedValue
_peer->isChannel() ? _peer->asChannel()->username : QString()).isEmpty()) ? !_dataSavedValue->username.isEmpty()
: (_peer->isChannel() && !_peer->asChannel()->username.isEmpty()))
, _wrap(container) , _wrap(container)
, _checkUsernameTimer([=] { checkUsernameAvailability(); }) { , _checkUsernameTimer([=] { checkUsernameAvailability(); }) {
_peer->updateFull(); _peer->updateFull();
@ -175,7 +177,12 @@ Controller::Controller(
void Controller::createContent() { void Controller::createContent() {
_controls = Controls(); _controls = Controls();
fillPrivaciesButtons(_wrap, _privacySavedValue); fillPrivaciesButtons(
_wrap,
(_dataSavedValue
? _dataSavedValue->privacy
: std::optional<Privacy>()));
// Skip. // Skip.
if (!_linkOnly) { if (!_linkOnly) {
_wrap->add(object_ptr<Ui::BoxContentDivider>(_wrap)); _wrap->add(object_ptr<Ui::BoxContentDivider>(_wrap));
@ -204,6 +211,63 @@ void Controller::createContent() {
AddDividerText(_wrap.get(), tr::lng_group_invite_manage_about()); AddDividerText(_wrap.get(), tr::lng_group_invite_manage_about());
if (!_linkOnly) { if (!_linkOnly) {
if (_peer->isMegagroup()) {
_controls.whoSendWrap = _wrap->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_wrap.get(),
object_ptr<Ui::VerticalLayout>(_wrap.get())));
const auto wrap = _controls.whoSendWrap->entity();
AddSkip(wrap);
if (_dataSavedValue->hasLinkedChat) {
AddSubsectionTitle(wrap, tr::lng_manage_peer_send_title());
_controls.joinToWrite = wrap->add(EditPeerInfoBox::CreateButton(
wrap,
tr::lng_manage_peer_send_only_members(),
rpl::single(QString()),
[=] {},
st::manageGroupTopButtonWithText,
{}
));
_controls.joinToWrite->toggleOn(
rpl::single(_dataSavedValue->joinToWrite)
)->toggledValue(
) | rpl::start_with_next([=](bool toggled) {
_dataSavedValue->joinToWrite = toggled;
}, wrap->lifetime());
}
auto joinToWrite = _controls.joinToWrite
? _controls.joinToWrite->toggledValue()
: rpl::single(true);
const auto requestToJoinWrap = wrap->add(
object_ptr<Ui::SlideWrap<Ui::SettingsButton>>(
wrap,
EditPeerInfoBox::CreateButton(
wrap,
tr::lng_manage_peer_send_approve_members(),
rpl::single(QString()),
[=] {},
st::manageGroupTopButtonWithText,
{})))->setDuration(0);
requestToJoinWrap->toggleOn(rpl::duplicate(joinToWrite));
_controls.requestToJoin = requestToJoinWrap->entity();
_controls.requestToJoin->toggleOn(
rpl::single(_dataSavedValue->requestToJoin)
)->toggledValue(
) | rpl::start_with_next([=](bool toggled) {
_dataSavedValue->requestToJoin = toggled;
}, wrap->lifetime());
AddSkip(wrap);
AddDividerText(
wrap,
rpl::conditional(
std::move(joinToWrite),
tr::lng_manage_peer_send_approve_members_about(),
tr::lng_manage_peer_send_only_members_about()));
}
AddSkip(_wrap.get()); AddSkip(_wrap.get());
AddSubsectionTitle( AddSubsectionTitle(
_wrap.get(), _wrap.get(),
@ -216,10 +280,10 @@ void Controller::createContent() {
st::peerPermissionsButton, st::peerPermissionsButton,
{})); {}));
_controls.noForwards->toggleOn( _controls.noForwards->toggleOn(
rpl::single(_noForwardsSavedValue.value_or(false)) rpl::single(_dataSavedValue->noForwards)
)->toggledValue( )->toggledValue(
) | rpl::start_with_next([=](bool toggled) { ) | rpl::start_with_next([=](bool toggled) {
_noForwardsSavedValue = toggled; _dataSavedValue->noForwards = toggled;
}, _wrap->lifetime()); }, _wrap->lifetime());
AddSkip(_wrap.get()); AddSkip(_wrap.get());
AddDividerText( AddDividerText(
@ -234,8 +298,9 @@ void Controller::createContent() {
if (_controls.privacy->value() == Privacy::NoUsername) { if (_controls.privacy->value() == Privacy::NoUsername) {
checkUsernameAvailability(); checkUsernameAvailability();
} }
const auto forShowing = _privacySavedValue.value_or( const auto forShowing = _dataSavedValue
Privacy::NoUsername); ? _dataSavedValue->privacy
: Privacy::NoUsername;
_controls.inviteLinkWrap->toggle( _controls.inviteLinkWrap->toggle(
(forShowing != Privacy::HasUsername), (forShowing != Privacy::HasUsername),
anim::type::instant); anim::type::instant);
@ -332,8 +397,9 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
Expects(_wrap != nullptr); Expects(_wrap != nullptr);
const auto channel = _peer->asChannel(); const auto channel = _peer->asChannel();
const auto username = _usernameSavedValue.value_or( const auto username = (!_dataSavedValue || !channel)
channel ? channel->username : QString()); ? QString()
: channel->username;
auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_wrap, _wrap,
@ -401,6 +467,15 @@ void Controller::privacyChanged(Privacy value) {
(value == Privacy::HasUsername), (value == Privacy::HasUsername),
anim::type::instant); anim::type::instant);
}; };
const auto toggleWhoSendWrap = [&] {
if (!_controls.whoSendWrap) {
return;
}
_controls.whoSendWrap->toggle(
(value == Privacy::HasUsername
|| (_dataSavedValue && _dataSavedValue->hasLinkedChat)),
anim::type::instant);
};
const auto refreshVisibilities = [&] { const auto refreshVisibilities = [&] {
// Now first we need to hide that was shown. // Now first we need to hide that was shown.
// Otherwise box will change own Y position. // Otherwise box will change own Y position.
@ -408,10 +483,12 @@ void Controller::privacyChanged(Privacy value) {
if (value == Privacy::HasUsername) { if (value == Privacy::HasUsername) {
toggleInviteLink(); toggleInviteLink();
toggleEditUsername(); toggleEditUsername();
toggleWhoSendWrap();
_controls.usernameResult = nullptr; _controls.usernameResult = nullptr;
checkUsernameAvailability(); checkUsernameAvailability();
} else { } else {
toggleWhoSendWrap();
toggleEditUsername(); toggleEditUsername();
toggleInviteLink(); toggleInviteLink();
} }
@ -572,7 +649,7 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkBlock() {
const auto container = result->entity(); const auto container = result->entity();
using namespace Settings; using namespace Settings;
if (_privacySavedValue) { if (_dataSavedValue) {
AddSkip(container); AddSkip(container);
AddSubsectionTitle(container, tr::lng_create_permanent_link_title()); AddSubsectionTitle(container, tr::lng_create_permanent_link_title());
@ -601,24 +678,20 @@ EditPeerTypeBox::EditPeerTypeBox(
QWidget*, QWidget*,
not_null<PeerData*> peer, not_null<PeerData*> peer,
bool useLocationPhrases, bool useLocationPhrases,
std::optional<FnMut<void(Privacy, QString, bool)>> savedCallback, std::optional<FnMut<void(EditPeerTypeData)>> savedCallback,
std::optional<Privacy> privacySaved, std::optional<EditPeerTypeData> dataSaved,
std::optional<QString> usernameSaved,
std::optional<bool> noForwardsValue,
std::optional<rpl::producer<QString>> usernameError) std::optional<rpl::producer<QString>> usernameError)
: _peer(peer) : _peer(peer)
, _useLocationPhrases(useLocationPhrases) , _useLocationPhrases(useLocationPhrases)
, _savedCallback(std::move(savedCallback)) , _savedCallback(std::move(savedCallback))
, _privacySavedValue(privacySaved) , _dataSavedValue(dataSaved)
, _usernameSavedValue(usernameSaved)
, _noForwardsValue(noForwardsValue)
, _usernameError(usernameError) { , _usernameError(usernameError) {
} }
EditPeerTypeBox::EditPeerTypeBox( EditPeerTypeBox::EditPeerTypeBox(
QWidget*, QWidget*,
not_null<PeerData*> peer) not_null<PeerData*> peer)
: EditPeerTypeBox(nullptr, peer, {}, {}, {}, {}, {}, {}) { : EditPeerTypeBox(nullptr, peer, {}, {}, {}) {
} }
void EditPeerTypeBox::setInnerFocus() { void EditPeerTypeBox::setInnerFocus() {
@ -636,9 +709,7 @@ void EditPeerTypeBox::prepare() {
content.data(), content.data(),
_peer, _peer,
_useLocationPhrases, _useLocationPhrases,
_privacySavedValue, _dataSavedValue);
_usernameSavedValue,
_noForwardsValue);
_focusRequests.events( _focusRequests.events(
) | rpl::start_with_next( ) | rpl::start_with_next(
[=] { [=] {
@ -662,12 +733,15 @@ void EditPeerTypeBox::prepare() {
} }
auto local = std::move(*_savedCallback); auto local = std::move(*_savedCallback);
local( local(EditPeerTypeData{
v, .privacy = v,
(v == Privacy::HasUsername .username = (v == Privacy::HasUsername
? controller->getUsernameInput() ? controller->getUsernameInput()
: QString()), : QString()),
controller->noForwards()); // We don't need username with private type. .noForwards = controller->noForwards(),
.joinToWrite = controller->joinToWrite(),
.requestToJoin = controller->requestToJoin(),
}); // We don't need username with private type.
closeBox(); closeBox();
}); });
addButton(tr::lng_cancel(), [=] { closeBox(); }); addButton(tr::lng_cancel(), [=] { closeBox(); });

View file

@ -29,16 +29,23 @@ enum class UsernameState {
NotAvailable, NotAvailable,
}; };
struct EditPeerTypeData {
Privacy privacy = Privacy::NoUsername;
QString username;
bool hasLinkedChat = false;
bool noForwards = false;
bool joinToWrite = false;
bool requestToJoin = false;
};
class EditPeerTypeBox : public Ui::BoxContent { class EditPeerTypeBox : public Ui::BoxContent {
public: public:
EditPeerTypeBox( EditPeerTypeBox(
QWidget*, QWidget*,
not_null<PeerData*> peer, not_null<PeerData*> peer,
bool useLocationPhrases, bool useLocationPhrases,
std::optional<FnMut<void(Privacy, QString, bool)>> savedCallback, std::optional<FnMut<void(EditPeerTypeData)>> savedCallback,
std::optional<Privacy> privacySaved, std::optional<EditPeerTypeData> dataSaved,
std::optional<QString> usernameSaved,
std::optional<bool> noForwardsSaved,
std::optional<rpl::producer<QString>> usernameError = {}); std::optional<rpl::producer<QString>> usernameError = {});
// For invite link only. // For invite link only.
@ -53,11 +60,9 @@ protected:
private: private:
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
bool _useLocationPhrases = false; bool _useLocationPhrases = false;
std::optional<FnMut<void(Privacy, QString, bool)>> _savedCallback; std::optional<FnMut<void(EditPeerTypeData)>> _savedCallback;
std::optional<Privacy> _privacySavedValue; std::optional<EditPeerTypeData> _dataSavedValue;
std::optional<QString> _usernameSavedValue;
std::optional<bool> _noForwardsValue;
std::optional<rpl::producer<QString>> _usernameError; std::optional<rpl::producer<QString>> _usernameError;
rpl::event_stream<> _focusRequests; rpl::event_stream<> _focusRequests;

View file

@ -52,6 +52,8 @@ enum class ChannelDataFlag {
HasLink = (1 << 18), HasLink = (1 << 18),
SlowmodeEnabled = (1 << 19), SlowmodeEnabled = (1 << 19),
NoForwards = (1 << 20), NoForwards = (1 << 20),
JoinToWrite = (1 << 21),
RequestToJoin = (1 << 22),
}; };
inline constexpr bool is_flag_type(ChannelDataFlag) { return true; }; inline constexpr bool is_flag_type(ChannelDataFlag) { return true; };
using ChannelDataFlags = base::flags<ChannelDataFlag>; using ChannelDataFlags = base::flags<ChannelDataFlag>;
@ -255,6 +257,12 @@ public:
[[nodiscard]] bool amCreator() const { [[nodiscard]] bool amCreator() const {
return flags() & Flag::Creator; return flags() & Flag::Creator;
} }
[[nodiscard]] bool joinToWrite() const {
return flags() & Flag::JoinToWrite;
}
[[nodiscard]] bool requestToJoin() const {
return flags() & Flag::RequestToJoin;
}
[[nodiscard]] auto adminRights() const { [[nodiscard]] auto adminRights() const {
return _adminRights.current(); return _adminRights.current();

View file

@ -741,7 +741,9 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
| Flag::CallNotEmpty | Flag::CallNotEmpty
| Flag::Forbidden | Flag::Forbidden
| (!minimal ? (Flag::Left | Flag::Creator) : Flag()) | (!minimal ? (Flag::Left | Flag::Creator) : Flag())
| Flag::NoForwards; | Flag::NoForwards
| Flag::JoinToWrite
| Flag::RequestToJoin;
const auto flagsSet = (data.is_broadcast() ? Flag::Broadcast : Flag()) const auto flagsSet = (data.is_broadcast() ? Flag::Broadcast : Flag())
| (data.is_verified() ? Flag::Verified : Flag()) | (data.is_verified() ? Flag::Verified : Flag())
| (data.is_scam() ? Flag::Scam : Flag()) | (data.is_scam() ? Flag::Scam : Flag())
@ -762,7 +764,9 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
? (data.is_left() ? Flag::Left : Flag()) ? (data.is_left() ? Flag::Left : Flag())
| (data.is_creator() ? Flag::Creator : Flag()) | (data.is_creator() ? Flag::Creator : Flag())
: Flag()) : Flag())
| (data.is_noforwards() ? Flag::NoForwards : Flag()); | (data.is_noforwards() ? Flag::NoForwards : Flag())
| (data.is_join_to_send() ? Flag::JoinToWrite : Flag())
| (data.is_join_request() ? Flag::RequestToJoin : Flag());
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet); channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
channel->setName( channel->setName(

View file

@ -913,6 +913,16 @@ Dialogs::EntryState HistoryWidget::computeDialogsEntryState() const {
}; };
} }
void HistoryWidget::refreshJoinChannelText() {
if (const auto channel = _peer ? _peer->asChannel() : nullptr) {
_joinChannel->setText((channel->isBroadcast()
? tr::lng_profile_join_channel(tr::now)
: (channel->requestToJoin() && !channel->amCreator())
? tr::lng_profile_apply_to_join_group(tr::now)
: tr::lng_profile_join_group(tr::now)).toUpper());
}
}
void HistoryWidget::refreshTopBarActiveChat() { void HistoryWidget::refreshTopBarActiveChat() {
const auto state = computeDialogsEntryState(); const auto state = computeDialogsEntryState();
_topBar->setActiveChat(state, _history->sendActionPainter()); _topBar->setActiveChat(state, _history->sendActionPainter());
@ -2210,12 +2220,6 @@ void HistoryWidget::showHistory(
&& !_peer->asUser()->isSupport()) && !_peer->asUser()->isSupport())
? tr::lng_restart_button(tr::now) ? tr::lng_restart_button(tr::now)
: tr::lng_unblock_button(tr::now)).toUpper()); : tr::lng_unblock_button(tr::now)).toUpper());
if (const auto channel = _peer->asChannel()) {
channel->updateFull();
_joinChannel->setText((channel->isMegagroup()
? tr::lng_profile_join_group(tr::now)
: tr::lng_profile_join_channel(tr::now)).toUpper());
}
} }
_nonEmptySelection = false; _nonEmptySelection = false;
@ -2269,6 +2273,18 @@ void HistoryWidget::showHistory(
object_ptr<HistoryInner>(this, _scroll, controller(), _history)); object_ptr<HistoryInner>(this, _scroll, controller(), _history));
_list->show(); _list->show();
if (const auto channel = _peer->asChannel()) {
channel->updateFull();
if (!channel->isBroadcast()) {
channel->flagsValue(
) | rpl::start_with_next([=] {
refreshJoinChannelText();
}, _list->lifetime());
} else {
refreshJoinChannelText();
}
}
controller()->adaptive().changes( controller()->adaptive().changes(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_history->forceFullResize(); _history->forceFullResize();

View file

@ -375,6 +375,7 @@ private:
[[nodiscard]] Dialogs::EntryState computeDialogsEntryState() const; [[nodiscard]] Dialogs::EntryState computeDialogsEntryState() const;
void refreshTopBarActiveChat(); void refreshTopBarActiveChat();
void refreshJoinChannelText();
void requestMessageData(MsgId msgId); void requestMessageData(MsgId msgId);
void messageDataReceived(not_null<PeerData*> peer, MsgId msgId); void messageDataReceived(not_null<PeerData*> peer, MsgId msgId);