Add shake-on-error animation to CallMuteButton.
This commit is contained in:
parent
300c5a9c66
commit
3bd98ac564
4 changed files with 92 additions and 16 deletions
|
|
@ -564,7 +564,7 @@ groupCallMemberActiveIcon: #8deb90; // group call active member icon
|
||||||
groupCallMemberActiveStatus: #8deb90; // group call active member status text
|
groupCallMemberActiveStatus: #8deb90; // group call active member status text
|
||||||
groupCallMemberInactiveIcon: #84888f; // group call inactive member icon
|
groupCallMemberInactiveIcon: #84888f; // group call inactive member icon
|
||||||
groupCallMemberInactiveStatus: #61c0ff; // group call inactive member status text
|
groupCallMemberInactiveStatus: #61c0ff; // group call inactive member status text
|
||||||
groupCallMemberMutedIcon: #ff4f4d; // group call muted by admin member icon
|
groupCallMemberMutedIcon: #ed7372; // group call muted by admin member icon
|
||||||
groupCallMemberNotJoinedStatus: #91979e; // group call non joined member status text
|
groupCallMemberNotJoinedStatus: #91979e; // group call non joined member status text
|
||||||
groupCallIconFg: #ffffff; // group call mute / settings / leave icon
|
groupCallIconFg: #ffffff; // group call mute / settings / leave icon
|
||||||
groupCallLive1: #0dcc39; // group call live button color1
|
groupCallLive1: #0dcc39; // group call live button color1
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ constexpr auto kOverrideColorBgAlpha = 76;
|
||||||
constexpr auto kOverrideColorRippleAlpha = 50;
|
constexpr auto kOverrideColorRippleAlpha = 50;
|
||||||
|
|
||||||
constexpr auto kSwitchStateDuration = 120;
|
constexpr auto kSwitchStateDuration = 120;
|
||||||
|
constexpr auto kShiftDuration = crl::time(300);
|
||||||
|
|
||||||
auto MuteBlobs() {
|
auto MuteBlobs() {
|
||||||
return std::vector<Paint::Blobs::BlobData>{
|
return std::vector<Paint::Blobs::BlobData>{
|
||||||
|
|
@ -315,12 +316,9 @@ void CallMuteButton::init() {
|
||||||
_label->show();
|
_label->show();
|
||||||
rpl::combine(
|
rpl::combine(
|
||||||
_content->geometryValue(),
|
_content->geometryValue(),
|
||||||
_label->geometryValue()
|
_label->sizeValue()
|
||||||
) | rpl::start_with_next([=](QRect my, QRect label) {
|
) | rpl::start_with_next([=](QRect my, QSize size) {
|
||||||
_label->moveToLeft(
|
updateLabelGeometry(my, size);
|
||||||
my.x() + (my.width() - label.width()) / 2,
|
|
||||||
my.y() + my.height() - label.height(),
|
|
||||||
my.width());
|
|
||||||
}, _label->lifetime());
|
}, _label->lifetime());
|
||||||
_label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
_label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
|
|
@ -342,7 +340,7 @@ void CallMuteButton::init() {
|
||||||
// State type.
|
// State type.
|
||||||
const auto previousType =
|
const auto previousType =
|
||||||
lifetime().make_state<CallMuteButtonType>(_state.current().type);
|
lifetime().make_state<CallMuteButtonType>(_state.current().type);
|
||||||
setEnableMouse(false);
|
setHandleMouseState(HandleMouseState::Disabled);
|
||||||
|
|
||||||
const auto blobsInner = [&] {
|
const auto blobsInner = [&] {
|
||||||
// The point of the circle at 45 degrees.
|
// The point of the circle at 45 degrees.
|
||||||
|
|
@ -379,8 +377,10 @@ void CallMuteButton::init() {
|
||||||
const auto previous = *previousType;
|
const auto previous = *previousType;
|
||||||
*previousType = type;
|
*previousType = type;
|
||||||
|
|
||||||
if (IsInactive(type) && !IsInactive(previous)) {
|
const auto mouseState = HandleMouseStateFromType(type);
|
||||||
setEnableMouse(false);
|
setHandleMouseState(HandleMouseState::Disabled);
|
||||||
|
if (mouseState != HandleMouseState::Enabled) {
|
||||||
|
setHandleMouseState(mouseState);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto crossFrom = IsMuted(previous) ? 0. : 1.;
|
const auto crossFrom = IsMuted(previous) ? 0. : 1.;
|
||||||
|
|
@ -419,9 +419,7 @@ void CallMuteButton::init() {
|
||||||
overridesColors(previous, type, value);
|
overridesColors(previous, type, value);
|
||||||
|
|
||||||
if (value == to) {
|
if (value == to) {
|
||||||
if (!IsInactive(type) && IsInactive(previous)) {
|
setHandleMouseState(mouseState);
|
||||||
setEnableMouse(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -463,6 +461,60 @@ void CallMuteButton::init() {
|
||||||
}, _content->lifetime());
|
}, _content->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CallMuteButton::updateLabelGeometry() {
|
||||||
|
updateLabelGeometry(_content->geometry(), _label->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallMuteButton::updateLabelGeometry(QRect my, QSize size) {
|
||||||
|
_label->moveToLeft(
|
||||||
|
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
||||||
|
my.y() + my.height() - size.height(),
|
||||||
|
my.width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallMuteButton::shake() {
|
||||||
|
if (_shakeAnimation.animating()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto update = [=] {
|
||||||
|
const auto fullProgress = _shakeAnimation.value(1.) * 6;
|
||||||
|
const auto segment = std::clamp(int(std::floor(fullProgress)), 0, 5);
|
||||||
|
const auto part = fullProgress - segment;
|
||||||
|
const auto from = (segment == 0)
|
||||||
|
? 0.
|
||||||
|
: (segment == 1 || segment == 3 || segment == 5)
|
||||||
|
? 1.
|
||||||
|
: -1.;
|
||||||
|
const auto to = (segment == 0 || segment == 2 || segment == 4)
|
||||||
|
? 1.
|
||||||
|
: (segment == 1 || segment == 3)
|
||||||
|
? -1.
|
||||||
|
: 0.;
|
||||||
|
const auto shift = from * (1. - part) + to * part;
|
||||||
|
_labelShakeShift = int(std::round(shift * st::shakeShift));
|
||||||
|
updateLabelGeometry();
|
||||||
|
};
|
||||||
|
_shakeAnimation.start(
|
||||||
|
update,
|
||||||
|
0.,
|
||||||
|
1.,
|
||||||
|
kShiftDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
CallMuteButton::HandleMouseState CallMuteButton::HandleMouseStateFromType(
|
||||||
|
CallMuteButtonType type) {
|
||||||
|
switch (type) {
|
||||||
|
case CallMuteButtonType::Active:
|
||||||
|
case CallMuteButtonType::Muted:
|
||||||
|
return HandleMouseState::Enabled;
|
||||||
|
case CallMuteButtonType::Connecting:
|
||||||
|
return HandleMouseState::Disabled;
|
||||||
|
case CallMuteButtonType::ForceMuted:
|
||||||
|
return HandleMouseState::Blocked;
|
||||||
|
}
|
||||||
|
Unexpected("Type in HandleMouseStateFromType.");
|
||||||
|
}
|
||||||
|
|
||||||
void CallMuteButton::setState(const CallMuteButtonState &state) {
|
void CallMuteButton::setState(const CallMuteButtonState &state) {
|
||||||
_state = state;
|
_state = state;
|
||||||
}
|
}
|
||||||
|
|
@ -516,8 +568,15 @@ void CallMuteButton::lower() {
|
||||||
_blobs->lower();
|
_blobs->lower();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallMuteButton::setEnableMouse(bool value) {
|
void CallMuteButton::setHandleMouseState(HandleMouseState state) {
|
||||||
_content->setAttribute(Qt::WA_TransparentForMouseEvents, !value);
|
if (_handleMouseState == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_handleMouseState = state;
|
||||||
|
const auto handle = (_handleMouseState != HandleMouseState::Disabled);
|
||||||
|
const auto pointer = (_handleMouseState == HandleMouseState::Enabled);
|
||||||
|
_content->setAttribute(Qt::WA_TransparentForMouseEvents, !handle);
|
||||||
|
_content->setPointerCursor(pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallMuteButton::overridesColors(
|
void CallMuteButton::overridesColors(
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ public:
|
||||||
[[nodiscard]] QRect innerGeometry() const;
|
[[nodiscard]] QRect innerGeometry() const;
|
||||||
void moveInner(QPoint position);
|
void moveInner(QPoint position);
|
||||||
|
|
||||||
|
void shake();
|
||||||
|
|
||||||
void setVisible(bool visible);
|
void setVisible(bool visible);
|
||||||
void show() {
|
void show() {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
|
|
@ -64,31 +66,44 @@ public:
|
||||||
[[nodiscard]] rpl::lifetime &lifetime();
|
[[nodiscard]] rpl::lifetime &lifetime();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class HandleMouseState {
|
||||||
|
Enabled,
|
||||||
|
Blocked,
|
||||||
|
Disabled,
|
||||||
|
};
|
||||||
void init();
|
void init();
|
||||||
void overridesColors(
|
void overridesColors(
|
||||||
CallMuteButtonType fromType,
|
CallMuteButtonType fromType,
|
||||||
CallMuteButtonType toType,
|
CallMuteButtonType toType,
|
||||||
float64 progress);
|
float64 progress);
|
||||||
|
|
||||||
void setEnableMouse(bool value);
|
void setHandleMouseState(HandleMouseState state);
|
||||||
|
void updateLabelGeometry(QRect my, QSize size);
|
||||||
|
void updateLabelGeometry();
|
||||||
|
|
||||||
|
[[nodiscard]] static HandleMouseState HandleMouseStateFromType(
|
||||||
|
CallMuteButtonType type);
|
||||||
|
|
||||||
rpl::variable<CallMuteButtonState> _state;
|
rpl::variable<CallMuteButtonState> _state;
|
||||||
float _level = 0.;
|
float _level = 0.;
|
||||||
float64 _crossLineProgress = 0.;
|
float64 _crossLineProgress = 0.;
|
||||||
rpl::variable<float64> _radialShowProgress = 0.;
|
rpl::variable<float64> _radialShowProgress = 0.;
|
||||||
QRect _muteIconPosition;
|
QRect _muteIconPosition;
|
||||||
|
HandleMouseState _handleMouseState = HandleMouseState::Enabled;
|
||||||
|
|
||||||
const style::CallButton &_st;
|
const style::CallButton &_st;
|
||||||
|
|
||||||
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<FlatLabel> _label;
|
||||||
|
int _labelShakeShift = 0;
|
||||||
|
|
||||||
std::unique_ptr<InfiniteRadialAnimation> _radial;
|
std::unique_ptr<InfiniteRadialAnimation> _radial;
|
||||||
const base::flat_map<CallMuteButtonType, std::vector<QColor>> _colors;
|
const base::flat_map<CallMuteButtonType, std::vector<QColor>> _colors;
|
||||||
|
|
||||||
CrossLineAnimation _crossLineMuteAnimation;
|
CrossLineAnimation _crossLineMuteAnimation;
|
||||||
Animations::Simple _switchAnimation;
|
Animations::Simple _switchAnimation;
|
||||||
|
Animations::Simple _shakeAnimation;
|
||||||
|
|
||||||
rpl::event_stream<CallButtonColors> _colorOverrides;
|
rpl::event_stream<CallButtonColors> _colorOverrides;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1468,6 +1468,8 @@ callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
|
||||||
size: size(100px, 100px);
|
size: size(100px, 100px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shakeShift: 4px;
|
||||||
|
|
||||||
// Windows specific title
|
// Windows specific title
|
||||||
|
|
||||||
windowTitleButton: IconButton {
|
windowTitleButton: IconButton {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue