Added Invite Link button. Refactored code.

- Removed unused includes.
 - Improved design for boxes.
 - Draw buttons for EditPeerInfoBox in single place.
 - Simplified conditions for all buttons.
 - Made AddSkip more flexible.
This commit is contained in:
23rd 2019-03-17 20:42:33 +03:00 committed by John Preston
parent 8887272577
commit 3d7b8b3162
8 changed files with 636 additions and 657 deletions

View File

@ -866,6 +866,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_create_private_group_about" = "People can only join if they were invited or have an invite link";
"lng_create_group_skip" = "Skip";
"lng_create_channel_link_about" = "You can use a-z, 0-9 and underscores.\nMinimum length is 5 characters.";
"lng_create_channel_link_invalid" = "This link is invalid";
"lng_create_channel_link_occupied" = "Sorry, this link is already occupied";
"lng_create_channel_link_too_short" = "Sorry, this link is too short";

View File

@ -23,14 +23,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
std::shared_ptr<Ui::RadioenumGroup<HistoryVisibility>> historyVisibility;
Ui::SlideWrap<Ui::RpWidget> *historyVisibilityWrap = nullptr;
void AddRoundButton(
not_null<Ui::VerticalLayout*> container,
HistoryVisibility value,
LangKey groupTextKey,
LangKey groupAboutKey) {
LangKey groupAboutKey,
std::shared_ptr<Ui::RadioenumGroup<HistoryVisibility>> historyVisibility) {
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerHistoryVisibilityTopSkip));
@ -46,12 +44,13 @@ void AddRoundButton(
container,
Lang::Viewer(groupAboutKey),
st::editPeerPrivacyLabel),
st::editPeerPrivacyLabelMargins));
};
st::editPeerPreHistoryLabelMargins));
}
void FillContent(
not_null<Ui::VerticalLayout*> parent,
not_null<PeerData*> peer,
std::shared_ptr<Ui::RadioenumGroup<HistoryVisibility>> historyVisibility,
std::optional<HistoryVisibility> savedValue = std::nullopt) {
const auto canEdit = [&] {
@ -67,13 +66,6 @@ void FillContent(
}
const auto channel = peer->asChannel();
const auto result = parent->add(object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
parent,
object_ptr<Ui::VerticalLayout>(parent),
st::editPeerHistoryVisibilityMargins));
historyVisibilityWrap = result;
const auto container = result->entity();
const auto defaultValue = savedValue.value_or(
(!channel || channel->hiddenPreHistory())
@ -81,20 +73,30 @@ void FillContent(
: HistoryVisibility::Visible
);
historyVisibility = std::make_shared<Ui::RadioenumGroup<HistoryVisibility>>(defaultValue);
historyVisibility->setValue(defaultValue);
const auto result = parent->add(object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
parent,
object_ptr<Ui::VerticalLayout>(parent),
st::editPeerHistoryVisibilityMargins));
const auto container = result->entity();
Expects(historyVisibility != nullptr);
AddRoundButton(
container,
HistoryVisibility::Visible,
lng_manage_history_visibility_shown,
lng_manage_history_visibility_shown_about);
lng_manage_history_visibility_shown_about,
historyVisibility);
AddRoundButton(
container,
HistoryVisibility::Hidden,
lng_manage_history_visibility_hidden,
(peer->isChat()
? lng_manage_history_visibility_hidden_legacy
: lng_manage_history_visibility_hidden_about));
: lng_manage_history_visibility_hidden_about),
historyVisibility);
}
} // namespace
@ -106,7 +108,10 @@ EditPeerHistoryVisibilityBox::EditPeerHistoryVisibilityBox(
std::optional<HistoryVisibility> historyVisibilitySavedValue)
: _peer(peer)
, _savedCallback(std::move(savedCallback))
, _historyVisibilitySavedValue(historyVisibilitySavedValue) {
, _historyVisibilitySavedValue(historyVisibilitySavedValue)
, _historyVisibility(
std::make_shared<Ui::RadioenumGroup<HistoryVisibility>>(
_historyVisibilitySavedValue.value_or(HistoryVisibility::Hidden))) {
}
void EditPeerHistoryVisibilityBox::prepare() {
@ -115,7 +120,7 @@ void EditPeerHistoryVisibilityBox::prepare() {
setTitle(langFactory(lng_manage_history_visibility_title));
addButton(langFactory(lng_settings_save), [=] {
auto local = std::move(_savedCallback);
local(historyVisibility->value());
local(_historyVisibility->value());
closeBox();
});
addButton(langFactory(lng_cancel), [=] { closeBox(); });
@ -125,6 +130,6 @@ void EditPeerHistoryVisibilityBox::prepare() {
void EditPeerHistoryVisibilityBox::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
FillContent(content, _peer, _historyVisibilitySavedValue);
FillContent(content, _peer, _historyVisibility, _historyVisibilitySavedValue);
setDimensionsToContent(st::boxWidth, content);
}

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/abstract_box.h"
#include "ui/widgets/checkbox.h"
namespace style {
struct InfoProfileCountButton;
@ -47,5 +48,6 @@ private:
FnMut<void(HistoryVisibility)> _savedCallback;
std::optional<HistoryVisibility> _historyVisibilitySavedValue;
std::shared_ptr<Ui::RadioenumGroup<HistoryVisibility>> _historyVisibility = nullptr;
};

View File

@ -47,12 +47,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
Fn<QString()> ManagePeerTitle(not_null<PeerData*> peer) {
return langFactory((peer->isChat() || peer->isMegagroup())
? lng_manage_group_title
: lng_manage_channel_title);
}
auto ToPositiveNumberString() {
return rpl::map([](int count) {
return count ? QString::number(count) : QString();
@ -67,11 +61,17 @@ auto ToPositiveNumberStringRestrictions() {
});
}
void AddSkip(not_null<Ui::VerticalLayout*> container) {
void AddSkip(
not_null<Ui::VerticalLayout*> container,
int top = st::editPeerTopButtonsLayoutSkip,
int bottom = st::editPeerTopButtonsLayoutSkipToBottom) {
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerSkip));
top));
container->add(object_ptr<BoxContentDivider>(container));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
bottom));
}
void AddButtonWithCount(
@ -103,32 +103,6 @@ Info::Profile::Button *AddButtonWithText(
nullptr);
}
bool HasRecentActions(not_null<ChannelData*> channel) {
return channel->hasAdminRights() || channel->amCreator();
}
void ShowRecentActions(
not_null<Window::Navigation*> navigation,
not_null<ChannelData*> channel) {
navigation->showSection(AdminLog::SectionMemento(channel));
}
bool HasEditInfoBox(not_null<PeerData*> peer) {
if (const auto chat = peer->asChat()) {
if (chat->canEditInformation()) {
return true;
}
} else if (const auto channel = peer->asChannel()) {
if (channel->canEditInformation()) {
return true;
} else if (!channel->isPublic() && channel->canAddMembers()) {
// Edit invite link.
return true;
}
}
return false;
}
void ShowEditPermissions(not_null<PeerData*> peer) {
const auto box = Ui::show(
Box<EditPeerPermissionsBox>(peer),
@ -147,108 +121,10 @@ void ShowEditPermissions(not_null<PeerData*> peer) {
}, box->lifetime());
}
void FillManageSection(
not_null<Window::Navigation*> navigation,
not_null<PeerData*> peer,
not_null<Ui::VerticalLayout*> content) {
const auto chat = peer->asChat();
const auto channel = peer->asChannel();
const auto isChannel = (!chat);
if (!chat && !channel) return;
const auto canEditPermissions = [=] {
return isChannel
? channel->canEditPermissions()
: chat->canEditPermissions();
}();
const auto canViewAdmins = [=] {
return isChannel
? channel->canViewAdmins()
: chat->amIn();
}();
const auto canViewMembers = [=] {
return isChannel
? channel->canViewMembers()
: chat->amIn();
}();
const auto canViewKicked = [=] {
return isChannel
? (!channel->isMegagroup())
: false;
}();
const auto hasRecentActions = [=] {
return isChannel
? (channel->hasAdminRights() || channel->amCreator())
: false;
}();
if (canEditPermissions) {
AddButtonWithCount(
content,
Lang::Viewer(lng_manage_peer_permissions),
Info::Profile::RestrictionsCountValue(peer)
| ToPositiveNumberStringRestrictions(),
[=] { ShowEditPermissions(peer); },
st::infoIconPermissions);
}
if (canViewAdmins) {
AddButtonWithCount(
content,
Lang::Viewer(lng_manage_peer_administrators),
Info::Profile::AdminsCountValue(peer)
| ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
peer,
ParticipantsBoxController::Role::Admins);
},
st::infoIconAdministrators);
}
if (canViewMembers) {
AddButtonWithCount(
content,
Lang::Viewer(lng_manage_peer_members),
Info::Profile::MembersCountValue(peer)
| ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
peer,
ParticipantsBoxController::Role::Members);
},
st::infoIconMembers);
}
if (canViewKicked) {
AddButtonWithCount(
content,
Lang::Viewer(lng_manage_peer_removed_users),
Info::Profile::KickedCountValue(channel)
| ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
peer,
ParticipantsBoxController::Role::Kicked);
},
st::infoIconBlacklist);
}
if (hasRecentActions) {
AddButtonWithCount(
content,
Lang::Viewer(lng_manage_peer_recent_actions),
rpl::single(QString()), //Empty count.
[=] { ShowRecentActions(navigation, channel); },
st::infoIconRecentActions);
}
}
} // namespace
namespace {
constexpr auto kUsernameCheckTimeout = crl::time(200);
constexpr auto kMinUsernameLength = 5;
constexpr auto kMaxGroupChannelTitle = 255; // See also add_contact_box.
constexpr auto kMaxChannelDescription = 255; // See also add_contact_box.
@ -269,23 +145,8 @@ private:
Ui::InputField *description = nullptr;
Ui::UserpicButton *photo = nullptr;
rpl::lifetime initialPhotoImageWaiting;
std::shared_ptr<Ui::RadioenumGroup<Privacy>> privacy;
Ui::SlideWrap<Ui::RpWidget> *usernameWrap = nullptr;
Ui::UsernameInput *username = nullptr;
base::unique_qptr<Ui::FlatLabel> usernameResult;
const style::FlatLabel *usernameResultStyle = nullptr;
Ui::SlideWrap<Ui::RpWidget> *createInviteLinkWrap = nullptr;
Ui::SlideWrap<Ui::RpWidget> *editInviteLinkWrap = nullptr;
Ui::FlatLabel *inviteLink = nullptr;
Ui::SlideWrap<Ui::RpWidget> *historyVisibilityWrap = nullptr;
std::optional<HistoryVisibility> historyVisibilitySavedValue = std::nullopt;
std::optional<Privacy> privacySavedValue = std::nullopt;
std::optional<QString> usernameSavedValue = std::nullopt;
std::optional<bool> signaturesSavedValue = std::nullopt;
Ui::VerticalLayout *buttonsLayout = nullptr;
};
struct Saving {
std::optional<QString> username;
@ -295,21 +156,24 @@ private:
std::optional<bool> signatures;
};
Fn<QString()> computeTitle() const;
object_ptr<Ui::RpWidget> createPhotoAndTitleEdit();
object_ptr<Ui::RpWidget> createTitleEdit();
object_ptr<Ui::RpWidget> createPhotoEdit();
object_ptr<Ui::RpWidget> createDescriptionEdit();
void refreshHistoryVisibility(bool instant);
void fillPrivacyTypeButton();
void fillInviteLinkButton();
void fillSignaturesButton();
void fillHistoryVisibilityButton();
void fillManageSection(not_null<Window::Navigation*> navigation, not_null<PeerData*> peer);
object_ptr<Ui::RpWidget> createUsernameEdit();
object_ptr<Ui::RpWidget> createInviteLinkCreate();
object_ptr<Ui::RpWidget> createInviteLinkEdit();
object_ptr<Ui::RpWidget> createStickersEdit();
object_ptr<Ui::RpWidget> createDeleteButton();
object_ptr<Ui::RpWidget> createPrivaciesButtons();
object_ptr<Ui::RpWidget> createManageGroupButtons();
QString inviteLinkText() const;
void observeInviteLink();
void submitTitle();
@ -338,15 +202,17 @@ private:
void subscribeToMigration();
void migrate(not_null<ChannelData*> channel);
std::optional<Privacy> _privacySavedValue = std::nullopt;
std::optional<HistoryVisibility> _historyVisibilitySavedValue = std::nullopt;
std::optional<QString> _usernameSavedValue = std::nullopt;
std::optional<bool> _signaturesSavedValue = std::nullopt;
not_null<BoxContent*> _box;
not_null<PeerData*> _peer;
bool _isGroup = false;
base::unique_qptr<Ui::VerticalLayout> _wrap;
Controls _controls;
mtpRequestId _checkUsernameRequestId = 0;
UsernameState _usernameState = UsernameState::Normal;
rpl::event_stream<rpl::producer<QString>> _usernameResultTexts;
std::deque<FnMut<void()>> _saveStagesQueue;
Saving _savingData;
@ -361,7 +227,9 @@ Controller::Controller(
: _box(box)
, _peer(peer)
, _isGroup(_peer->isChat() || _peer->isMegagroup()) {
_box->setTitle(computeTitle());
_box->setTitle(langFactory(_isGroup
? lng_edit_group
: lng_edit_channel_title));
_box->addButton(langFactory(lng_settings_save), [this] {
save();
});
@ -385,12 +253,6 @@ void Controller::migrate(not_null<ChannelData*> channel) {
_peer->updateFull();
}
Fn<QString()> Controller::computeTitle() const {
return langFactory(_isGroup
? lng_edit_group
: lng_edit_channel_title);
}
object_ptr<Ui::VerticalLayout> Controller::createContent() {
auto result = object_ptr<Ui::VerticalLayout>(_box);
_wrap.reset(result.data());
@ -399,11 +261,7 @@ object_ptr<Ui::VerticalLayout> Controller::createContent() {
_wrap->add(createPhotoAndTitleEdit());
_wrap->add(createDescriptionEdit());
AddSkip(_wrap); // Divider.
_wrap->add(createPrivaciesButtons());
AddSkip(_wrap); // Divider.
_wrap->add(createManageGroupButtons());
AddSkip(_wrap); // Divider.
_wrap->add(createStickersEdit());
_wrap->add(createDeleteButton());
@ -532,142 +390,281 @@ object_ptr<Ui::RpWidget> Controller::createDescriptionEdit() {
return std::move(result);
}
object_ptr<Ui::RpWidget> Controller::createPrivaciesButtons() {
Expects(_wrap != nullptr);
const auto canEditUsername = [&] {
if (const auto chat = _peer->asChat()) {
return chat->canEditUsername();
} else if (const auto channel = _peer->asChannel()) {
return channel->canEditUsername();
}
Unexpected("Peer type in Controller::createPrivaciesEdit.");
}();
if (!canEditUsername) {
return nullptr;
void Controller::refreshHistoryVisibility(bool instant = false) {
if (!_controls.historyVisibilityWrap) {
return;
}
_controls.historyVisibilityWrap->toggle(
_privacySavedValue == Privacy::Private,
instant ? anim::type::instant : anim::type::normal);
};
const auto refreshHistoryVisibility = [=](bool instant = false) {
if (!_controls.historyVisibilityWrap) {
return;
}
_controls.historyVisibilityWrap->toggle(
_controls.privacySavedValue == Privacy::Private,
instant ? anim::type::instant : anim::type::normal);
};
const auto channel = _peer->asChannel();
auto isRealChannel = !(!channel || !channel->canEditSignatures() || channel->isMegagroup());
void Controller::fillPrivacyTypeButton() {
Expects(_controls.buttonsLayout != nullptr);
// Create Privacy Button.
_controls.privacySavedValue = (_peer->isChannel()
_privacySavedValue = (_peer->isChannel()
&& _peer->asChannel()->isPublic())
? Privacy::Public
: Privacy::Private;
const auto updateType = std::make_shared<rpl::event_stream<Privacy>>();
auto result = object_ptr<Ui::PaddingWrap<Ui::VerticalLayout>>(
_wrap,
object_ptr<Ui::VerticalLayout>(_wrap),
st::editPeerTopButtonsLayoutMargins);
auto resultContainer = result->entity();
const auto boxCallback = [=](Privacy checked, QString publicLink) {
updateType->fire(std::move(checked));
_controls.privacySavedValue = checked;
_controls.usernameSavedValue = publicLink;
_privacySavedValue = checked;
_usernameSavedValue = publicLink;
refreshHistoryVisibility();
};
const auto buttonCallback = [=]{
const auto buttonCallback = [=] {
Ui::show(Box<EditPeerTypeBox>(
_peer,
boxCallback,
_controls.privacySavedValue,
_controls.usernameSavedValue
), LayerOption::KeepOther);
_privacySavedValue,
_usernameSavedValue
), LayerOption::KeepOther);
};
AddButtonWithText(
resultContainer,
_controls.buttonsLayout,
std::move(Lang::Viewer((_peer->isChat() || _peer->isMegagroup())
? lng_manage_peer_group_type
: lng_manage_peer_channel_type)),
updateType->events(
) | rpl::map([](Privacy flag) {
return lang(Privacy::Public == flag
? lng_manage_public_peer_title
: lng_manage_private_peer_title);
}),
return lang(Privacy::Public == flag
? lng_manage_public_peer_title
: lng_manage_private_peer_title);
}),
buttonCallback);
updateType->fire(std::move(_controls.privacySavedValue.value()));
// Create Signatures Toggle Button.
if (isRealChannel) {
AddButtonWithText(
resultContainer,
std::move(Lang::Viewer(lng_edit_sign_messages)),
rpl::single(QString()),
[=] {}
)->toggleOn(rpl::single(channel->addsSignature())
)->toggledValue(
) | rpl::start_with_next([=](bool toggled) {
_controls.signaturesSavedValue = toggled;
}, resultContainer->lifetime());
updateType->fire(std::move(_privacySavedValue.value()));
}
return std::move(result);
}
void Controller::fillInviteLinkButton() {
Expects(_controls.buttonsLayout != nullptr);
// Create History Visibility Button.
const auto boxCallback = [=](Privacy checked, QString publicLink) {};
const auto addHistoryVisibilityButton = [=](LangKey privacyTextKey, Ui::VerticalLayout* container) {
// Bug with defaultValue here.
_controls.historyVisibilitySavedValue = (!channel || channel->hiddenPreHistory())
? HistoryVisibility::Hidden
: HistoryVisibility::Visible;
const auto updateHistoryVisibility = std::make_shared<rpl::event_stream<HistoryVisibility>>();
const auto boxCallback = [=](HistoryVisibility checked) {
updateHistoryVisibility->fire(std::move(checked));
_controls.historyVisibilitySavedValue = checked;
};
const auto buttonCallback = [=]{
Ui::show(Box<EditPeerHistoryVisibilityBox>(
_peer,
boxCallback,
_controls.historyVisibilitySavedValue
const auto buttonCallback = [=] {
Ui::show(Box<EditPeerTypeBox>(
_peer,
boxCallback
), LayerOption::KeepOther);
};
AddButtonWithText(
container,
std::move(Lang::Viewer(privacyTextKey)),
updateHistoryVisibility->events(
) | rpl::map([](HistoryVisibility flag) {
return lang(HistoryVisibility::Visible == flag
? lng_manage_history_visibility_shown
: lng_manage_history_visibility_hidden);
}),
buttonCallback);
updateHistoryVisibility->fire(
std::move(_controls.historyVisibilitySavedValue.value())
);
};
auto wrapLayout = resultContainer->add(object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
resultContainer,
object_ptr<Ui::VerticalLayout>(resultContainer),
AddButtonWithText(
_controls.buttonsLayout,
Lang::Viewer(lng_profile_invite_link_section),
rpl::single(QString()), //Empty text.
buttonCallback);
}
void Controller::fillSignaturesButton() {
Expects(_controls.buttonsLayout != nullptr);
const auto channel = _peer->asChannel();
if (!channel) return;
AddButtonWithText(
_controls.buttonsLayout,
std::move(Lang::Viewer(lng_edit_sign_messages)),
rpl::single(QString()),
[=] {}
)->toggleOn(rpl::single(channel->addsSignature())
)->toggledValue(
) | rpl::start_with_next([=](bool toggled) {
_signaturesSavedValue = toggled;
}, _controls.buttonsLayout->lifetime());
}
void Controller::fillHistoryVisibilityButton() {
Expects(_controls.buttonsLayout != nullptr);
auto wrapLayout = _controls.buttonsLayout->add(object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_controls.buttonsLayout,
object_ptr<Ui::VerticalLayout>(_controls.buttonsLayout),
st::boxOptionListPadding)); // Empty margins.
_controls.historyVisibilityWrap = wrapLayout;
addHistoryVisibilityButton(lng_manage_history_visibility_title, wrapLayout->entity());
const auto channel = _peer->asChannel();
auto container = wrapLayout->entity();
_historyVisibilitySavedValue = (!channel || channel->hiddenPreHistory())
? HistoryVisibility::Hidden
: HistoryVisibility::Visible;
const auto updateHistoryVisibility = std::make_shared<rpl::event_stream<HistoryVisibility>>();
const auto boxCallback = [=](HistoryVisibility checked) {
updateHistoryVisibility->fire(std::move(checked));
_historyVisibilitySavedValue = checked;
};
const auto buttonCallback = [=] {
Ui::show(Box<EditPeerHistoryVisibilityBox>(
_peer,
boxCallback,
_historyVisibilitySavedValue
), LayerOption::KeepOther);
};
AddButtonWithText(
container,
std::move(Lang::Viewer(lng_manage_history_visibility_title)),
updateHistoryVisibility->events(
) | rpl::map([](HistoryVisibility flag) {
return lang(HistoryVisibility::Visible == flag
? lng_manage_history_visibility_shown
: lng_manage_history_visibility_hidden);
}),
buttonCallback);
updateHistoryVisibility->fire(
std::move(_historyVisibilitySavedValue.value())
);
//While appearing box we should use instant animation.
refreshHistoryVisibility(true);
}
return std::move(result);
void Controller::fillManageSection(
not_null<Window::Navigation*> navigation,
not_null<PeerData*> peer) {
Expects(_controls.buttonsLayout != nullptr);
const auto chat = peer->asChat();
const auto channel = peer->asChannel();
const auto isChannel = (!chat);
if (!chat && !channel) return;
const auto canEditUsername = [=] {
return isChannel
? channel->canEditUsername()
: chat->canEditUsername();
}();
const auto canEditInviteLink = [=] {
return isChannel
? (channel->amCreator() || (channel->adminRights() & ChatAdminRight::f_invite_users))
: (chat->amCreator() || (chat->adminRights() & ChatAdminRight::f_invite_users));
}();
const auto canEditSignatures = [=] {
return isChannel
? (channel->canEditSignatures() && !channel->isMegagroup())
: false;
}();
const auto canEditPreHistoryHidden = [=] {
return isChannel
? channel->canEditPreHistoryHidden()
: chat->canEditPreHistoryHidden();
}();
const auto canEditPermissions = [=] {
return isChannel
? channel->canEditPermissions()
: chat->canEditPermissions();
}();
const auto canViewAdmins = [=] {
return isChannel
? channel->canViewAdmins()
: chat->amIn();
}();
const auto canViewMembers = [=] {
return isChannel
? channel->canViewMembers()
: chat->amIn();
}();
const auto canViewKicked = [=] {
return isChannel
? (!channel->isMegagroup())
: false;
}();
const auto hasRecentActions = [=] {
return isChannel
? (channel->hasAdminRights() || channel->amCreator())
: false;
}();
AddSkip(_controls.buttonsLayout, 0);
if (canEditUsername) {
fillPrivacyTypeButton();
}
else if (canEditInviteLink) {
fillInviteLinkButton();
}
if (canEditSignatures) {
fillSignaturesButton();
}
if (canEditPreHistoryHidden) {
fillHistoryVisibilityButton();
}
if (canEditPreHistoryHidden || canEditSignatures || canEditInviteLink) {
// Perhaps should fix extra 1-pixel line for design.
AddSkip(_controls.buttonsLayout);
}
if (canEditPermissions) {
AddButtonWithCount(
_controls.buttonsLayout,
Lang::Viewer(lng_manage_peer_permissions),
Info::Profile::RestrictionsCountValue(peer)
| ToPositiveNumberStringRestrictions(),
[=] { ShowEditPermissions(peer); },
st::infoIconPermissions);
}
if (canViewAdmins) {
AddButtonWithCount(
_controls.buttonsLayout,
Lang::Viewer(lng_manage_peer_administrators),
Info::Profile::AdminsCountValue(peer)
| ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
peer,
ParticipantsBoxController::Role::Admins);
},
st::infoIconAdministrators);
}
if (canViewMembers) {
AddButtonWithCount(
_controls.buttonsLayout,
Lang::Viewer(lng_manage_peer_members),
Info::Profile::MembersCountValue(peer)
| ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
peer,
ParticipantsBoxController::Role::Members);
},
st::infoIconMembers);
}
if (canViewKicked) {
AddButtonWithCount(
_controls.buttonsLayout,
Lang::Viewer(lng_manage_peer_removed_users),
Info::Profile::KickedCountValue(channel)
| ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
peer,
ParticipantsBoxController::Role::Kicked);
},
st::infoIconBlacklist);
}
if (hasRecentActions) {
AddButtonWithCount(
_controls.buttonsLayout,
Lang::Viewer(lng_manage_peer_recent_actions),
rpl::single(QString()), //Empty count.
[=] {
navigation->showSection(AdminLog::SectionMemento(channel));
},
st::infoIconRecentActions);
}
AddSkip(_controls.buttonsLayout);
}
object_ptr<Ui::RpWidget> Controller::createManageGroupButtons() {
@ -677,10 +674,9 @@ object_ptr<Ui::RpWidget> Controller::createManageGroupButtons() {
_wrap,
object_ptr<Ui::VerticalLayout>(_wrap),
st::editPeerBottomButtonsLayoutMargins);
auto container = result->entity();
_controls.buttonsLayout = result->entity();
FillManageSection(App::wnd()->controller(), _peer, container);
// setDimensionsToContent(st::boxWidth, content);
fillManageSection(App::wnd()->controller(), _peer);
return std::move(result);
}
@ -696,7 +692,7 @@ object_ptr<Ui::RpWidget> Controller::createStickersEdit() {
auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_wrap,
object_ptr<Ui::VerticalLayout>(_wrap),
st::editPeerInviteLinkMargins);
st::editPeerInvitesMargins);
auto container = result->entity();
container->add(object_ptr<Ui::FlatLabel>(
@ -786,11 +782,11 @@ std::optional<Controller::Saving> Controller::validate() const {
}
bool Controller::validateUsername(Saving &to) const {
if (_controls.privacySavedValue != Privacy::Public) {
if (_privacySavedValue != Privacy::Public) {
to.username = QString();
return true;
}
auto username = _controls.usernameSavedValue.value_or(
auto username = _usernameSavedValue.value_or(
_peer->isChannel()
? _peer->asChannel()->username
: QString()
@ -828,19 +824,19 @@ bool Controller::validateHistoryVisibility(Saving &to) const {
if (!_controls.historyVisibilityWrap) return true;
if (!_controls.historyVisibilityWrap->toggled()
|| (_controls.privacySavedValue == Privacy::Public)) {
|| (_privacySavedValue == Privacy::Public)) {
return true;
}
to.hiddenPreHistory
= (_controls.historyVisibilitySavedValue == HistoryVisibility::Hidden);
= (_historyVisibilitySavedValue == HistoryVisibility::Hidden);
return true;
}
bool Controller::validateSignatures(Saving &to) const {
if (!_controls.signaturesSavedValue.has_value()) {
if (!_signaturesSavedValue.has_value()) {
return true;
}
to.signatures = _controls.signaturesSavedValue;
to.signatures = _signaturesSavedValue;
return true;
}
@ -923,8 +919,7 @@ void Controller::saveUsername() {
}
return lng_create_channel_link_invalid;
}();
_controls.username->showError();
_box->scrollToWidget(_controls.username);
// Probably never happend.
// showUsernameError(Lang::Viewer(errorKey));
cancelSave();
}).send();
@ -1187,7 +1182,7 @@ bool EditPeerInfoBox::Available(not_null<PeerData*> peer) {
|| channel->canViewBanned()
|| channel->canEditInformation()
|| channel->canEditPermissions()
|| HasRecentActions(channel);
|| (channel->hasAdminRights() || channel->amCreator());
} else {
return false;
}

View File

@ -46,7 +46,7 @@ protected:
void prepare() override;
private:
not_null<PeerData*> _peer;
rpl::event_stream<> _focusRequests;
not_null<PeerData*> _peer;
};

View File

@ -8,268 +8,41 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_peer_type_box.h"
#include "apiwrap.h"
#include "apiwrap.h"
#include "apiwrap.h"
#include "auth_session.h"
#include "auth_session.h"
#include "auth_session.h"
#include "boxes/add_contact_box.h"
#include "boxes/add_contact_box.h"
#include "boxes/confirm_box.h"
#include "boxes/confirm_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/edit_participants_box.h"
#include "boxes/peers/edit_participants_box.h"
#include "boxes/peers/edit_participants_box.h"
#include "boxes/peers/edit_peer_type_box.h"
#include "boxes/peers/edit_peer_history_visibility_box.h"
#include "boxes/peers/edit_peer_info_box.h"
#include "boxes/peers/edit_peer_permissions_box.h"
#include "boxes/peers/edit_peer_permissions_box.h"
#include "boxes/photo_crop_box.h"
#include "boxes/stickers_box.h"
#include "boxes/stickers_box.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "core/application.h"
#include "data/data_channel.h"
#include "data/data_channel.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_chat.h"
#include "data/data_chat.h"
#include "data/data_peer.h"
#include "data/data_peer.h"
#include "history/admin_log/history_admin_log_section.h"
#include "history/admin_log/history_admin_log_section.h"
#include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_icon.h"
#include "info/profile/info_profile_values.h"
#include "data/data_session.h"
#include "info/profile/info_profile_values.h"
#include "lang/lang_keys.h"
#include "lang/lang_keys.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "mainwindow.h"
#include "mtproto/sender.h"
#include "mtproto/sender.h"
#include "observer_peer.h"
#include "styles/style_boxes.h"
#include "styles/style_boxes.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h"
#include "styles/style_info.h"
#include "styles/style_info.h"
#include "ui/rp_widget.h"
#include "ui/special_buttons.h"
#include "ui/special_buttons.h"
#include "ui/toast/toast.h"
#include "ui/toast/toast.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_controller.h"
#include "window/window_controller.h"
#include <rpl/combine.h>
#include <rpl/flatten_latest.h>
#include <rpl/flatten_latest.h>
#include <rpl/range.h>
#include <rpl/range.h>
#include "styles/style_boxes.h"
#include "styles/style_dialogs.h"
#include "lang/lang_keys.h"
#include "mtproto/sender.h"
#include "base/flat_set.h"
#include "boxes/confirm_box.h"
#include "boxes/photo_crop_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/add_participants_box.h"
#include "boxes/peers/edit_participant_box.h"
#include "boxes/peers/edit_participants_box.h"
#include "core/file_utilities.h"
#include "core/application.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h"
#include "ui/toast/toast.h"
#include "ui/special_buttons.h"
#include "ui/text_options.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "apiwrap.h"
#include "observer_peer.h"
#include "auth_session.h"
namespace {
std::optional<Privacy> privacySavedValue;
std::optional<QString> usernameSavedValue;
std::shared_ptr<Ui::RadioenumGroup<Privacy>> privacyButtons;
Ui::SlideWrap<Ui::RpWidget> *usernameWrap = nullptr;
Ui::UsernameInput *usernameInput = nullptr;
base::unique_qptr<Ui::FlatLabel> usernameResult;
const style::FlatLabel *usernameResultStyle = nullptr;
Ui::SlideWrap<Ui::RpWidget> *createInviteLinkWrap = nullptr;
// Ui::SlideWrap<Ui::RpWidget> *_editInviteLinkWrap = nullptr;
Ui::FlatLabel *inviteLink = nullptr;
PeerData *peer = nullptr;
bool allowSave = false;
mtpRequestId _checkUsernameRequestId = 0;
UsernameState _usernameState = UsernameState::Normal;
rpl::event_stream<rpl::producer<QString>> _usernameResultTexts;
bool isGroup = false;
void AddRoundButton(
not_null<Ui::VerticalLayout*> container,
Privacy value,
LangKey groupTextKey,
LangKey channelTextKey,
LangKey groupAboutKey,
LangKey channelAboutKey) {
container->add(object_ptr<Ui::Radioenum<Privacy>>(
container,
privacyButtons,
value,
lang(isGroup ? groupTextKey : channelTextKey),
st::defaultBoxCheckbox));
container->add(object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
container,
object_ptr<Ui::FlatLabel>(
container,
Lang::Viewer(isGroup ? groupAboutKey : channelAboutKey),
st::editPeerPrivacyLabel),
st::editPeerPrivacyLabelMargins));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerPrivacyBottomSkip));
};
void FillGroupedButtons(
not_null<Ui::VerticalLayout*> parent,
not_null<PeerData*> peer,
std::optional<Privacy> savedValue = std::nullopt) {
const auto canEditUsername = [&] {
if (const auto chat = peer->asChat()) {
return chat->canEditUsername();
} else if (const auto channel = peer->asChannel()) {
return channel->canEditUsername();
}
Unexpected("Peer type in Controller::createPrivaciesEdit.");
}();
if (!canEditUsername) {
return;
}
const auto result = parent->add(object_ptr<Ui::PaddingWrap<Ui::VerticalLayout>>(
parent,
object_ptr<Ui::VerticalLayout>(parent),
st::editPeerPrivaciesMargins));
auto container = result->entity();
const auto isPublic = peer->isChannel()
&& peer->asChannel()->isPublic();
privacyButtons = std::make_shared<Ui::RadioenumGroup<Privacy>>(
savedValue.value_or(isPublic ? Privacy::Public : Privacy::Private));
AddRoundButton(
container,
Privacy::Public,
lng_create_public_group_title,
lng_create_public_channel_title,
lng_create_public_group_about,
lng_create_public_channel_about);
AddRoundButton(
container,
Privacy::Private,
lng_create_private_group_title,
lng_create_private_channel_title,
lng_create_private_group_about,
lng_create_private_channel_about);
// privacyButtons->setChangedCallback([this](Privacy value) {
// privacyChanged(value);
// });
if (!isPublic) {
// checkUsernameAvailability();
}
// return std::move(result);
}
void FillContent(
not_null<Ui::VerticalLayout*> parent,
not_null<PeerData*> peer,
std::optional<Privacy> savedValue = std::nullopt) {
FillGroupedButtons(parent, peer, savedValue);
}
void SetFocusUsername() {
if (usernameInput) {
usernameInput->setFocus();
}
}
QString GetUsernameInput() {
return usernameInput->getLastText().trimmed();
}
bool InviteLinkShown() {
return !privacyButtons
|| (privacyButtons->value() == Privacy::Private);
}
QString InviteLinkText() {
if (const auto channel = peer->asChannel()) {
return channel->inviteLink();
} else if (const auto chat = peer->asChat()) {
return chat->inviteLink();
}
return QString();
}
} // namespace
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_controller.h"
#include <rpl/flatten_latest.h>
namespace {
constexpr auto kUsernameCheckTimeout = crl::time(200);
constexpr auto kMinUsernameLength = 5;
constexpr auto kMaxGroupChannelTitle = 255; // See also add_contact_box.
constexpr auto kMaxChannelDescription = 255; // See also add_contact_box.
class Controller
: public base::has_weak_ptr
@ -277,12 +50,50 @@ class Controller
public:
Controller(
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer);
not_null<PeerData*> peer,
std::optional<Privacy> privacySavedValue,
std::optional<QString> usernameSavedValue);
void createContent();
QString getUsernameInput();
void setFocusUsername();
LangKey getTitle() {
return _isInviteLink
? lng_profile_invite_link_section
: _isGroup
? lng_manage_peer_group_type
: lng_manage_peer_channel_type;
}
bool isInviteLink() {
return _isInviteLink;
}
bool isAllowSave() {
return _isAllowSave;
}
Privacy getPrivacy() {
return _controls.privacy->value();
}
private:
struct Controls {
std::shared_ptr<Ui::RadioenumGroup<Privacy>> privacy;
Ui::SlideWrap<Ui::RpWidget> *usernameWrap = nullptr;
Ui::UsernameInput *usernameInput = nullptr;
base::unique_qptr<Ui::FlatLabel> usernameResult;
const style::FlatLabel *usernameResultStyle = nullptr;
Ui::SlideWrap<Ui::RpWidget> *createInviteLinkWrap = nullptr;
Ui::SlideWrap<Ui::RpWidget> *editInviteLinkWrap = nullptr;
Ui::FlatLabel *inviteLink = nullptr;
};
Controls _controls;
object_ptr<Ui::RpWidget> createPrivaciesEdit();
object_ptr<Ui::RpWidget> createUsernameEdit();
object_ptr<Ui::RpWidget> createInviteLinkCreate();
@ -308,11 +119,30 @@ private:
void revokeInviteLink();
void exportInviteLink(const QString &confirmation);
void fillPrivaciesButtons(
not_null<Ui::VerticalLayout*> parent,
std::optional<Privacy> savedValue = std::nullopt);
void addRoundButton(
not_null<Ui::VerticalLayout*> container,
Privacy value,
LangKey groupTextKey,
LangKey channelTextKey,
LangKey groupAboutKey,
LangKey channelAboutKey);
bool inviteLinkShown();
QString inviteLinkText();
void subscribeToMigration();
void migrate(not_null<ChannelData*> channel);
not_null<PeerData*> _peer;
std::optional<Privacy> _privacySavedValue = std::nullopt;
std::optional<QString> _usernameSavedValue = std::nullopt;
bool _isGroup = false;
bool _isInviteLink = false;
bool _isAllowSave = false;
base::unique_qptr<Ui::VerticalLayout> _wrap;
base::Timer _checkUsernameTimer;
@ -320,17 +150,21 @@ private:
UsernameState _usernameState = UsernameState::Normal;
rpl::event_stream<rpl::producer<QString>> _usernameResultTexts;
Ui::SlideWrap<Ui::RpWidget> *_editInviteLinkWrap = nullptr;
rpl::lifetime _lifetime;
};
Controller::Controller(
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer)
not_null<PeerData*> peer,
std::optional<Privacy> privacySavedValue,
std::optional<QString> usernameSavedValue)
: _peer(peer)
, _privacySavedValue(privacySavedValue)
, _usernameSavedValue(usernameSavedValue)
, _isGroup(_peer->isChat() || _peer->isMegagroup())
, _isInviteLink(!_privacySavedValue.has_value() && !_usernameSavedValue.has_value())
, _isAllowSave(!_usernameSavedValue.value_or(QString()).isEmpty())
, _wrap(container)
, _checkUsernameTimer([=] { checkUsernameAvailability(); }) {
subscribeToMigration();
@ -351,41 +185,150 @@ void Controller::migrate(not_null<ChannelData*> channel) {
}
void Controller::createContent() {
privacyButtons->setChangedCallback([this](Privacy value) {
privacyChanged(value);
});
_controls = Controls();
if (_isInviteLink) {
_wrap->add(createInviteLinkCreate());
_wrap->add(createInviteLinkEdit());
return;
}
// _wrap->add(createPrivaciesEdit());
fillPrivaciesButtons(_wrap, _privacySavedValue);
// Skip.
_wrap->add(object_ptr<BoxContentDivider>(_wrap));
//
_wrap->add(createInviteLinkCreate());
_wrap->add(createInviteLinkEdit());
_wrap->add(createUsernameEdit());
if (privacyButtons->value() == Privacy::Private) {
if (_controls.privacy->value() == Privacy::Private) {
checkUsernameAvailability();
}
}
void Controller::addRoundButton(
not_null<Ui::VerticalLayout*> container,
Privacy value,
LangKey groupTextKey,
LangKey channelTextKey,
LangKey groupAboutKey,
LangKey channelAboutKey) {
container->add(object_ptr<Ui::Radioenum<Privacy>>(
container,
_controls.privacy,
value,
lang(_isGroup ? groupTextKey : channelTextKey),
st::editPeerPrivacyBoxCheckbox));
container->add(object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
container,
object_ptr<Ui::FlatLabel>(
container,
Lang::Viewer(_isGroup ? groupAboutKey : channelAboutKey),
st::editPeerPrivacyLabel),
st::editPeerPrivacyLabelMargins));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerPrivacyBottomSkip));
};
void Controller::fillPrivaciesButtons(
not_null<Ui::VerticalLayout*> parent,
std::optional<Privacy> savedValue) {
const auto canEditUsername = [&] {
if (const auto chat = _peer->asChat()) {
return chat->canEditUsername();
} else if (const auto channel = _peer->asChannel()) {
return channel->canEditUsername();
}
Unexpected("Peer type in Controller::createPrivaciesEdit.");
}();
if (!canEditUsername) {
return;
}
const auto result = parent->add(object_ptr<Ui::PaddingWrap<Ui::VerticalLayout>>(
parent,
object_ptr<Ui::VerticalLayout>(parent),
st::editPeerPrivaciesMargins));
auto container = result->entity();
const auto isPublic = _peer->isChannel()
&& _peer->asChannel()->isPublic();
_controls.privacy = std::make_shared<Ui::RadioenumGroup<Privacy>>(
savedValue.value_or(isPublic ? Privacy::Public : Privacy::Private));
addRoundButton(
container,
Privacy::Public,
lng_create_public_group_title,
lng_create_public_channel_title,
lng_create_public_group_about,
lng_create_public_channel_about);
addRoundButton(
container,
Privacy::Private,
lng_create_private_group_title,
lng_create_private_channel_title,
lng_create_private_group_about,
lng_create_private_channel_about);
_controls.privacy->setChangedCallback([=](Privacy value) {
privacyChanged(value);
});
if (!isPublic) {
// checkUsernameAvailability();
}
// return std::move(result);
}
void Controller::setFocusUsername() {
if (_controls.usernameInput) {
_controls.usernameInput->setFocus();
}
}
QString Controller::getUsernameInput() {
return _controls.usernameInput->getLastText().trimmed();
}
QString Controller::inviteLinkText() {
if (const auto channel = _peer->asChannel()) {
return channel->inviteLink();
} else if (const auto chat = _peer->asChat()) {
return chat->inviteLink();
}
return QString();
}
object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
Expects(_wrap != nullptr);
const auto channel = _peer->asChannel();
const auto username = usernameSavedValue.value_or(channel ? channel->username : QString());
const auto username = _usernameSavedValue.value_or(channel ? channel->username : QString());
auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_wrap,
object_ptr<Ui::VerticalLayout>(_wrap),
st::editPeerUsernameMargins);
usernameWrap = result.data();
_controls.usernameWrap = result.data();
auto container = result->entity();
container->add(object_ptr<Ui::FlatLabel>(
container->add(object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
container,
Lang::Viewer(lng_create_group_link),
st::editPeerSectionLabel));
object_ptr<Ui::FlatLabel>(
container,
Lang::Viewer(lng_create_group_link),
st::editPeerSectionLabel),
st::editPeerUsernameTitleLabelMargins));
auto placeholder = container->add(object_ptr<Ui::RpWidget>(
container));
placeholder->setAttribute(Qt::WA_TransparentForMouseEvents);
usernameInput = Ui::AttachParentChild(
_controls.usernameInput = Ui::AttachParentChild(
container,
object_ptr<Ui::UsernameInput>(
container,
@ -393,24 +336,32 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
Fn<QString()>(),
username,
true));
usernameInput->heightValue(
_controls.usernameInput->heightValue(
) | rpl::start_with_next([placeholder](int height) {
placeholder->resize(placeholder->width(), height);
}, placeholder->lifetime());
placeholder->widthValue(
) | rpl::start_with_next([this](int width) {
usernameInput->resize(
_controls.usernameInput->resize(
width,
usernameInput->height());
_controls.usernameInput->height());
}, placeholder->lifetime());
usernameInput->move(placeholder->pos());
_controls.usernameInput->move(placeholder->pos());
container->add(object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
container,
object_ptr<Ui::FlatLabel>(
container,
Lang::Viewer(lng_create_channel_link_about),
st::editPeerPrivacyLabel),
st::editPeerUsernameAboutLabelMargins));
QObject::connect(
usernameInput,
_controls.usernameInput,
&Ui::UsernameInput::changed,
[this] { usernameChanged(); });
auto shown = (privacyButtons->value() == Privacy::Public);
auto shown = (_controls.privacy->value() == Privacy::Public);
result->toggle(shown, anim::type::instant);
return std::move(result);
@ -418,7 +369,7 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
void Controller::privacyChanged(Privacy value) {
auto toggleEditUsername = [&] {
usernameWrap->toggle(
_controls.usernameWrap->toggle(
(value == Privacy::Public),
anim::type::instant);
};
@ -431,7 +382,7 @@ void Controller::privacyChanged(Privacy value) {
refreshEditInviteLink();
toggleEditUsername();
usernameResult = nullptr;
_controls.usernameResult = nullptr;
checkUsernameAvailability();
} else {
toggleEditUsername();
@ -444,29 +395,29 @@ void Controller::privacyChanged(Privacy value) {
askUsernameRevoke();
return;
} else if (_usernameState == UsernameState::NotAvailable) {
privacyButtons->setValue(Privacy::Private);
_controls.privacy->setValue(Privacy::Private);
return;
}
refreshVisibilities();
usernameInput->setDisplayFocused(true);
SetFocusUsername();
// _box->scrollToWidget(usernameInput);
_controls.usernameInput->setDisplayFocused(true);
setFocusUsername();
// _box->scrollToWidget(_controls.usernameInput);
} else {
request(base::take(_checkUsernameRequestId)).cancel();
_checkUsernameTimer.cancel();
refreshVisibilities();
SetFocusUsername();
setFocusUsername();
}
}
void Controller::checkUsernameAvailability() {
if (!usernameInput) {
if (!_controls.usernameInput) {
return;
}
auto initial = (privacyButtons->value() != Privacy::Public);
auto initial = (_controls.privacy->value() != Privacy::Public);
auto checking = initial
? qsl(".bad.")
: GetUsernameInput();
: getUsernameInput();
if (checking.size() < kMinUsernameLength) {
return;
}
@ -495,17 +446,17 @@ void Controller::checkUsernameAvailability() {
_usernameState = UsernameState::Normal;
if (type == qstr("CHANNEL_PUBLIC_GROUP_NA")) {
_usernameState = UsernameState::NotAvailable;
privacyButtons->setValue(Privacy::Private);
_controls.privacy->setValue(Privacy::Private);
} else if (type == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) {
_usernameState = UsernameState::TooMany;
if (privacyButtons->value() == Privacy::Public) {
if (_controls.privacy->value() == Privacy::Public) {
askUsernameRevoke();
}
} else if (initial) {
if (privacyButtons->value() == Privacy::Public) {
usernameResult = nullptr;
SetFocusUsername();
// _box->scrollToWidget(usernameInput);
if (_controls.privacy->value() == Privacy::Public) {
_controls.usernameResult = nullptr;
setFocusUsername();
// _box->scrollToWidget(_controls.usernameInput);
}
} else if (type == qstr("USERNAME_INVALID")) {
showUsernameError(
@ -519,10 +470,10 @@ void Controller::checkUsernameAvailability() {
}
void Controller::askUsernameRevoke() {
privacyButtons->setValue(Privacy::Private);
_controls.privacy->setValue(Privacy::Private);
auto revokeCallback = crl::guard(this, [this] {
_usernameState = UsernameState::Normal;
privacyButtons->setValue(Privacy::Public);
_controls.privacy->setValue(Privacy::Public);
checkUsernameAvailability();
});
Ui::show(
@ -531,10 +482,10 @@ void Controller::askUsernameRevoke() {
}
void Controller::usernameChanged() {
allowSave = false;
auto username = GetUsernameInput();
_isAllowSave = false;
auto username = getUsernameInput();
if (username.isEmpty()) {
usernameResult = nullptr;
_controls.usernameResult = nullptr;
_checkUsernameTimer.cancel();
return;
}
@ -551,7 +502,7 @@ void Controller::usernameChanged() {
showUsernameError(
Lang::Viewer(lng_create_channel_link_too_short));
} else {
usernameResult = nullptr;
_controls.usernameResult = nullptr;
_checkUsernameTimer.callOnce(kUsernameCheckTimeout);
}
}
@ -561,7 +512,7 @@ void Controller::showUsernameError(rpl::producer<QString> &&error) {
}
void Controller::showUsernameGood() {
allowSave = true;
_isAllowSave = true;
showUsernameResult(
Lang::Viewer(lng_create_channel_link_available),
&st::editPeerUsernameGood);
@ -570,14 +521,14 @@ void Controller::showUsernameGood() {
void Controller::showUsernameResult(
rpl::producer<QString> &&text,
not_null<const style::FlatLabel*> st) {
if (!usernameResult
|| usernameResultStyle != st) {
usernameResultStyle = st;
usernameResult = base::make_unique_q<Ui::FlatLabel>(
usernameWrap,
if (!_controls.usernameResult
|| _controls.usernameResultStyle != st) {
_controls.usernameResultStyle = st;
_controls.usernameResult = base::make_unique_q<Ui::FlatLabel>(
_controls.usernameWrap,
_usernameResultTexts.events() | rpl::flatten_latest(),
*st);
auto label = usernameResult.get();
auto label = _controls.usernameResult.get();
label->show();
label->widthValue(
) | rpl::start_with_next([label] {
@ -625,7 +576,7 @@ bool Controller::canEditInviteLink() const {
}
void Controller::observeInviteLink() {
if (!_editInviteLinkWrap) {
if (!_controls.editInviteLinkWrap) {
return;
}
// return; //
@ -635,7 +586,7 @@ void Controller::observeInviteLink() {
) | rpl::start_with_next([=] {
refreshCreateInviteLink();
refreshEditInviteLink();
}, _editInviteLinkWrap->lifetime());
}, _controls.editInviteLinkWrap->lifetime());
}
object_ptr<Ui::RpWidget> Controller::createInviteLinkEdit() {
@ -648,26 +599,28 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkEdit() {
auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_wrap,
object_ptr<Ui::VerticalLayout>(_wrap),
st::editPeerInviteLinkMargins);
_editInviteLinkWrap = result.data();
st::editPeerInvitesMargins);
_controls.editInviteLinkWrap = result.data();
auto container = result->entity();
container->add(object_ptr<Ui::FlatLabel>(
container,
Lang::Viewer(lng_profile_invite_link_section),
st::editPeerSectionLabel));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerInviteLinkSkip));
if (!_isInviteLink) {
container->add(object_ptr<Ui::FlatLabel>(
container,
Lang::Viewer(lng_profile_invite_link_section),
st::editPeerSectionLabel));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerInviteLinkBoxBottomSkip));
}
inviteLink = container->add(object_ptr<Ui::FlatLabel>(
_controls.inviteLink = container->add(object_ptr<Ui::FlatLabel>(
container,
st::editPeerInviteLink));
inviteLink->setSelectable(true);
inviteLink->setContextCopyText(QString());
inviteLink->setBreakEverywhere(true);
inviteLink->setClickHandlerFilter([=](auto&&...) {
QApplication::clipboard()->setText(InviteLinkText());
_controls.inviteLink->setSelectable(true);
_controls.inviteLink->setContextCopyText(QString());
_controls.inviteLink->setBreakEverywhere(true);
_controls.inviteLink->setClickHandlerFilter([=](auto&&...) {
QApplication::clipboard()->setText(inviteLinkText());
Ui::Toast::Show(lang(lng_group_invite_copied));
return false;
});
@ -687,7 +640,7 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkEdit() {
}
void Controller::refreshEditInviteLink() {
auto link = InviteLinkText();
auto link = inviteLinkText();
auto text = TextWithEntities();
if (!link.isEmpty()) {
text.text = link;
@ -701,13 +654,13 @@ void Controller::refreshEditInviteLink() {
text.text.size(),
link));
}
inviteLink->setMarkedText(text);
_controls.inviteLink->setMarkedText(text);
// Hack to expand FlatLabel width to naturalWidth again.
_editInviteLinkWrap->resizeToWidth(st::boxWideWidth);
_controls.editInviteLinkWrap->resizeToWidth(st::boxWideWidth);
_editInviteLinkWrap->toggle(
InviteLinkShown() && !link.isEmpty(),
_controls.editInviteLinkWrap->toggle(
inviteLinkShown() && !link.isEmpty(),
anim::type::instant);
}
@ -721,16 +674,18 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkCreate() {
auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_wrap,
object_ptr<Ui::VerticalLayout>(_wrap),
st::editPeerInviteLinkMargins);
st::editPeerInvitesMargins);
auto container = result->entity();
container->add(object_ptr<Ui::FlatLabel>(
container,
Lang::Viewer(lng_profile_invite_link_section),
st::editPeerSectionLabel));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerInviteLinkSkip));
if (!_isInviteLink) {
container->add(object_ptr<Ui::FlatLabel>(
container,
Lang::Viewer(lng_profile_invite_link_section),
st::editPeerSectionLabel));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::editPeerInviteLinkSkip));
}
container->add(object_ptr<Ui::LinkButton>(
_wrap,
@ -739,7 +694,7 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkCreate() {
)->addClickHandler([this] {
createInviteLink();
});
createInviteLinkWrap = result.data();
_controls.createInviteLinkWrap = result.data();
observeInviteLink();
@ -747,65 +702,72 @@ object_ptr<Ui::RpWidget> Controller::createInviteLinkCreate() {
}
void Controller::refreshCreateInviteLink() {
createInviteLinkWrap->toggle(
InviteLinkShown() && InviteLinkText().isEmpty(),
_controls.createInviteLinkWrap->toggle(
inviteLinkShown() && inviteLinkText().isEmpty(),
anim::type::instant);
}
bool Controller::inviteLinkShown() {
return !_controls.privacy
|| (_controls.privacy->value() == Privacy::Private)
|| _isInviteLink;
}
} // namespace
EditPeerTypeBox::EditPeerTypeBox(
QWidget*,
not_null<PeerData*> p,
not_null<PeerData*> peer,
FnMut<void(Privacy, QString)> savedCallback,
std::optional<Privacy> privacySaved,
std::optional<QString> usernameSaved)
: _peer(p)
, _savedCallback(std::move(savedCallback)) {
peer = p;
privacySavedValue = privacySaved;
usernameSavedValue = usernameSaved;
allowSave = !usernameSaved->isEmpty() && usernameSaved.has_value();
: _peer(peer)
, _savedCallback(std::move(savedCallback))
, _privacySavedValue(privacySaved)
, _usernameSavedValue(usernameSaved) {
}
void EditPeerTypeBox::prepare() {
_peer->updateFull();
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
setTitle(langFactory((peer->isChat() || peer->isMegagroup())
? lng_manage_peer_group_type
: lng_manage_peer_channel_type));
auto controller = Ui::CreateChild<Controller>(
this,
content,
_peer,
_privacySavedValue,
_usernameSavedValue);
_focusRequests.events(
) | rpl::start_with_next(
[=] { controller->setFocusUsername(); },
lifetime());
controller->createContent();
addButton(langFactory(lng_settings_save), [=] {
const auto v = privacyButtons->value();
if (!allowSave && (v == Privacy::Public)) {
SetFocusUsername();
return;
}
setTitle(langFactory(controller->getTitle()));
auto local = std::move(_savedCallback);
local(v,
(v == Privacy::Public)
? GetUsernameInput()
: QString()); // We dont need username with private type.
closeBox();
});
addButton(langFactory(lng_cancel), [=] { closeBox(); });
if (!controller->isInviteLink()) {
addButton(langFactory(lng_settings_save), [=] {
const auto v = controller->getPrivacy();
if (!controller->isAllowSave() && (v == Privacy::Public)) {
controller->setFocusUsername();
return;
}
setupContent();
auto local = std::move(_savedCallback);
local(v,
(v == Privacy::Public)
? controller->getUsernameInput()
: QString()); // We dont need username with private type.
closeBox();
});
}
addButton(langFactory(controller->isInviteLink() ? lng_close : lng_cancel), [=] { closeBox(); });
setDimensionsToContent(st::boxWideWidth, content);
}
void EditPeerTypeBox::setupContent() {
isGroup = (_peer->isChat() || _peer->isMegagroup());
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
FillContent(content, _peer, privacySavedValue);
auto controller = Ui::CreateChild<Controller>(this, content, _peer);
_focusRequests.events(
) | rpl::start_with_next(
[=] { SetFocusUsername(); },
lifetime());
controller->createContent();
// setDimensionsToContent(st::boxWidth, content);
setDimensionsToContent(st::boxWideWidth, content);
}

View File

@ -54,6 +54,9 @@ private:
not_null<PeerData*> _peer;
FnMut<void(Privacy, QString)> _savedCallback;
std::optional<Privacy> _privacySavedValue = std::nullopt;
std::optional<QString> _usernameSavedValue = std::nullopt;
rpl::event_stream<> _focusRequests;
};

View File

@ -639,9 +639,12 @@ infoEmptyLabel: FlatLabel(defaultFlatLabel) {
textFg: windowSubTextFg;
}
editPeerBottomButtonsLayoutMargins: margins(0px, 11px, 0px, 7px);
editPeerBottomButtonsLayoutMargins: margins(0px, 7px, 0px, 0px);
editPeerTopButtonsLayoutMargins: margins(0px, 12px, 0px, 6px);
editPeerTopButtonsLayoutSkip: 13px;
editPeerTopButtonsLayoutSkipToBottom: 12px;
editPeerHistoryVisibilityTopSkip: 8px;
editPeerDeleteButtonMargins: margins(23px, 16px, 23px, 16px);
@ -651,15 +654,20 @@ editPeerTitle: defaultInputField;
editPeerTitleMargins: margins(27px, 21px, 23px, 8px);
editPeerDescription: newGroupDescription;
editPeerDescriptionMargins: margins(23px, 5px, 23px, 16px);
editPeerPrivaciesMargins: margins(15px, 0px, 23px, 0px);
editPeerPrivaciesMargins: margins(15px, 7px, 23px, 0px);
editPeerPrivacyTopSkip: 10px;
editPeerPrivacyBottomSkip: 16px;
editPeerPrivacyLabel: FlatLabel(defaultFlatLabel) {
minWidth: 220px;
textFg: windowSubTextFg;
}
editPeerPrivacyBoxCheckbox: Checkbox(defaultBoxCheckbox) {
margin: margins(0px, 8px, 0px, 8px);
style: boxTextStyle;
}
editPeerHistoryVisibilityLabelMargins: margins(34px, 0px, 48px, 0px);
editPeerPrivacyLabelMargins: margins(34px, 0px, 34px, 0px);
editPeerPrivacyLabelMargins: margins(42px, 0px, 34px, 0px);
editPeerPreHistoryLabelMargins: margins(34px, 0px, 34px, 0px);
editPeerSectionLabel: FlatLabel(boxTitle) {
style: TextStyle(defaultTextStyle) {
font: font(15px semibold);
@ -667,6 +675,8 @@ editPeerSectionLabel: FlatLabel(boxTitle) {
linkFontOver: font(15px semibold underline);
}
}
editPeerUsernameTitleLabelMargins: margins(0px, 0px, 0px, 10px);
editPeerUsernameAboutLabelMargins: margins(0px, 15px, 34px, 15px);
editPeerUsername: setupChannelLink;
editPeerUsernameSkip: 8px;
editPeerInviteLink: FlatLabel(defaultFlatLabel) {
@ -674,7 +684,7 @@ editPeerInviteLink: FlatLabel(defaultFlatLabel) {
style: boxTextStyle;
}
editPeerInviteLinkButton: boxLinkButton;
editPeerUsernameMargins: margins(15px, 2px, 35px, 2px);
editPeerUsernameMargins: margins(23px, 17px, 23px, 2px);
editPeerUsernameGood: FlatLabel(defaultFlatLabel) {
textFg: boxTextFgGood;
style: boxTextStyle;
@ -682,12 +692,12 @@ editPeerUsernameGood: FlatLabel(defaultFlatLabel) {
editPeerUsernameError: FlatLabel(editPeerUsernameGood) {
textFg: boxTextFgError;
}
editPeerUsernamePosition: point(35px, 3px);
editPeerUsernamePosition: point(23px, 18px);
editPeerInviteLinkSkip: 10px;
editPeerInviteLinkMargins: margins(15px, 10px, 14px, 16px);
editPeerInvitesMargins: margins(23px, 10px, 23px, 16px);
editPeerInvitesMargins: margins(23px, 17px, 23px, 16px);
editPeerInvitesTopSkip: 10px;
editPeerInvitesSkip: 10px;
editPeerInviteLinkBoxBottomSkip: 15px;
historyTopBarBack: IconButton(infoTopBarBack) {
width: 52px;