Update lottie icons in voice chats.

Esse commit está contido em:
John Preston
2021-04-08 20:25:50 +04:00
commit 4d91ab7079
13 arquivos alterados com 125 adições e 164 exclusões
+3
Ver Arquivo
@@ -4,3 +4,6 @@
# Ensure diffs have LF endings
*.diff text eol=lf
*.bat text eol=crlf
# Ensure lottie animations are treated as binary files
*.lottie binary
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+2 -3
Ver Arquivo
@@ -59,9 +59,8 @@
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
<file alias="icons/calls/active_hand.json">../../icons/calls/active_hand.json</file>
<file alias="icons/calls/hand_muted_active.json">../../icons/calls/hand_muted_active.json</file>
<file alias="icons/calls/raised_hand.json">../../icons/calls/raised_hand.json</file>
<file alias="icons/calls/hands.lottie">../../icons/calls/hands.lottie</file>
<file alias="icons/calls/voice.lottie">../../icons/calls/voice.lottie</file>
</qresource>
<qresource prefix="/qt-project.org">
<file>../qmime/freedesktop.org.xml</file>
+2 -2
Ver Arquivo
@@ -393,8 +393,8 @@ callErrorToast: Toast(defaultToast) {
groupCallWidth: 380px;
groupCallHeight: 580px;
groupCallMuteButtonIconSize: size(55px, 55px);
groupCallMuteButtonIconTop: 42px;
groupCallMuteButtonIconSize: size(69px, 69px);
groupCallMuteButtonIconTop: 35px;
groupCallRipple: RippleAnimation(defaultRippleAnimation) {
color: groupCallMembersBgRipple;
}
@@ -357,6 +357,13 @@ bool GroupCall::showChooseJoinAs() const {
&& !_possibleJoinAs.front()->isSelf());
}
bool GroupCall::scheduleStartSubscribed() const {
if (const auto real = lookupReal()) {
return real->scheduleStartSubscribed();
}
return false;
}
Data::GroupCall *GroupCall::lookupReal() const {
const auto real = _peer->groupCall();
return (real && real->id() == _id) ? real : nullptr;
@@ -113,6 +113,7 @@ public:
[[nodiscard]] TimeId scheduleDate() const {
return _scheduleDate;
}
[[nodiscard]] bool scheduleStartSubscribed() const;
[[nodiscard]] Data::GroupCall *lookupReal() const;
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
@@ -388,9 +388,13 @@ Panel::Panel(not_null<GroupCall*> call)
.text = (_call->scheduleDate()
? tr::lng_group_call_start_now(tr::now)
: tr::lng_group_call_connecting(tr::now)),
.type = (_call->scheduleDate()
.type = (!_call->scheduleDate()
? Ui::CallMuteButtonType::Connecting
: _peer->canManageGroupCall()
? Ui::CallMuteButtonType::ScheduledCanStart
: Ui::CallMuteButtonType::Connecting),
: _call->scheduleStartSubscribed()
? Ui::CallMuteButtonType::ScheduledNotify
: Ui::CallMuteButtonType::ScheduledSilent),
}))
, _hangup(widget(), st::groupCallHangup) {
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
@@ -70,6 +70,14 @@ constexpr auto kOverlapProgressRadialHide = 1.2;
constexpr auto kRadialFinishArcShift = 1200;
[[nodiscard]] CallMuteButtonType TypeForIcon(CallMuteButtonType type) {
return (type == CallMuteButtonType::Connecting)
? CallMuteButtonType::Muted
: (type == CallMuteButtonType::RaisedHand)
? CallMuteButtonType::ForceMuted
: type;
};
auto MuteBlobs() {
return std::vector<Paint::Blobs::BlobData>{
{
@@ -546,160 +554,101 @@ CallMuteButton::CallMuteButton(
}
CallMuteButton::IconState CallMuteButton::initialState() {
const auto result = iconStateFrom(_state.current().type);
_icons[0].emplace(Lottie::IconDescriptor{
.path = u":/gui/icons/calls/hand_muted_active.json"_q,
.path = u":/gui/icons/calls/voice.lottie"_q,
.color = st::groupCallIconFg,
.sizeOverride = st::groupCallMuteButtonIconSize,
.frame = 22,
.frame = result.frameTo,
});
_icons[1].emplace(Lottie::IconDescriptor{
.path = u":/gui/icons/calls/active_hand.json"_q,
.path = u":/gui/icons/calls/hands.lottie"_q,
.color = st::groupCallIconFg,
.sizeOverride = st::groupCallMuteButtonIconSize,
.frame = 0,
});
_icons[2].emplace(Lottie::IconDescriptor{
.path = u":/gui/icons/calls/raised_hand.json"_q,
.color = st::groupCallIconFg,
.sizeOverride = st::groupCallMuteButtonIconSize,
.frame = 0,
});
return iconStateFrom(_state.current().type);
return result;
}
auto CallMuteButton::iconStateAnimated(CallMuteButtonType previous)
-> IconState {
using Type = CallMuteButtonType;
using Key = std::pair<Type, Type>;
struct Animation {
int from = 0;
int to = 0;
};
static const auto kAnimations = std::vector<std::pair<Key, Animation>>{
{ { Type::ForceMuted, Type::Muted }, { 0, 35 } },
{ { Type::Muted, Type::Active }, { 36, 68 } },
{ { Type::Active, Type::Muted }, { 69, 98 } },
{ { Type::Muted, Type::ForceMuted }, { 99, 135 } },
{ { Type::Active, Type::ForceMuted }, { 136, 172 } },
{ { Type::ScheduledSilent, Type::ScheduledNotify }, { 173, 201 } },
{ { Type::ScheduledSilent, Type::Muted }, { 202, 236 } },
{ { Type::ScheduledSilent, Type::ForceMuted }, { 237, 273 } },
{ { Type::ScheduledNotify, Type::ForceMuted }, { 274, 310 } },
{ { Type::ScheduledNotify, Type::ScheduledSilent }, { 311, 343 } },
{ { Type::ScheduledNotify, Type::Muted }, { 344, 375 } },
{ { Type::ScheduledCanStart, Type::Muted }, { 376, 403 } },
};
static const auto kMap = [] {
// flat_multi_map_pair_type lacks some required constructors :(
auto &&list = kAnimations | ranges::views::transform([](auto &&pair) {
return base::flat_multi_map_pair_type<Key, Animation>(
pair.first,
pair.second);
});
return base::flat_map<Key, Animation>(begin(list), end(list));
}();
const auto was = TypeForIcon(previous);
const auto now = TypeForIcon(_state.current().type);
if (was == now) {
return {};
}
if (const auto i = kMap.find(Key{ was, now }); i != end(kMap)) {
return { 0, i->second.from, i->second.to };
}
return {};
}
CallMuteButton::IconState CallMuteButton::iconStateFrom(
CallMuteButtonType previous) {
const auto current = _state.current().type;
switch (previous) {
case CallMuteButtonType::Active: {
switch (current) {
case CallMuteButtonType::Active: {
return { // Active
.icon = &*_icons[0],
.frameFrom = 41,
.frameTo = 41,
.otherJumpToFrame = 0,
};
} break;
case CallMuteButtonType::Connecting:
case CallMuteButtonType::Muted: {
return { // Active -> Muted
.icon = &*_icons[0],
.frameFrom = 42,
.frameTo = 62,
};
} break;
case CallMuteButtonType::ScheduledCanStart: // #TODO voice chats
case CallMuteButtonType::ScheduledNotify:
case CallMuteButtonType::ScheduledSilent:
case CallMuteButtonType::ForceMuted:
case CallMuteButtonType::RaisedHand: {
return { // Active -> Hand
.icon = &*_icons[1],
.frameFrom = 0,
.frameTo = 22,
.otherJumpToFrame = 0,
};
} break;
}
} break;
case CallMuteButtonType::Connecting:
case CallMuteButtonType::Muted: {
switch (current) {
case CallMuteButtonType::Active: {
return { // Muted -> Active
.icon = &*_icons[0],
.frameFrom = 21,
.frameTo = 41,
.otherJumpToFrame = 0,
};
} break;
case CallMuteButtonType::Connecting:
case CallMuteButtonType::Muted: {
return { // Muted
.icon = &*_icons[0],
.frameFrom = 22,
.frameTo = 22,
};
} break;
case CallMuteButtonType::ScheduledCanStart: // #TODO voice chats
case CallMuteButtonType::ScheduledNotify:
case CallMuteButtonType::ScheduledSilent:
case CallMuteButtonType::ForceMuted:
case CallMuteButtonType::RaisedHand: {
return { // Muted -> Hand
.icon = &*_icons[0],
.frameFrom = 63,
.frameTo = 83,
.otherJumpToFrame = 22,
};
} break;
}
} break;
case CallMuteButtonType::ScheduledCanStart: // #TODO voice chats
case CallMuteButtonType::ScheduledNotify:
case CallMuteButtonType::ScheduledSilent:
case CallMuteButtonType::ForceMuted:
case CallMuteButtonType::RaisedHand: {
switch (current) {
case CallMuteButtonType::Active: {
return { // Hand -> Active
.icon = &*_icons[1],
.frameFrom = 22,
.frameTo = 0,
.otherJumpToFrame = 42,
};
} break;
case CallMuteButtonType::Connecting:
case CallMuteButtonType::Muted: {
return { // Hand -> Muted
.icon = &*_icons[0],
.frameFrom = 0,
.frameTo = 20,
};
} break;
case CallMuteButtonType::ScheduledCanStart: // #TODO voice chats
case CallMuteButtonType::ScheduledNotify:
case CallMuteButtonType::ScheduledSilent:
case CallMuteButtonType::ForceMuted:
case CallMuteButtonType::RaisedHand: {
return { // Hand
.icon = &*_icons[0],
.frameFrom = 0,
.frameTo = 0,
.otherJumpToFrame = 22,
};
} break;
}
} break;
if (const auto animated = iconStateAnimated(previous)) {
return animated;
}
Unexpected("State in CallMuteButton::iconStateFrom.");
using Type = CallMuteButtonType;
static const auto kFinal = base::flat_map<Type, int>{
{ Type::ForceMuted, 0 },
{ Type::Muted, 36 },
{ Type::Active, 69 },
{ Type::ScheduledSilent, 173 },
{ Type::ScheduledNotify, 274 },
{ Type::ScheduledCanStart, 376 },
};
const auto now = TypeForIcon(_state.current().type);
const auto i = kFinal.find(now);
Ensures(i != end(kFinal));
return { 0, i->second, i->second };
}
CallMuteButton::IconState CallMuteButton::randomWavingState() {
switch (openssl::RandomValue<uint32>() % 5) {
case 0: return {
.icon = &*_icons[2],
.frameFrom = 0,
.frameTo = 120 };
case 1: return {
.icon = &*_icons[2],
.frameFrom = 120,
.frameTo = 240 };
case 2: return {
.icon = &*_icons[2],
.frameFrom = 240,
.frameTo = 420 };
case 3: return {
.icon = &*_icons[2],
.frameFrom = 420,
.frameTo = 540 };
case 4: return {
.icon = &*_icons[2],
.frameFrom = 540,
.frameTo = 720 };
}
Unexpected("Value in CallMuteButton::randomWavingState.");
struct Animation {
int from = 0;
int to = 0;
};
static const auto kAnimations = std::vector<Animation>{
{ 0, 120 },
{ 120, 240 },
{ 240, 420 },
{ 420, 540 },
};
const auto index = openssl::RandomValue<uint32>() % kAnimations.size();
return { 1, kAnimations[index].from, kAnimations[index].to };
}
void CallMuteButton::init() {
@@ -884,7 +833,7 @@ void CallMuteButton::init() {
) | rpl::start_with_next([=](QRect clip) {
Painter p(_content);
_iconState.icon->paint(p, _muteIconRect.x(), _muteIconRect.y());
_icons[_iconState.index]->paint(p, _muteIconRect.x(), _muteIconRect.y());
if (_radialInfo.state.has_value() && _switchAnimation.animating()) {
const auto radialProgress = _radialInfo.realShowProgress;
@@ -929,7 +878,7 @@ void CallMuteButton::init() {
void CallMuteButton::scheduleIconState(const IconState &state) {
if (_iconState != state) {
if (_iconState.icon->animating()) {
if (_icons[_iconState.index]->animating()) {
_scheduledState = state;
} else {
startIconState(state);
@@ -942,22 +891,15 @@ void CallMuteButton::scheduleIconState(const IconState &state) {
void CallMuteButton::startIconState(const IconState &state) {
_iconState = state;
_scheduledState = std::nullopt;
_iconState.icon->animate(
_icons[_iconState.index]->animate(
[=] { iconAnimationCallback(); },
_iconState.frameFrom,
_iconState.frameTo);
if (const auto other = state.otherJumpToFrame) {
if (_iconState.icon == &*_icons[0]) {
_icons[1]->jumpTo(*other, nullptr);
} else {
_icons[0]->jumpTo(*other, nullptr);
}
}
}
void CallMuteButton::iconAnimationCallback() {
_content->update(_muteIconRect);
if (!_iconState.icon->animating() && _scheduledState) {
if (!_icons[_iconState.index]->animating() && _scheduledState) {
startIconState(*_scheduledState);
}
}
@@ -87,20 +87,25 @@ private:
const style::InfiniteRadialAnimation &st = st::callConnectingRadial;
};
struct IconState {
not_null<Lottie::Icon*> icon;
int index = -1;
int frameFrom = 0;
int frameTo = 0;
std::optional<int> otherJumpToFrame;
inline bool operator==(const IconState &other) const {
return (icon == other.icon)
return (index == other.index)
&& (frameFrom == other.frameFrom)
&& (frameTo == other.frameTo)
&& (otherJumpToFrame == other.otherJumpToFrame);
&& (frameTo == other.frameTo);
}
inline bool operator!=(const IconState &other) const {
return !(*this == other);
}
bool valid() const {
return (index >= 0);
}
explicit operator bool() const {
return valid();
}
};
void init();
@@ -118,6 +123,7 @@ private:
[[nodiscard]] IconState initialState();
[[nodiscard]] IconState iconStateFrom(CallMuteButtonType previous);
[[nodiscard]] IconState randomWavingState();
[[nodiscard]] IconState iconStateAnimated(CallMuteButtonType previous);
void scheduleIconState(const IconState &state);
void startIconState(const IconState &state);
void iconAnimationCallback();
@@ -143,7 +149,7 @@ private:
std::unique_ptr<InfiniteRadialAnimation> _radial;
const base::flat_map<CallMuteButtonType, anim::gradient_colors> _colors;
std::array<std::optional<Lottie::Icon>, 3> _icons;
std::array<std::optional<Lottie::Icon>, 2> _icons;
IconState _iconState;
std::optional<IconState> _scheduledState;