| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- /*
- 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 "core/phone_click_handler.h"
- #include "boxes/add_contact_box.h"
- #include "core/click_handler_types.h"
- #include "data/data_session.h"
- #include "data/data_user.h"
- #include "info/profile/info_profile_values.h"
- #include "lang/lang_keys.h"
- #include "main/main_session.h"
- #include "mainwidget.h"
- #include "mtproto/sender.h"
- #include "ui/effects/ripple_animation.h"
- #include "ui/painter.h"
- #include "ui/rect.h"
- #include "ui/widgets/menu/menu_item_base.h"
- #include "ui/widgets/popup_menu.h"
- #include "window/window_controller.h"
- #include "window/window_session_controller.h"
- #include "styles/style_calls.h"
- #include "styles/style_chat.h" // popupMenuExpandedSeparator.
- #include "styles/style_menu_icons.h"
- namespace {
- [[nodiscard]] QString Trim(QString text) {
- return text
- .replace('+', QString())
- .replace(' ', QString())
- .replace('-', QString());
- }
- class ResolvePhoneAction final : public Ui::Menu::ItemBase {
- public:
- ResolvePhoneAction(
- not_null<Ui::RpWidget*> parent,
- const style::Menu &st,
- const QString &phone,
- not_null<Window::SessionController*> controller);
- bool isEnabled() const override;
- not_null<QAction*> action() const override;
- void handleKeyPress(not_null<QKeyEvent*> e) override;
- [[nodiscard]] QString firstName() const;
- [[nodiscard]] QString lastName() const;
- protected:
- QPoint prepareRippleStartPosition() const override;
- QImage prepareRippleMask() const override;
- int contentHeight() const override;
- private:
- void prepare();
- void paint(Painter &p);
- const not_null<QAction*> _dummyAction;
- const style::Menu &_st;
- rpl::variable<PeerData*> _peer;
- rpl::variable<bool> _loaded;
- Ui::PeerUserpicView _userpicView;
- MTP::Sender _api;
- Ui::Text::String _above;
- Ui::Text::String _below;
- int _aboveWidth = 0;
- int _belowWidth = 0;
- const int _height = 0;
- };
- ResolvePhoneAction::ResolvePhoneAction(
- not_null<Ui::RpWidget*> parent,
- const style::Menu &st,
- const QString &phone,
- not_null<Window::SessionController*> controller)
- : ItemBase(parent, st)
- , _dummyAction(new QAction(parent))
- , _st(st)
- , _api(&controller->session().mtp())
- , _height(rect::m::sum::v(st::groupCallJoinAsPadding)
- + st::groupCallJoinAsPhotoSize) {
- setAcceptBoth(true);
- initResizeHook(parent->sizeValue());
- setClickedCallback([=] {
- if (const auto peer = _peer.current()) {
- controller->showPeerInfo(peer);
- }
- });
- const auto formattedPhone = Trim(phone);
- const auto owner = &controller->session().data();
- if (const auto peer = owner->userByPhone(formattedPhone)) {
- _peer = peer;
- _loaded.force_assign(true);
- } else {
- _api.request(MTPcontacts_ResolvePhone(
- MTP_string(phone)
- )).done([=](const MTPcontacts_ResolvedPeer &result) {
- result.match([&](const MTPDcontacts_resolvedPeer &data) {
- owner->processUsers(data.vusers());
- owner->processChats(data.vchats());
- if (const auto peerId = peerFromMTP(data.vpeer())) {
- _peer = owner->peer(peerId);
- }
- _loaded.force_assign(true);
- });
- }).fail([=](const MTP::Error &error) {
- if (error.code() == 400) {
- _peer.force_assign(nullptr);
- _loaded.force_assign(true);
- }
- }).send();
- }
- paintRequest(
- ) | rpl::start_with_next([=] {
- Painter p(this);
- paint(p);
- }, lifetime());
- enableMouseSelecting();
- prepare();
- }
- QString ResolvePhoneAction::firstName() const {
- const auto peer = _peer.current();
- const auto user = peer ? peer->asUser() : nullptr;
- return user ? user->firstName : QString();
- }
- QString ResolvePhoneAction::lastName() const {
- const auto peer = _peer.current();
- const auto user = peer ? peer->asUser() : nullptr;
- return user ? user->lastName : QString();
- }
- void ResolvePhoneAction::paint(Painter &p) {
- const auto selected = isSelected() && _peer.current();
- const auto height = contentHeight();
- if (selected && _st.itemBgOver->c.alpha() < 255) {
- p.fillRect(0, 0, width(), height, _st.itemBg);
- }
- p.fillRect(0, 0, width(), height, selected ? _st.itemBgOver : _st.itemBg);
- if (isEnabled()) {
- paintRipple(p, 0, 0);
- }
- const auto &padding = st::groupCallJoinAsPadding;
- const auto textLeft = padding.left()
- + st::groupCallJoinAsPhotoSize
- + padding.left();
- if (const auto peer = _peer.current()) {
- peer->paintUserpic(
- p,
- _userpicView,
- padding.left(),
- padding.top(),
- st::groupCallJoinAsPhotoSize);
- p.setPen(selected ? _st.itemFgOver : _st.itemFg);
- _above.drawLeftElided(
- p,
- textLeft,
- st::groupCallJoinAsTextTop,
- width() - textLeft - padding.right(),
- width());
- p.setPen(selected ? _st.itemFgShortcutOver : _st.itemFgShortcut);
- _below.drawLeftElided(
- p,
- textLeft,
- st::groupCallJoinAsNameTop,
- _belowWidth,
- width());
- } else {
- p.setPen(selected ? _st.itemFgShortcutOver : _st.itemFgShortcut);
- const auto w = width() - padding.left() - padding.right();
- _below.draw(p, Ui::Text::PaintContext{
- .position = QPoint(
- (width() - w) / 2,
- (height - _below.countHeight(w)) / 2),
- .outerWidth = w,
- .availableWidth = w,
- .align = style::al_center,
- .elisionLines = 2,
- });
- }
- }
- void ResolvePhoneAction::prepare() {
- rpl::combine(
- tr::lng_context_view_profile(),
- _peer.value(
- ) | rpl::map([](PeerData *peer) {
- return peer
- ? Info::Profile::NameValue(peer)
- : rpl::single(QString());
- }) | rpl::flatten_latest(),
- tr::lng_menu_not_contact(),
- _loaded.value(
- ) | rpl::map([](bool loaded) {
- return loaded
- ? rpl::single(QString())
- : tr::lng_contacts_loading();
- }) | rpl::flatten_latest()
- ) | rpl::start_with_next([=](
- QString text,
- QString name,
- QString no,
- QString loading) {
- const auto &padding = st::groupCallJoinAsPadding;
- QWidget::setAttribute(
- Qt::WA_TransparentForMouseEvents,
- !_peer.current());
- const auto above = name;
- const auto below = !loading.isEmpty()
- ? loading
- : name.isEmpty()
- ? no
- : text;
- const auto options = kDefaultTextOptions;
- const auto tempWidth = [&] {
- _below.setMarkedText(_st.itemStyle, { text }, options);
- return _below.maxWidth();
- }();
- const auto textLeft = padding.left()
- + st::groupCallJoinAsPhotoSize
- + padding.left();
- const auto w = std::clamp(
- (textLeft + tempWidth + padding.right()),
- _st.widthMin,
- _st.widthMax);
- if (!no.isEmpty()) {
- _below = Ui::Text::String(w);
- }
- _above.setMarkedText(_st.itemStyle, { above }, options);
- _below.setMarkedText(_st.itemStyle, { below }, options);
- setMinWidth(w);
- _aboveWidth = w - textLeft - padding.right();
- _belowWidth = w
- - ((loading.isEmpty() && name.isEmpty()) ? 0 : textLeft)
- - padding.right();
- update();
- }, lifetime());
- }
- bool ResolvePhoneAction::isEnabled() const {
- return true;
- }
- not_null<QAction*> ResolvePhoneAction::action() const {
- return _dummyAction;
- }
- QPoint ResolvePhoneAction::prepareRippleStartPosition() const {
- return mapFromGlobal(QCursor::pos());
- }
- QImage ResolvePhoneAction::prepareRippleMask() const {
- return Ui::RippleAnimation::RectMask(size());
- }
- int ResolvePhoneAction::contentHeight() const {
- return _height;
- }
- void ResolvePhoneAction::handleKeyPress(not_null<QKeyEvent*> e) {
- if (!isSelected() || !_peer.current()) {
- return;
- }
- const auto key = e->key();
- if (key == Qt::Key_Enter || key == Qt::Key_Return) {
- setClicked(Ui::Menu::TriggeredSource::Keyboard);
- }
- }
- } // namespace
- PhoneClickHandler::PhoneClickHandler(
- not_null<Main::Session*> session,
- QString text)
- : _session(session)
- , _text(text) {
- setProperty(kPhoneNumberLinkProperty, _text);
- }
- void PhoneClickHandler::onClick(ClickContext context) const {
- if (context.button != Qt::LeftButton) {
- return;
- }
- const auto my = context.other.value<ClickHandlerContext>();
- const auto controller = my.sessionWindow.get();
- const auto pos = QCursor::pos();
- if (!controller) {
- return;
- }
- const auto menu = Ui::CreateChild<Ui::PopupMenu>(
- controller->content(),
- st::popupMenuWithIcons);
- const auto phone = _text;
- #if 0
- const auto maybeContact = [&]() -> PeerData* {
- const auto &chats = controller->session().data().contactsList();
- for (const auto &row : chats->all()) {
- if (const auto history = row->history()) {
- if (const auto user = history->peer->asUser()) {
- if (Trim(user->phone()) == Trim(phone)) {
- return user;
- }
- }
- }
- }
- return nullptr;
- }();
- #endif
- menu->addAction(tr::lng_profile_copy_phone(tr::now), [=] {
- TextUtilities::SetClipboardText(
- TextForMimeData::Simple(phone.trimmed()));
- }, &st::menuIconCopy);
- auto resolvePhoneAction = base::make_unique_q<ResolvePhoneAction>(
- menu,
- menu->st().menu,
- phone,
- controller);
- if (Trim(phone) != Trim(controller->session().user()->phone())) {
- menu->addAction(
- tr::lng_info_add_as_contact(tr::now),
- [=, raw = Ui::MakeWeak(resolvePhoneAction.get())] {
- controller->show(
- Box<AddContactBox>(
- &controller->session(),
- raw ? raw->firstName() : QString(),
- raw ? raw->lastName() : QString(),
- Trim(phone)));
- },
- &st::menuIconInvite);
- }
- menu->addSeparator(&st::popupMenuExpandedSeparator.menu.separator);
- menu->addAction(std::move(resolvePhoneAction));
- menu->popup(pos);
- }
- auto PhoneClickHandler::getTextEntity() const -> TextEntity {
- return { EntityType::Phone };
- }
- QString PhoneClickHandler::tooltip() const {
- return _text;
- }
|