diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 29c102382e..7cad39beb2 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1196,6 +1196,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_new_contact_block" = "Block user"; "lng_new_contact_add" = "Add contact"; "lng_new_contact_share" = "Share my phone number"; +"lng_new_contact_add_name" = "Add {user} to contacts"; "lng_cant_send_to_not_contact" = "Sorry, you can only send messages to\nmutual contacts at the moment.\n{more_info}"; "lng_cant_invite_not_contact" = "Sorry, you can only add mutual contacts\nto groups at the moment.\n{more_info}"; "lng_cant_more_info" = "More info ยป"; diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index adbec3df7f..8d3bb1e559 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -103,6 +103,9 @@ private: }; class PeerData { +private: + static constexpr auto kSettingsUnknown = MTPDpeerSettings::Flag(1U << 9); + protected: PeerData(not_null owner, PeerId id); PeerData(const PeerData &other) = delete; @@ -113,7 +116,8 @@ public: | MTPDpeerSettings::Flag::f_report_spam | MTPDpeerSettings::Flag::f_add_contact | MTPDpeerSettings::Flag::f_block_contact - | MTPDpeerSettings::Flag::f_share_contact; + | MTPDpeerSettings::Flag::f_share_contact + | kSettingsUnknown; using Settings = Data::Flags< MTPDpeerSettings::Flags, kEssentialSettings.value()>; @@ -365,9 +369,6 @@ private: crl::time _lastFullUpdate = 0; MsgId _pinnedMessageId = 0; - static constexpr auto kSettingsUnknown = MTPDpeerSettings::Flag(1U << 9); - static_assert(!(kEssentialSettings & kSettingsUnknown)); - Settings _settings = { kSettingsUnknown }; QString _about; diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style index d3083a9b84..ed7d7a7543 100644 --- a/Telegram/SourceFiles/history/history.style +++ b/Telegram/SourceFiles/history/history.style @@ -202,6 +202,19 @@ historyUnblock: FlatButton(historyComposeButton) { color: attentionButtonFg; overColor: attentionButtonFgOver; } +historyContactStatusButton: FlatButton(historyComposeButton) { + height: 49px; + textTop: 16px; + overBgColor: historyComposeButtonBg; + ripple: RippleAnimation(defaultRippleAnimation) { + color: historyComposeButtonBgOver; + } +} +historyContactStatusBlock: FlatButton(historyContactStatusButton) { + color: attentionButtonFg; + overColor: attentionButtonFg; +} +historyContactStatusMinSkip: 16px; historySendIcon: icon {{ "send_control_send", historySendIconFg }}; historySendIconOver: icon {{ "send_control_send", historySendIconFgOver }}; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b0e72e2568..80b45f97ba 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1686,6 +1686,10 @@ void HistoryWidget::showHistory( _contactStatus = std::make_unique( this, _peer); + _contactStatus->heightValue() | rpl::start_with_next([=] { + updateControlsGeometry(); + }, _contactStatus->lifetime()); + orderWidgets(); } else { _contactStatus = nullptr; } @@ -1847,8 +1851,8 @@ void HistoryWidget::updateNotifyControls() { _silent->setChecked(session().data().notifySilentPosts(_peer)); } else if (hasSilentToggle()) { refreshSilentToggle(); - updateControlsGeometry(); updateControlsVisibility(); + updateControlsGeometry(); } } } diff --git a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp index 116c5f4b24..cc433c4b57 100644 --- a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp +++ b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp @@ -16,11 +16,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "auth_session.h" #include "styles/style_history.h" -#include "styles/style_info.h" namespace HistoryView { namespace { +QString PeerFirstName(not_null peer) { + if (const auto user = peer->asUser()) { + return user->firstName; + } + return QString(); +} + bool BarCurrentlyHidden(not_null peer) { const auto settings = peer->settings(); if (!settings) { @@ -109,33 +115,112 @@ bool BarCurrentlyHidden(not_null peer) { // controller()->showBackFromStack(); //} -ContactStatus::Bar::Bar(QWidget *parent) +ContactStatus::Bar::Bar(QWidget *parent, const QString &name) : RpWidget(parent) -, _block(this, lang(lng_new_contact_block), st::historyUnblock) -, _add(this, lang(lng_new_contact_add), st::historyComposeButton) -, _share(this, lang(lng_new_contact_share), st::historyComposeButton) -, _report(this, lang(lng_report_spam), st::historyUnblock) -, _close(this, st::infoTopBarClose) { +, _name(name) +, _block( + this, + lang(lng_new_contact_block).toUpper(), + st::historyContactStatusBlock) +, _add( + this, + lang(lng_new_contact_add).toUpper(), + st::historyContactStatusButton) +, _share( + this, + lang(lng_new_contact_share).toUpper(), + st::historyContactStatusButton) +, _report( + this, + lang(lng_report_spam).toUpper(), + st::historyContactStatusBlock) +, _close(this, st::historyReplyCancel) { resize(_close->size()); } void ContactStatus::Bar::showState(State state) { - _add->setVisible(state == State::BlockOrAdd); - _block->setVisible(state == State::BlockOrAdd); + _add->setVisible(state == State::AddOrBlock || state == State::Add); + _block->setVisible(state == State::AddOrBlock); _share->setVisible(state == State::SharePhoneNumber); _report->setVisible(state == State::ReportSpam); + _add->setText((state == State::Add) + ? lng_new_contact_add_name(lt_user, _name).toUpper() + : lang(lng_new_contact_add).toUpper()); + updateButtonsGeometry(); } void ContactStatus::Bar::resizeEvent(QResizeEvent *e) { _close->moveToRight(0, 0); - _add->setGeometry(0, 0, width() / 2, height()); - _block->setGeometry(width() / 2, 0, width() - (width() / 2), height()); - _share->setGeometry(rect()); - _report->setGeometry(rect()); + updateButtonsGeometry(); } -ContactStatus::ContactStatus(not_null parent, not_null peer) -: _bar(parent, object_ptr(parent)) +void ContactStatus::Bar::updateButtonsGeometry() { + const auto full = width(); + const auto closeWidth = _close->width(); + const auto available = full - closeWidth; + const auto skip = st::historyContactStatusMinSkip; + const auto buttonWidth = [&](const object_ptr &button) { + return button->textWidth() + 2 * skip; + }; + + auto accumulatedLeft = 0; + const auto placeButton = [&]( + const object_ptr &button, + int buttonWidth, + int rightTextMargin = 0) { + button->setGeometry(accumulatedLeft, 0, buttonWidth, height()); + button->setTextMargins({ 0, 0, rightTextMargin, 0 }); + accumulatedLeft += buttonWidth; + }; + const auto placeOne = [&](const object_ptr &button) { + if (button->isHidden()) { + return; + } + const auto thatWidth = buttonWidth(button); + const auto margin = std::clamp( + thatWidth + closeWidth - available, + 0, + closeWidth); + placeButton(button, full, margin); + }; + if (!_add->isHidden() && !_block->isHidden()) { + const auto addWidth = buttonWidth(_add); + const auto blockWidth = buttonWidth(_block); + const auto half = full / 2; + if (addWidth <= half + && blockWidth + 2 * closeWidth <= full - half) { + placeButton(_add, half); + placeButton(_block, full - half); + } else if (addWidth + blockWidth <= available) { + const auto margin = std::clamp( + addWidth + blockWidth + closeWidth - available, + 0, + closeWidth); + const auto realBlockWidth = blockWidth + 2 * closeWidth - margin; + if (addWidth > realBlockWidth) { + placeButton(_add, addWidth); + placeButton(_block, full - addWidth, margin); + } else { + placeButton(_add, full - realBlockWidth); + placeButton(_block, realBlockWidth, margin); + } + } else { + const auto forAdd = (available * addWidth) + / (addWidth + blockWidth); + placeButton(_add, forAdd); + placeButton(_block, full - forAdd, closeWidth); + } + } else { + placeOne(_add); + placeOne(_share); + placeOne(_report); + } +} + +ContactStatus::ContactStatus( + not_null parent, + not_null peer) +: _bar(parent, object_ptr(parent, PeerFirstName(peer))) , _shadow(parent) { setupWidgets(parent); setupState(peer); @@ -190,7 +275,7 @@ auto ContactStatus::PeerState(not_null peer) return State::None; } } - return State::BlockOrAdd; + return State::AddOrBlock; }); } @@ -209,6 +294,7 @@ void ContactStatus::setupState(not_null peer) { PeerState( peer ) | rpl::start_with_next([=](State state) { + _state = state; if (state == State::None) { _bar.hide(anim::type::normal); } else { diff --git a/Telegram/SourceFiles/history/view/history_view_contact_status.h b/Telegram/SourceFiles/history/view/history_view_contact_status.h index 53f24ad067..742e36446a 100644 --- a/Telegram/SourceFiles/history/view/history_view_contact_status.h +++ b/Telegram/SourceFiles/history/view/history_view_contact_status.h @@ -29,17 +29,22 @@ public: int height() const; rpl::producer heightValue() const; + rpl::lifetime &lifetime() { + return _lifetime; + } + private: enum class State { None, ReportSpam, - BlockOrAdd, + Add, + AddOrBlock, SharePhoneNumber, }; class Bar : public Ui::RpWidget { public: - explicit Bar(QWidget *parent); + Bar(QWidget *parent, const QString &name); void showState(State state); @@ -47,6 +52,9 @@ private: void resizeEvent(QResizeEvent *e) override; private: + void updateButtonsGeometry(); + + QString _name; object_ptr _block; object_ptr _add; object_ptr _share; diff --git a/Telegram/SourceFiles/ui/widgets/buttons.cpp b/Telegram/SourceFiles/ui/widgets/buttons.cpp index 15b190a206..145addbfea 100644 --- a/Telegram/SourceFiles/ui/widgets/buttons.cpp +++ b/Telegram/SourceFiles/ui/widgets/buttons.cpp @@ -164,7 +164,11 @@ QPoint RippleButton::prepareRippleStartPosition() const { RippleButton::~RippleButton() = default; -FlatButton::FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st) : RippleButton(parent, st.ripple) +FlatButton::FlatButton( + QWidget *parent, + const QString &text, + const style::FlatButton &st) +: RippleButton(parent, st.ripple) , _text(text) , _st(st) { if (_st.width < 0) { @@ -182,7 +186,7 @@ void FlatButton::setText(const QString &text) { update(); } -void FlatButton::setWidth(int32 w) { +void FlatButton::setWidth(int w) { _width = w; if (_width < 0) { _width = textWidth() - _st.width; @@ -204,8 +208,8 @@ void FlatButton::onStateChanged(State was, StateChangeSource source) { void FlatButton::paintEvent(QPaintEvent *e) { QPainter p(this); - QRect r(0, height() - _st.height, width(), _st.height); - p.fillRect(r, isOver() ? _st.overBgColor : _st.bgColor); + const auto inner = QRect(0, height() - _st.height, width(), _st.height); + p.fillRect(inner, isOver() ? _st.overBgColor : _st.bgColor); paintRipple(p, 0, 0); @@ -213,8 +217,17 @@ void FlatButton::paintEvent(QPaintEvent *e) { p.setRenderHint(QPainter::TextAntialiasing); p.setPen(isOver() ? _st.overColor : _st.color); - r.setTop(_st.textTop); - p.drawText(r, _text, style::al_top); + const auto textRect = inner.marginsRemoved( + _textMargins + ).marginsRemoved( + { 0, _st.textTop, 0, 0 } + ); + p.drawText(textRect, _text, style::al_top); +} + +void FlatButton::setTextMargins(QMargins margins) { + _textMargins = margins; + update(); } RoundButton::RoundButton(QWidget *parent, Fn textFactory, const style::RoundButton &st) : RippleButton(parent, st.ripple) diff --git a/Telegram/SourceFiles/ui/widgets/buttons.h b/Telegram/SourceFiles/ui/widgets/buttons.h index 40b61cf7fc..346a5594cd 100644 --- a/Telegram/SourceFiles/ui/widgets/buttons.h +++ b/Telegram/SourceFiles/ui/widgets/buttons.h @@ -69,7 +69,6 @@ protected: private: void ensureRipple(); - void handleRipples(bool wasDown, bool wasPress); const style::RippleAnimation &_st; std::unique_ptr _ripple; @@ -83,7 +82,8 @@ public: FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st); void setText(const QString &text); - void setWidth(int32 w); + void setWidth(int w); + void setTextMargins(QMargins margins); int32 textWidth() const; @@ -93,8 +93,9 @@ protected: void onStateChanged(State was, StateChangeSource source) override; private: - QString _text, _textForAutoSize; - int _width; + QString _text; + QMargins _textMargins; + int _width = 0; const style::FlatButton &_st;