From 3fdb807a1ed185e813218bab0ca258a90a43fb88 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 27 Nov 2022 15:32:13 +0300 Subject: [PATCH] Respected new error for occupied usernames in manage channel. --- Telegram/Resources/langs/lang.strings | 1 + .../SourceFiles/boxes/add_contact_box.cpp | 2 + .../boxes/peers/edit_peer_type_box.cpp | 77 +++++----- Telegram/SourceFiles/boxes/username_box.cpp | 139 ++++++++---------- Telegram/SourceFiles/boxes/username_box.h | 16 ++ Telegram/SourceFiles/info/info.style | 3 +- Telegram/lib_ui | 2 +- 7 files changed, 126 insertions(+), 114 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 45cf5728b..ace9ce30d 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1386,6 +1386,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_create_channel_link_too_short" = "Sorry, this link is too short"; "lng_create_channel_link_bad_symbols" = "Only 0-9, a-z, and underscores allowed."; "lng_create_channel_link_available" = "This link is available"; +"lng_create_channel_link_pending" = "Checking name..."; "lng_create_channel_link_copied" = "Link copied to clipboard"; "lng_create_group_crop" = "Select an area for group photo"; diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index 64c4169c0..e98af9634 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -1225,6 +1225,8 @@ SetupChannelBox::UsernameResult SetupChannelBox::parseError( return UsernameResult::Invalid; } else if (error == u"USERNAME_OCCUPIED"_q) { return UsernameResult::Occupied; + } else if (error == u"USERNAME_PURCHASE_AVAILABLE"_q) { + return UsernameResult::Occupied; } else if (error == u"USERNAMES_UNAVAILABLE"_q) { return UsernameResult::Occupied; } else if (error == u"CHANNEL_PUBLIC_GROUP_NA"_q) { diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp index 7b53ba217..d9a233936 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_peer_invite_link.h" #include "boxes/peers/edit_peer_invite_links.h" #include "boxes/peers/edit_peer_usernames_list.h" +#include "boxes/username_box.h" #include "chat_helpers/emoji_suggestions_widget.h" #include "data/data_channel.h" #include "data/data_chat.h" @@ -103,8 +104,7 @@ private: Ui::SlideWrap *usernameWrap = nullptr; Ui::UsernameInput *usernameInput = nullptr; UsernamesList *usernamesList = nullptr; - base::unique_qptr usernameResult; - const style::FlatLabel *usernameResultStyle = nullptr; + base::unique_qptr usernameCheckResult; Ui::SlideWrap<> *inviteLinkWrap = nullptr; Ui::FlatLabel *inviteLink = nullptr; @@ -127,9 +127,8 @@ private: void usernameChanged(); void showUsernameError(rpl::producer &&error); void showUsernameGood(); - void showUsernameResult( - rpl::producer &&text, - not_null st); + void showUsernamePending(); + void showUsernameEmpty(); void fillPrivaciesButtons( not_null parent, @@ -157,7 +156,9 @@ private: base::Timer _checkUsernameTimer; mtpRequestId _checkUsernameRequestId = 0; UsernameState _usernameState = UsernameState::Normal; - rpl::event_stream> _usernameResultTexts; + + rpl::event_stream _usernameCheckInfo; + rpl::lifetime _usernameCheckInfoLifetime; rpl::event_stream _scrollToRequests; @@ -450,6 +451,8 @@ object_ptr Controller::createUsernameEdit() { }, placeholder->lifetime()); _controls.usernameInput->move(placeholder->pos()); + AddUsernameCheckLabel(container, _usernameCheckInfo.events()); + AddDividerText( container, tr::lng_create_channel_link_about()); @@ -506,7 +509,7 @@ void Controller::privacyChanged(Privacy value) { toggleEditUsername(); toggleWhoSendWrap(); - _controls.usernameResult = nullptr; + showUsernameEmpty(); checkUsernameAvailability(); } else { toggleWhoSendWrap(); @@ -575,11 +578,16 @@ void Controller::checkUsernameAvailability() { } } else if (initial) { if (_controls.privacy->value() == Privacy::HasUsername) { - _controls.usernameResult = nullptr; + showUsernameEmpty(); setFocusUsername(); } } else if (type == u"USERNAME_INVALID"_q) { showUsernameError(tr::lng_create_channel_link_invalid()); + } else if (type == u"USERNAME_PURCHASE_AVAILABLE"_q) { + _goodUsername = false; + _usernameCheckInfo.fire({ + .type = UsernameCheckInfo::Type::PurchaseAvailable, + }); } else if (type == u"USERNAME_OCCUPIED"_q && checking != username) { showUsernameError(tr::lng_create_channel_link_occupied()); } @@ -602,7 +610,7 @@ void Controller::usernameChanged() { _goodUsername = false; const auto username = getUsernameInput(); if (username.isEmpty()) { - _controls.usernameResult = nullptr; + showUsernameEmpty(); _checkUsernameTimer.cancel(); return; } @@ -617,43 +625,44 @@ void Controller::usernameChanged() { } else if (username.size() < Ui::EditPeer::kMinUsernameLength) { showUsernameError(tr::lng_create_channel_link_too_short()); } else { - _controls.usernameResult = nullptr; + showUsernamePending(); _checkUsernameTimer.callOnce(Ui::EditPeer::kUsernameCheckTimeout); } } void Controller::showUsernameError(rpl::producer &&error) { _goodUsername = false; - showUsernameResult(std::move(error), &st::editPeerUsernameError); + _usernameCheckInfoLifetime.destroy(); + std::move( + error + ) | rpl::map([](QString s) { + return UsernameCheckInfo{ + .type = UsernameCheckInfo::Type::Error, + .text = { std::move(s) }, + }; + }) | rpl::start_to_stream(_usernameCheckInfo, _usernameCheckInfoLifetime); } void Controller::showUsernameGood() { _goodUsername = true; - showUsernameResult( - tr::lng_create_channel_link_available(), - &st::editPeerUsernameGood); + _usernameCheckInfoLifetime.destroy(); + _usernameCheckInfo.fire({ + .type = UsernameCheckInfo::Type::Good, + .text = { tr::lng_create_channel_link_available(tr::now) }, + }); } -void Controller::showUsernameResult( - rpl::producer &&text, - not_null st) { - if (!_controls.usernameResult - || _controls.usernameResultStyle != st) { - _controls.usernameResultStyle = st; - _controls.usernameResult = base::make_unique_q( - _controls.usernameWrap, - _usernameResultTexts.events() | rpl::flatten_latest(), - *st); - const auto label = _controls.usernameResult.get(); - label->show(); - label->widthValue( - ) | rpl::start_with_next([label] { - label->moveToRight( - st::editPeerUsernamePosition.x(), - st::editPeerUsernamePosition.y()); - }, label->lifetime()); - } - _usernameResultTexts.fire(std::move(text)); +void Controller::showUsernamePending() { + _usernameCheckInfoLifetime.destroy(); + _usernameCheckInfo.fire({ + .type = UsernameCheckInfo::Type::Default, + .text = { .text = tr::lng_create_channel_link_pending(tr::now) }, + }); +} + +void Controller::showUsernameEmpty() { + _usernameCheckInfoLifetime.destroy(); + _usernameCheckInfo.fire({ .type = UsernameCheckInfo::Type::Default }); } object_ptr Controller::createInviteLinkBlock() { diff --git a/Telegram/SourceFiles/boxes/username_box.cpp b/Telegram/SourceFiles/boxes/username_box.cpp index 24ddba564..ccdecc50c 100644 --- a/Telegram/SourceFiles/boxes/username_box.cpp +++ b/Telegram/SourceFiles/boxes/username_box.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/fields/special_fields.h" #include "ui/widgets/labels.h" +#include "ui/wrap/follow_slide_wrap.h" #include "ui/wrap/slide_wrap.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" @@ -31,16 +32,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { -struct CheckInfo final { - enum class Type { - Good, - Error, - Default, - PurchaseAvailable, - }; - Type type; - v::text::data text; -}; +[[nodiscard]] TextWithEntities PurchaseAvailableText() { + constexpr auto kUsernameAuction = "auction"; + return tr::lng_username_purchase_available( + tr::now, + lt_link, + Ui::Text::Link( + '@' + QString(kUsernameAuction), + u"https://t.me/"_q + kUsernameAuction), + Ui::Text::RichLangValue); +} class UsernameEditor final : public Ui::RpWidget { public: @@ -49,7 +50,7 @@ public: void setInnerFocus(); [[nodiscard]] rpl::producer<> submitted() const; [[nodiscard]] rpl::producer<> save(); - [[nodiscard]] rpl::producer checkInfoChanged() const; + [[nodiscard]] rpl::producer checkInfoChanged() const; protected: void resizeEvent(QResizeEvent *e) override; @@ -80,7 +81,7 @@ private: base::Timer _checkTimer; rpl::event_stream<> _saved; - rpl::event_stream _checkInfoChanged; + rpl::event_stream _checkInfoChanged; }; @@ -147,7 +148,7 @@ rpl::producer<> UsernameEditor::save() { return _saved.events(); } -rpl::producer UsernameEditor::checkInfoChanged() const { +rpl::producer UsernameEditor::checkInfoChanged() const { return _checkInfoChanged.events(); } @@ -184,7 +185,7 @@ void UsernameEditor::changed() { if (name.isEmpty()) { if (!_errorText.isEmpty() || !_goodText.isEmpty()) { _errorText = _goodText = QString(); - checkInfoChange(); + _checkInfoChanged.fire({ UsernameCheckInfo::Type::Default }); } _checkTimer.cancel(); } else { @@ -223,38 +224,29 @@ void UsernameEditor::changed() { void UsernameEditor::checkInfoChange() { if (!_errorText.isEmpty()) { _checkInfoChanged.fire({ - .type = CheckInfo::Type::Error, - .text = _errorText, + .type = UsernameCheckInfo::Type::Error, + .text = { _errorText }, }); } else if (!_goodText.isEmpty()) { _checkInfoChanged.fire({ - .type = CheckInfo::Type::Good, - .text = _goodText, + .type = UsernameCheckInfo::Type::Good, + .text = { _goodText }, }); } else { _checkInfoChanged.fire({ - .type = CheckInfo::Type::Default, - .text = tr::lng_username_choose(tr::now), + .type = UsernameCheckInfo::Type::Default, + .text = { tr::lng_username_choose(tr::now) }, }); } } void UsernameEditor::checkInfoPurchaseAvailable() { - constexpr auto kUsernameAuction = "auction"; - const auto text = tr::lng_username_purchase_available( - tr::now, - lt_link, - Ui::Text::Link( - '@' + QString(kUsernameAuction), - u"https://t.me/"_q + kUsernameAuction), - Ui::Text::RichLangValue); _username->setFocus(); _username->showError(); - _errorText = text.text; + _errorText = u".bad."_q; _checkInfoChanged.fire({ - .type = CheckInfo::Type::PurchaseAvailable, - .text = text, + .type = UsernameCheckInfo::Type::PurchaseAvailable, }); } @@ -320,52 +312,7 @@ void UsernamesBox( {}); box->setFocusCallback([=] { editor->setInnerFocus(); }); - { - const auto padding = st::boxRowPadding; - const auto &st = st::aboutRevokePublicLabel; - const auto skip = (st::usernameSkip - st.style.font->height) / 2; - - box->addSkip(skip); - const auto wrap = box->addRow( - object_ptr>( - box, - object_ptr(box)), - padding); - wrap->setMinimalHeight(st.style.font->height); - - const auto maxHeightWrap = wrap->entity(); - const auto label = Ui::CreateChild( - maxHeightWrap, - editor->checkInfoChanged( - ) | rpl::map([](CheckInfo info) { - return v::text::take_marked(base::take(info.text)); - }) | rpl::flatten_latest(), - st); - label->heightValue( - ) | rpl::start_with_next([=](int height) { - if (height > maxHeightWrap->height()) { - maxHeightWrap->resize(maxHeightWrap->width(), height); - } - }, maxHeightWrap->lifetime()); - - editor->checkInfoChanged( - ) | rpl::start_with_next([=](CheckInfo info) { - const auto &color = (info.type == CheckInfo::Type::Good) - ? st::boxTextFgGood - : (info.type == CheckInfo::Type::Error) - ? st::boxTextFgError - : st::usernameDefaultFg; - label->setTextColorOverride(color->c); - label->resizeToWidth(container->width() - - padding.left() - - padding.right()); - - wrap->toggle( - info.type == CheckInfo::Type::PurchaseAvailable, - anim::type::normal); - }, label->lifetime()); - box->addSkip(skip); - } + AddUsernameCheckLabel(container, editor->checkInfoChanged()); container->add(object_ptr( container, @@ -401,3 +348,41 @@ void UsernamesBox( box->addButton(tr::lng_settings_save(), finish); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); } + +void AddUsernameCheckLabel( + not_null container, + rpl::producer checkInfo) { + const auto padding = st::boxRowPadding; + const auto &st = st::aboutRevokePublicLabel; + const auto skip = (st::usernameSkip - st.style.font->height) / 4; + + auto wrapped = object_ptr(container); + Settings::AddSkip(wrapped, skip); + const auto label = wrapped->add(object_ptr(wrapped, st)); + Settings::AddSkip(wrapped, skip); + + Settings::AddSkip(container, skip); + const auto wrap = container->add( + object_ptr>( + container, + std::move(wrapped)), + padding); + + rpl::combine( + std::move(checkInfo), + container->widthValue() + ) | rpl::start_with_next([=](const UsernameCheckInfo &info, int w) { + using Type = UsernameCheckInfo::Type; + label->setMarkedText((info.type == Type::PurchaseAvailable) + ? PurchaseAvailableText() + : info.text); + const auto &color = (info.type == Type::Good) + ? st::boxTextFgGood + : (info.type == Type::Error) + ? st::boxTextFgError + : st::usernameDefaultFg; + label->setTextColorOverride(color->c); + label->resizeToWidth(w - padding.left() - padding.right()); + }, label->lifetime()); + Settings::AddSkip(container, skip); +} diff --git a/Telegram/SourceFiles/boxes/username_box.h b/Telegram/SourceFiles/boxes/username_box.h index 62ebc8a08..46183e3ef 100644 --- a/Telegram/SourceFiles/boxes/username_box.h +++ b/Telegram/SourceFiles/boxes/username_box.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { class GenericBox; +class VerticalLayout; } // namespace Ui namespace Main { @@ -18,3 +19,18 @@ class Session; void UsernamesBox( not_null box, not_null session); + +struct UsernameCheckInfo final { + enum class Type { + Good, + Error, + Default, + PurchaseAvailable, + }; + Type type; + TextWithEntities text; +}; + +void AddUsernameCheckLabel( + not_null container, + rpl::producer checkInfo); diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index f208d341b..a3684de9b 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -655,7 +655,7 @@ editPeerHistoryVisibilityLabelMargins: margins(34px, 0px, 48px, 0px); editPeerPrivacyLabelMargins: margins(42px, 0px, 34px, 0px); editPeerPreHistoryLabelMargins: margins(34px, 0px, 34px, 0px); editPeerUsernameTitleLabelMargins: margins(22px, 17px, 22px, 10px); -editPeerUsernameFieldMargins: margins(22px, 0px, 22px, 16px); +editPeerUsernameFieldMargins: margins(22px, 0px, 22px, 0px); editPeerUsername: setupChannelLink; editPeerUsernameSkip: 8px; editPeerInviteLink: FlatLabel(defaultFlatLabel) { @@ -669,7 +669,6 @@ editPeerUsernameGood: FlatLabel(defaultFlatLabel) { editPeerUsernameError: FlatLabel(editPeerUsernameGood) { textFg: boxTextFgError; } -editPeerUsernamePosition: point(22px, 18px); editPeerReactionsButton: SettingsButton(infoProfileButton) { padding: margins(59px, 13px, 8px, 11px); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 0937ac0ad..c197c1831 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 0937ac0ad0feaf3cbccf009e0e1f2a04cc0ef9f8 +Subproject commit c197c1831d1af48cf769f271a126af2c2eaf8185