Added initial implementation of label animation in mute button.

This commit is contained in:
23rd 2020-12-18 12:35:53 +03:00
parent abb615a7c9
commit a29e93ca55
3 changed files with 157 additions and 19 deletions

View file

@ -47,6 +47,7 @@ constexpr auto kOverrideColorRippleAlpha = 50;
constexpr auto kShiftDuration = crl::time(300); constexpr auto kShiftDuration = crl::time(300);
constexpr auto kSwitchStateDuration = crl::time(120); constexpr auto kSwitchStateDuration = crl::time(120);
constexpr auto kSwitchLabelDuration = crl::time(180);
// Switch state from Connecting animation. // Switch state from Connecting animation.
constexpr auto kSwitchRadialDuration = crl::time(350); constexpr auto kSwitchRadialDuration = crl::time(350);
@ -148,6 +149,110 @@ void ComputeRadialFinish(
} // namespace } // namespace
class AnimatedLabel final : public RpWidget {
public:
AnimatedLabel(
QWidget *parent,
rpl::producer<QString> &&text,
crl::time duration,
int additionalHeight,
const style::FlatLabel &st = st::defaultFlatLabel);
int height() const;
private:
int realHeight() const;
void setText(const QString &text);
const style::FlatLabel &_st;
const crl::time _duration;
const int _additionalHeight;
const TextParseOptions _options;
Text::String _text;
Text::String _previousText;
Animations::Simple _animation;
};
AnimatedLabel::AnimatedLabel(
QWidget *parent,
rpl::producer<QString> &&text,
crl::time duration,
int additionalHeight,
const style::FlatLabel &st)
: RpWidget(parent)
, _st(st)
, _duration(duration)
, _additionalHeight(additionalHeight)
, _options({ 0, 0, 0, Qt::LayoutDirectionAuto }) {
std::move(
text
) | rpl::start_with_next([=](const QString &value) {
setText(value);
}, lifetime());
paintRequest(
) | rpl::start_with_next([=] {
Painter p(this);
const auto progress = _animation.value(1.);
p.setFont(_st.style.font);
p.setPen(_st.textFg);
p.setTextPalette(_st.palette);
const auto textHeight = height();
const auto diffHeight = realHeight() - textHeight;
const auto center = (diffHeight) / 2;
p.setOpacity(1. - progress);
if (p.opacity()) {
_previousText.draw(
p,
0,
anim::interpolate(center, diffHeight, progress),
width(),
style::al_center);
}
p.setOpacity(progress);
if (p.opacity()) {
_text.draw(
p,
0,
anim::interpolate(0, center, progress),
width(),
style::al_center);
}
}, lifetime());
}
int AnimatedLabel::height() const {
return _st.style.font->height;
}
int AnimatedLabel::realHeight() const {
return RpWidget::height();
}
void AnimatedLabel::setText(const QString &text) {
if (_text.toString() == text) {
return;
}
_previousText = _text;
_text.setText(_st.style, text, _options);
const auto width = std::max(
_st.style.font->width(_text.toString()),
_st.style.font->width(_previousText.toString()));
resize(width + _additionalHeight, height() + _additionalHeight * 2);
_animation.stop();
_animation.start([=] { update(); }, 0., 1., _duration);
}
class BlobsWidget final : public RpWidget { class BlobsWidget final : public RpWidget {
public: public:
BlobsWidget( BlobsWidget(
@ -379,19 +484,32 @@ CallMuteButton::CallMuteButton(
return isBadState || !(!animDisabled && !hide); return isBadState || !(!animDisabled && !hide);
}))) })))
, _content(base::make_unique_q<AbstractButton>(parent)) , _content(base::make_unique_q<AbstractButton>(parent))
, _label(base::make_unique_q<FlatLabel>( , _centerLabel(base::make_unique_q<AnimatedLabel>(
parent, parent,
_state.value( _state.value(
) | rpl::map([](const CallMuteButtonState &state) { ) | rpl::map([](const CallMuteButtonState &state) {
return state.text; return state.subtext.isEmpty() ? state.text : QString();
}), }),
kSwitchLabelDuration,
st::callMuteButtonLabelAdditional,
_st.label)) _st.label))
, _sublabel(base::make_unique_q<FlatLabel>( , _label(base::make_unique_q<AnimatedLabel>(
parent,
_state.value(
) | rpl::map([](const CallMuteButtonState &state) {
return state.subtext.isEmpty() ? QString() : state.text;
}),
kSwitchLabelDuration,
st::callMuteButtonLabelAdditional,
_st.label))
, _sublabel(base::make_unique_q<AnimatedLabel>(
parent, parent,
_state.value( _state.value(
) | rpl::map([](const CallMuteButtonState &state) { ) | rpl::map([](const CallMuteButtonState &state) {
return state.subtext; return state.subtext;
}), }),
kSwitchLabelDuration,
st::callMuteButtonLabelAdditional,
st::callMuteButtonSublabel)) st::callMuteButtonSublabel))
, _radial(nullptr) , _radial(nullptr)
, _colors(Colors()) , _colors(Colors())
@ -411,10 +529,9 @@ void CallMuteButton::init() {
_label->show(); _label->show();
rpl::combine( rpl::combine(
_content->geometryValue(), _content->geometryValue(),
_sublabel->widthValue(),
_label->sizeValue() _label->sizeValue()
) | rpl::start_with_next([=](QRect my, int subWidth, QSize size) { ) | rpl::start_with_next([=](QRect my, QSize size) {
updateLabelGeometry(my, subWidth, size); updateLabelGeometry(my, size);
}, _label->lifetime()); }, _label->lifetime());
_label->setAttribute(Qt::WA_TransparentForMouseEvents); _label->setAttribute(Qt::WA_TransparentForMouseEvents);
@ -427,6 +544,15 @@ void CallMuteButton::init() {
}, _sublabel->lifetime()); }, _sublabel->lifetime());
_sublabel->setAttribute(Qt::WA_TransparentForMouseEvents); _sublabel->setAttribute(Qt::WA_TransparentForMouseEvents);
_centerLabel->show();
rpl::combine(
_content->geometryValue(),
_centerLabel->sizeValue()
) | rpl::start_with_next([=](QRect my, QSize size) {
updateCenterLabelGeometry(my, size);
}, _centerLabel->lifetime());
_centerLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
_radialInfo.rawShowProgress.value( _radialInfo.rawShowProgress.value(
) | rpl::start_with_next([=](float64 value) { ) | rpl::start_with_next([=](float64 value) {
auto &info = _radialInfo; auto &info = _radialInfo;
@ -626,27 +752,34 @@ void CallMuteButton::init() {
} }
void CallMuteButton::updateLabelsGeometry() { void CallMuteButton::updateLabelsGeometry() {
updateLabelGeometry( updateLabelGeometry(_content->geometry(), _label->size());
_content->geometry(), updateCenterLabelGeometry(_content->geometry(), _centerLabel->size());
_sublabel->width(),
_label->size());
updateSublabelGeometry(_content->geometry(), _sublabel->size()); updateSublabelGeometry(_content->geometry(), _sublabel->size());
} }
void CallMuteButton::updateLabelGeometry(QRect my, int subWidth, QSize size) { void CallMuteButton::updateLabelGeometry(QRect my, QSize size) {
const auto skip = subWidth const auto skip = st::callMuteButtonSublabelSkip
? st::callMuteButtonSublabelSkip + st::callMuteButtonLabelsSkip;
: (st::callMuteButtonSublabelSkip / 2);
_label->moveToLeft( _label->moveToLeft(
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift, my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
my.y() + my.height() - size.height() - skip, my.y() + my.height() - _label->height() - skip,
my.width());
}
void CallMuteButton::updateCenterLabelGeometry(QRect my, QSize size) {
const auto skip = (st::callMuteButtonSublabelSkip / 2)
+ st::callMuteButtonLabelsSkip;
_centerLabel->moveToLeft(
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
my.y() + my.height() - _centerLabel->height() - skip,
my.width()); my.width());
} }
void CallMuteButton::updateSublabelGeometry(QRect my, QSize size) { void CallMuteButton::updateSublabelGeometry(QRect my, QSize size) {
const auto skip = st::callMuteButtonLabelsSkip;
_sublabel->moveToLeft( _sublabel->moveToLeft(
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift, my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
my.y() + my.height() - size.height(), my.y() + my.height() - _sublabel->height() - skip,
my.width()); my.width());
} }

View file

@ -19,6 +19,7 @@ class BlobsWidget;
class AbstractButton; class AbstractButton;
class FlatLabel; class FlatLabel;
class RpWidget; class RpWidget;
class AnimatedLabel;
struct CallButtonColors; struct CallButtonColors;
@ -87,7 +88,8 @@ private:
float64 progress); float64 progress);
void setHandleMouseState(HandleMouseState state); void setHandleMouseState(HandleMouseState state);
void updateLabelGeometry(QRect my, int subWidth, QSize size); void updateCenterLabelGeometry(QRect my, QSize size);
void updateLabelGeometry(QRect my, QSize size);
void updateSublabelGeometry(QRect my, QSize size); void updateSublabelGeometry(QRect my, QSize size);
void updateLabelsGeometry(); void updateLabelsGeometry();
@ -104,8 +106,9 @@ private:
const base::unique_qptr<BlobsWidget> _blobs; const base::unique_qptr<BlobsWidget> _blobs;
const base::unique_qptr<AbstractButton> _content; const base::unique_qptr<AbstractButton> _content;
const base::unique_qptr<FlatLabel> _label; const base::unique_qptr<AnimatedLabel> _centerLabel;
const base::unique_qptr<FlatLabel> _sublabel; const base::unique_qptr<AnimatedLabel> _label;
const base::unique_qptr<AnimatedLabel> _sublabel;
int _labelShakeShift = 0; int _labelShakeShift = 0;
RadialInfo _radialInfo; RadialInfo _radialInfo;

View file

@ -1433,6 +1433,7 @@ callMuteButtonLabel: FlatLabel(defaultFlatLabel) {
callMuteButtonSublabel: FlatLabel(defaultFlatLabel) { callMuteButtonSublabel: FlatLabel(defaultFlatLabel) {
textFg: groupCallMemberNotJoinedStatus; textFg: groupCallMemberNotJoinedStatus;
} }
callMuteButtonLabelsSkip: 5px;
callMuteButtonSublabelSkip: 19px; callMuteButtonSublabelSkip: 19px;
callMuteButtonActive: CallButton { callMuteButtonActive: CallButton {
button: callMuteButtonActiveInner; button: callMuteButtonActiveInner;
@ -1457,6 +1458,7 @@ callMuteButtonConnecting: CallButton(callMuteButtonMuted) {
bg: callIconBg; bg: callIconBg;
label: callMuteButtonLabel; label: callMuteButtonLabel;
} }
callMuteButtonLabelAdditional: 5px;
callMuteCrossLine: CrossLineAnimation { callMuteCrossLine: CrossLineAnimation {
fg: groupCallIconFg; fg: groupCallIconFg;