mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-31 07:52:06 +00:00
Implement adaptive ContactStatus buttons.
This commit is contained in:
parent
5e3734d7bf
commit
984f19b1e9
@ -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 »";
|
||||
|
@ -103,6 +103,9 @@ private:
|
||||
};
|
||||
|
||||
class PeerData {
|
||||
private:
|
||||
static constexpr auto kSettingsUnknown = MTPDpeerSettings::Flag(1U << 9);
|
||||
|
||||
protected:
|
||||
PeerData(not_null<Data::Session*> 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;
|
||||
|
@ -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 }};
|
||||
|
@ -1686,6 +1686,10 @@ void HistoryWidget::showHistory(
|
||||
_contactStatus = std::make_unique<HistoryView::ContactStatus>(
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<PeerData*> peer) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
return user->firstName;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool BarCurrentlyHidden(not_null<PeerData*> peer) {
|
||||
const auto settings = peer->settings();
|
||||
if (!settings) {
|
||||
@ -109,33 +115,112 @@ bool BarCurrentlyHidden(not_null<PeerData*> 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<Ui::RpWidget*> parent, not_null<PeerData*> peer)
|
||||
: _bar(parent, object_ptr<Bar>(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<Ui::FlatButton> &button) {
|
||||
return button->textWidth() + 2 * skip;
|
||||
};
|
||||
|
||||
auto accumulatedLeft = 0;
|
||||
const auto placeButton = [&](
|
||||
const object_ptr<Ui::FlatButton> &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<Ui::FlatButton> &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<Ui::RpWidget*> parent,
|
||||
not_null<PeerData*> peer)
|
||||
: _bar(parent, object_ptr<Bar>(parent, PeerFirstName(peer)))
|
||||
, _shadow(parent) {
|
||||
setupWidgets(parent);
|
||||
setupState(peer);
|
||||
@ -190,7 +275,7 @@ auto ContactStatus::PeerState(not_null<PeerData*> peer)
|
||||
return State::None;
|
||||
}
|
||||
}
|
||||
return State::BlockOrAdd;
|
||||
return State::AddOrBlock;
|
||||
});
|
||||
}
|
||||
|
||||
@ -209,6 +294,7 @@ void ContactStatus::setupState(not_null<PeerData*> peer) {
|
||||
PeerState(
|
||||
peer
|
||||
) | rpl::start_with_next([=](State state) {
|
||||
_state = state;
|
||||
if (state == State::None) {
|
||||
_bar.hide(anim::type::normal);
|
||||
} else {
|
||||
|
@ -29,17 +29,22 @@ public:
|
||||
int height() const;
|
||||
rpl::producer<int> 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<Ui::FlatButton> _block;
|
||||
object_ptr<Ui::FlatButton> _add;
|
||||
object_ptr<Ui::FlatButton> _share;
|
||||
|
@ -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<QString()> textFactory, const style::RoundButton &st) : RippleButton(parent, st.ripple)
|
||||
|
@ -69,7 +69,6 @@ protected:
|
||||
|
||||
private:
|
||||
void ensureRipple();
|
||||
void handleRipples(bool wasDown, bool wasPress);
|
||||
|
||||
const style::RippleAnimation &_st;
|
||||
std::unique_ptr<RippleAnimation> _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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user