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 kSwitchStateDuration = crl::time(120);
constexpr auto kSwitchLabelDuration = crl::time(180);
// Switch state from Connecting animation.
constexpr auto kSwitchRadialDuration = crl::time(350);
@ -148,6 +149,110 @@ void ComputeRadialFinish(
} // 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 {
public:
BlobsWidget(
@ -379,19 +484,32 @@ CallMuteButton::CallMuteButton(
return isBadState || !(!animDisabled && !hide);
})))
, _content(base::make_unique_q<AbstractButton>(parent))
, _label(base::make_unique_q<FlatLabel>(
, _centerLabel(base::make_unique_q<AnimatedLabel>(
parent,
_state.value(
) | rpl::map([](const CallMuteButtonState &state) {
return state.text;
return state.subtext.isEmpty() ? state.text : QString();
}),
kSwitchLabelDuration,
st::callMuteButtonLabelAdditional,
_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,
_state.value(
) | rpl::map([](const CallMuteButtonState &state) {
return state.subtext;
}),
kSwitchLabelDuration,
st::callMuteButtonLabelAdditional,
st::callMuteButtonSublabel))
, _radial(nullptr)
, _colors(Colors())
@ -411,10 +529,9 @@ void CallMuteButton::init() {
_label->show();
rpl::combine(
_content->geometryValue(),
_sublabel->widthValue(),
_label->sizeValue()
) | rpl::start_with_next([=](QRect my, int subWidth, QSize size) {
updateLabelGeometry(my, subWidth, size);
) | rpl::start_with_next([=](QRect my, QSize size) {
updateLabelGeometry(my, size);
}, _label->lifetime());
_label->setAttribute(Qt::WA_TransparentForMouseEvents);
@ -427,6 +544,15 @@ void CallMuteButton::init() {
}, _sublabel->lifetime());
_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(
) | rpl::start_with_next([=](float64 value) {
auto &info = _radialInfo;
@ -626,27 +752,34 @@ void CallMuteButton::init() {
}
void CallMuteButton::updateLabelsGeometry() {
updateLabelGeometry(
_content->geometry(),
_sublabel->width(),
_label->size());
updateLabelGeometry(_content->geometry(), _label->size());
updateCenterLabelGeometry(_content->geometry(), _centerLabel->size());
updateSublabelGeometry(_content->geometry(), _sublabel->size());
}
void CallMuteButton::updateLabelGeometry(QRect my, int subWidth, QSize size) {
const auto skip = subWidth
? st::callMuteButtonSublabelSkip
: (st::callMuteButtonSublabelSkip / 2);
void CallMuteButton::updateLabelGeometry(QRect my, QSize size) {
const auto skip = st::callMuteButtonSublabelSkip
+ st::callMuteButtonLabelsSkip;
_label->moveToLeft(
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());
}
void CallMuteButton::updateSublabelGeometry(QRect my, QSize size) {
const auto skip = st::callMuteButtonLabelsSkip;
_sublabel->moveToLeft(
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
my.y() + my.height() - size.height(),
my.y() + my.height() - _sublabel->height() - skip,
my.width());
}

View file

@ -19,6 +19,7 @@ class BlobsWidget;
class AbstractButton;
class FlatLabel;
class RpWidget;
class AnimatedLabel;
struct CallButtonColors;
@ -87,7 +88,8 @@ private:
float64 progress);
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 updateLabelsGeometry();
@ -104,8 +106,9 @@ private:
const base::unique_qptr<BlobsWidget> _blobs;
const base::unique_qptr<AbstractButton> _content;
const base::unique_qptr<FlatLabel> _label;
const base::unique_qptr<FlatLabel> _sublabel;
const base::unique_qptr<AnimatedLabel> _centerLabel;
const base::unique_qptr<AnimatedLabel> _label;
const base::unique_qptr<AnimatedLabel> _sublabel;
int _labelShakeShift = 0;
RadialInfo _radialInfo;

View file

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