diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 4f9d82cfd..ab7450ff4 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -77,6 +77,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_month_year" = "{month} {year}"; "lng_box_ok" = "OK"; +"lng_box_done" = "Done"; "lng_cancel" = "Cancel"; "lng_continue" = "Continue"; @@ -1409,6 +1410,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_contact_phone" = "Phone Number"; "lng_enter_contact_data" = "New Contact"; +"lng_contact_mobile_hidden" = "Mobile hidden"; +"lng_contact_phone_after" = "Phone number will be visible once {user} adds you as a contact. Your phone number will become visible to {name}."; +"lng_contact_phone_show" = "When you click {button}, your phone number will become visible to {user}."; "lng_edit_contact_title" = "Edit contact name"; "lng_edit_channel_title" = "Edit channel"; "lng_edit_sign_messages" = "Sign messages"; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 1be3d4083..2d98862e2 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -977,3 +977,6 @@ urlAuthCheckbox: Checkbox(defaultBoxCheckbox) { linkedChatAbout: membersAbout; linkedChatAboutPadding: margins(20px, 20px, 20px, 20px); + +addContactFieldMargin: margins(19px, 0px, 19px, 10px); +addContactWarningMargin: margins(19px, 10px, 19px, 5px); diff --git a/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.cpp b/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.cpp new file mode 100644 index 000000000..b216c1e09 --- /dev/null +++ b/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.cpp @@ -0,0 +1,191 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "boxes/peers/add_to_contacts_box.h" + +#include "data/data_user.h" +#include "data/data_session.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/widgets/labels.h" +#include "ui/widgets/input_fields.h" +#include "info/profile/info_profile_cover.h" +#include "lang/lang_keys.h" +#include "window/window_controller.h" +#include "auth_session.h" +#include "apiwrap.h" +#include "styles/style_boxes.h" +#include "styles/style_info.h" + +namespace { + +QString UserPhone(not_null user) { + const auto phone = user->phone(); + return phone.isEmpty() + ? user->owner().findContactPhone(user->bareId()) + : phone; +} + +TextWithEntities BoldText(const QString &text) { + auto result = TextWithEntities{ text }; + result.entities.push_back({ EntityType::Bold, 0, text.size() }); + return result; +} + +} // namespace + +AddToContactsBox::AddToContactsBox( + QWidget*, + not_null window, + not_null user) +: _window(window) +, _user(user) +, _phone(UserPhone(user)) { +} + +void AddToContactsBox::prepare() { + setupContent(); + + setTitle(langFactory(lng_enter_contact_data)); + + addButton(langFactory(lng_box_done), [=] { _save(); }); + addButton(langFactory(lng_cancel), [=] { closeBox(); }); +} + +void AddToContactsBox::setInnerFocus() { + _focus(); +} + +void AddToContactsBox::setupContent() { + const auto content = Ui::CreateChild(this); + + setupCover(content); + setupNameFields(content); + setupWarning(content); + + setDimensionsToContent(st::boxWidth, content); +} + +void AddToContactsBox::setupCover(not_null container) { + container->add(object_ptr( + container, + _user, + _window->sessionController(), + (_phone.isEmpty() + ? Lang::Viewer(lng_contact_mobile_hidden) + : rpl::single(App::formatPhone(_phone)))) + )->setAttribute(Qt::WA_TransparentForMouseEvents); +} + +void AddToContactsBox::setupNameFields( + not_null container) { + const auto inverted = langFirstNameGoesSecond(); + const auto first = container->add( + object_ptr( + container, + st::defaultInputField, + langFactory(lng_signup_firstname), + _user->firstName), + st::addContactFieldMargin); + auto preparedLast = object_ptr( + container, + st::defaultInputField, + langFactory(lng_signup_lastname), + _user->lastName); + const auto last = inverted + ? container->insert( + container->count() - 1, + std::move(preparedLast), + st::addContactFieldMargin) + : container->add(std::move(preparedLast), st::addContactFieldMargin); + + initNameFields(first, last, inverted); +} + +void AddToContactsBox::initNameFields( + not_null first, + not_null last, + bool inverted) { + if (inverted) { + setTabOrder(last, first); + } + const auto submit = [=] { + const auto firstValue = first->getLastText().trimmed(); + const auto lastValue = last->getLastText().trimmed(); + const auto empty = firstValue.isEmpty() && lastValue.isEmpty(); + if (inverted ? last->hasFocus() : empty) { + first->setFocus(); + } else if (inverted ? empty : first->hasFocus()) { + last->setFocus(); + } else { + _save(); + } + }; + connect(first, &Ui::InputField::submitted, [=] { submit(); }); + connect(last, &Ui::InputField::submitted, [=] { submit(); }); + + _focus = [=] { + const auto firstValue = first->getLastText().trimmed(); + const auto lastValue = last->getLastText().trimmed(); + const auto empty = firstValue.isEmpty() && lastValue.isEmpty(); + const auto focusFirst = (inverted != empty); + (focusFirst ? first : last)->setFocusFast(); + }; + _save = [=] { + const auto firstValue = first->getLastText().trimmed(); + const auto lastValue = last->getLastText().trimmed(); + const auto empty = firstValue.isEmpty() && lastValue.isEmpty(); + if (empty) { + _focus(); + (inverted ? last : first)->showError(); + return; + } + const auto user = _user; + const auto box = make_weak(this); + user->session().api().request(MTPcontacts_AddContact( + MTP_flags(0), + user->inputUser, + MTP_string(firstValue), + MTP_string(lastValue), + MTP_string(_phone) + )).done([=](const MTPUpdates &result) { + user->session().api().applyUpdates(result); + if (const auto settings = user->settings()) { + using Flag = MTPDpeerSettings::Flag; + const auto flags = Flag::f_add_contact + | Flag::f_block_contact + | Flag::f_report_spam; + user->setSettings(*settings & ~flags); + } + if (box) { + box->closeBox(); + } + }).fail([=](const RPCError &error) { + }).send(); + }; +} + +void AddToContactsBox::setupWarning( + not_null container) { + const auto name = _user->firstName.isEmpty() + ? _user->lastName + : _user->firstName; + const auto text = _phone.isEmpty() + ? TextWithEntities{ + lng_contact_phone_after(lt_user, name, lt_name, name) + } + : lng_contact_phone_show__generic( + lt_button, + BoldText(lang(lng_box_done).toUpper()), + lt_user, + TextWithEntities{ name }); + container->add( + object_ptr( + container, + rpl::single(text), + st::changePhoneLabel), + st::addContactWarningMargin); +} \ No newline at end of file diff --git a/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.h b/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.h new file mode 100644 index 000000000..cd4e42e06 --- /dev/null +++ b/Telegram/SourceFiles/boxes/peers/add_to_contacts_box.h @@ -0,0 +1,50 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "boxes/abstract_box.h" + +class UserData; + +namespace Window { +class Controller; +} // namespace Window + +namespace Ui { +class VerticalLayout; +} // namespace Ui + +class AddToContactsBox : public BoxContent { +public: + AddToContactsBox( + QWidget*, + not_null window, + not_null user); + +protected: + void prepare() override; + + void setInnerFocus() override; + +private: + void setupContent(); + void setupCover(not_null container); + void setupNameFields(not_null container); + void setupWarning(not_null container); + void initNameFields( + not_null first, + not_null last, + bool inverted); + + not_null _window; + not_null _user; + QString _phone; + Fn _focus; + Fn _save; + +}; diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index f3011250a..8db6b060d 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -484,7 +484,7 @@ void ActionsFiller::addEditContactAction(not_null user) { _wrap, Lang::Viewer(lng_info_edit_contact), IsContactValue(user), - [user] { Ui::show(Box(user)); }); + [=] { Ui::show(Box(user)); }); } void ActionsFiller::addDeleteContactAction( diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 8cbb61f54..a1ebcb48c 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -212,6 +212,18 @@ Cover::Cover( QWidget *parent, not_null peer, not_null controller) +: Cover(parent, peer, controller, NameValue( + peer +) | rpl::map([=](const TextWithEntities &name) { + return name.text; +})) { +} + +Cover::Cover( + QWidget *parent, + not_null peer, + not_null controller, + rpl::producer title) : SectionWithToggle( parent, st::infoProfilePhotoTop @@ -240,7 +252,7 @@ Cover::Cover( _status->setAttribute(Qt::WA_TransparentForMouseEvents); } - initViewers(); + initViewers(std::move(title)); setupChildGeometry(); } @@ -270,12 +282,12 @@ Cover *Cover::setOnlineCount(rpl::producer &&count) { return this; } -void Cover::initViewers() { +void Cover::initViewers(rpl::producer title) { using Flag = Notify::PeerUpdate::Flag; - NameValue( - _peer - ) | rpl::start_with_next([=](const TextWithEntities &name) { - _name->setText(name.text); + std::move( + title + ) | rpl::start_with_next([=](const QString &title) { + _name->setText(title); refreshNameGeometry(width()); }, lifetime()); diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.h b/Telegram/SourceFiles/info/profile/info_profile_cover.h index c38462be0..6089cf1f3 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.h +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.h @@ -59,6 +59,11 @@ public: QWidget *parent, not_null peer, not_null controller); + Cover( + QWidget *parent, + not_null peer, + not_null controller, + rpl::producer title); Cover *setOnlineCount(rpl::producer &&count); @@ -75,7 +80,7 @@ public: private: void setupChildGeometry(); - void initViewers(); + void initViewers(rpl::producer title); void refreshStatusText(); void refreshNameGeometry(int newWidth); void refreshStatusGeometry(int newWidth); diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 381afd21b..060198644 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/report_box.h" #include "boxes/create_poll_box.h" #include "boxes/peers/add_participants_box.h" +#include "boxes/peers/add_to_contacts_box.h" #include "ui/toast/toast.h" #include "auth_session.h" #include "apiwrap.h" @@ -628,10 +629,7 @@ void PeerMenuDeleteContact(not_null user) { } void PeerMenuAddContact(not_null user) { - Ui::show(Box( - user->firstName, - user->lastName, - Auth().data().findContactPhone(user))); + Ui::show(Box(&App::wnd()->controller(), user)); } void PeerMenuShareContactBox(not_null user) { diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 5f01d4f20..49e608bf6 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -1,5 +1,7 @@ <(src_loc)/boxes/peers/add_participants_box.cpp <(src_loc)/boxes/peers/add_participants_box.h +<(src_loc)/boxes/peers/add_to_contacts_box.cpp +<(src_loc)/boxes/peers/add_to_contacts_box.h <(src_loc)/boxes/peers/edit_linked_chat_box.cpp <(src_loc)/boxes/peers/edit_linked_chat_box.h <(src_loc)/boxes/peers/edit_participant_box.cpp