Formatted classes for send actions.

This commit is contained in:
23rd 2021-08-30 16:11:43 +03:00
parent ccea6ce492
commit 0852dbc40f
3 changed files with 185 additions and 49 deletions

View file

@ -67,9 +67,13 @@ bool SendActionPainter::updateNeedsAnimating(
}, [&](const MTPDsendMessageRecordRoundAction &) {
emplaceAction(Type::RecordRound, kStatusShowClientsideRecordRound);
}, [&](const MTPDsendMessageGeoLocationAction &) {
emplaceAction(Type::ChooseLocation, kStatusShowClientsideChooseLocation);
emplaceAction(
Type::ChooseLocation,
kStatusShowClientsideChooseLocation);
}, [&](const MTPDsendMessageChooseContactAction &) {
emplaceAction(Type::ChooseContact, kStatusShowClientsideChooseContact);
emplaceAction(
Type::ChooseContact,
kStatusShowClientsideChooseContact);
}, [&](const MTPDsendMessageUploadVideoAction &data) {
emplaceAction(
Type::UploadVideo,
@ -221,19 +225,41 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
} else if (!_sendActions.empty()) {
// Handles all actions except game playing.
using Type = Api::SendProgressType;
auto sendActionString = [](Type type, const QString &name) -> QString {
const auto sendActionString = [](
Type type,
const QString &name) -> QString {
switch (type) {
case Type::RecordVideo: return name.isEmpty() ? tr::lng_send_action_record_video(tr::now) : tr::lng_user_action_record_video(tr::now, lt_user, name);
case Type::UploadVideo: return name.isEmpty() ? tr::lng_send_action_upload_video(tr::now) : tr::lng_user_action_upload_video(tr::now, lt_user, name);
case Type::RecordVoice: return name.isEmpty() ? tr::lng_send_action_record_audio(tr::now) : tr::lng_user_action_record_audio(tr::now, lt_user, name);
case Type::UploadVoice: return name.isEmpty() ? tr::lng_send_action_upload_audio(tr::now) : tr::lng_user_action_upload_audio(tr::now, lt_user, name);
case Type::RecordRound: return name.isEmpty() ? tr::lng_send_action_record_round(tr::now) : tr::lng_user_action_record_round(tr::now, lt_user, name);
case Type::UploadRound: return name.isEmpty() ? tr::lng_send_action_upload_round(tr::now) : tr::lng_user_action_upload_round(tr::now, lt_user, name);
case Type::UploadPhoto: return name.isEmpty() ? tr::lng_send_action_upload_photo(tr::now) : tr::lng_user_action_upload_photo(tr::now, lt_user, name);
case Type::UploadFile: return name.isEmpty() ? tr::lng_send_action_upload_file(tr::now) : tr::lng_user_action_upload_file(tr::now, lt_user, name);
case Type::RecordVideo: return name.isEmpty()
? tr::lng_send_action_record_video({})
: tr::lng_user_action_record_video({}, lt_user, name);
case Type::UploadVideo: return name.isEmpty()
? tr::lng_send_action_upload_video({})
: tr::lng_user_action_upload_video({}, lt_user, name);
case Type::RecordVoice: return name.isEmpty()
? tr::lng_send_action_record_audio({})
: tr::lng_user_action_record_audio({}, lt_user, name);
case Type::UploadVoice: return name.isEmpty()
? tr::lng_send_action_upload_audio({})
: tr::lng_user_action_upload_audio({}, lt_user, name);
case Type::RecordRound: return name.isEmpty()
? tr::lng_send_action_record_round({})
: tr::lng_user_action_record_round({}, lt_user, name);
case Type::UploadRound: return name.isEmpty()
? tr::lng_send_action_upload_round({})
: tr::lng_user_action_upload_round({}, lt_user, name);
case Type::UploadPhoto: return name.isEmpty()
? tr::lng_send_action_upload_photo({})
: tr::lng_user_action_upload_photo({}, lt_user, name);
case Type::UploadFile: return name.isEmpty()
? tr::lng_send_action_upload_file({})
: tr::lng_user_action_upload_file({}, lt_user, name);
case Type::ChooseLocation:
case Type::ChooseContact: return name.isEmpty() ? tr::lng_typing(tr::now) : tr::lng_user_typing(tr::now, lt_user, name);
case Type::ChooseSticker: return name.isEmpty() ? tr::lng_send_action_choose_sticker(tr::now) : tr::lng_user_action_choose_sticker(tr::now, lt_user, name);
case Type::ChooseContact: return name.isEmpty()
? tr::lng_typing({})
: tr::lng_user_typing({}, lt_user, name);
case Type::ChooseSticker: return name.isEmpty()
? tr::lng_send_action_choose_sticker({})
: tr::lng_user_action_choose_sticker({}, lt_user, name);
default: break;
};
return QString();

View file

@ -62,7 +62,9 @@ protected:
return _started;
}
[[nodiscard]] int frameTime(crl::time now) const {
return anim::Disabled() ? 0 : (std::max(now - _started, crl::time(0)) % _period);
return anim::Disabled()
? 0
: (std::max(now - _started, crl::time(0)) % _period);
}
private:
@ -73,7 +75,9 @@ private:
namespace {
using ImplementationsMap = QMap<Api::SendProgressType, const SendActionAnimation::Impl::MetaData*>;
using ImplementationsMap = QMap<
Api::SendProgressType,
const SendActionAnimation::Impl::MetaData*>;
NeverFreedPointer<ImplementationsMap> Implementations;
class TypingAnimation : public SendActionAnimation::Impl {
@ -90,34 +94,64 @@ public:
}
int width() const override {
return st::historySendActionTypingPosition.x() + kTypingDotsCount * st::historySendActionTypingDelta;
return st::historySendActionTypingPosition.x()
+ kTypingDotsCount * st::historySendActionTypingDelta;
}
void paint(Painter &p, style::color color, int x, int y, int outerWidth, crl::time now) override;
void paint(
Painter &p,
style::color color,
int x,
int y,
int outerWidth,
crl::time now) override;
};
const TypingAnimation::MetaData TypingAnimation::kMeta = { 0, &TypingAnimation::create };
const TypingAnimation::MetaData TypingAnimation::kMeta = {
0,
&TypingAnimation::create,
};
void TypingAnimation::paint(Painter &p, style::color color, int x, int y, int outerWidth, crl::time now) {
void TypingAnimation::paint(
Painter &p,
style::color color,
int x,
int y,
int outerWidth,
crl::time now) {
PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen);
p.setBrush(color);
auto frameMs = frameTime(now);
auto position = QPointF(x + 0.5, y - 0.5) + st::historySendActionTypingPosition;
auto position = QPointF(x + 0.5, y - 0.5)
+ st::historySendActionTypingPosition;
for (auto i = 0; i != kTypingDotsCount; ++i) {
auto r = st::historySendActionTypingSmallNumerator / st::historySendActionTypingDenominator;
auto r = st::historySendActionTypingSmallNumerator
/ st::historySendActionTypingDenominator;
if (frameMs < 2 * st::historySendActionTypingHalfPeriod) {
auto delta = (st::historySendActionTypingLargeNumerator - st::historySendActionTypingSmallNumerator) / st::historySendActionTypingDenominator;
const auto delta = (st::historySendActionTypingLargeNumerator
- st::historySendActionTypingSmallNumerator)
/ st::historySendActionTypingDenominator;
if (frameMs < st::historySendActionTypingHalfPeriod) {
r += delta * anim::easeOutCirc(1., float64(frameMs) / st::historySendActionTypingHalfPeriod);
r += delta
* anim::easeOutCirc(
1.,
float64(frameMs)
/ st::historySendActionTypingHalfPeriod);
} else {
r += delta * (1. - anim::easeOutCirc(1., float64(frameMs - st::historySendActionTypingHalfPeriod) / st::historySendActionTypingHalfPeriod));
r += delta
* (1. - anim::easeOutCirc(
1.,
float64(frameMs
- st::historySendActionTypingHalfPeriod)
/ st::historySendActionTypingHalfPeriod));
}
}
p.drawEllipse(position, r, r);
position.setX(position.x() + st::historySendActionTypingDelta);
frameMs = (frameMs + st::historySendActionTypingDuration - st::historySendActionTypingDeltaTime) % st::historySendActionTypingDuration;
frameMs = (frameMs + period() - st::historySendActionTypingDeltaTime)
% period();
}
}
@ -135,29 +169,51 @@ public:
}
int width() const override {
return st::historySendActionRecordPosition.x() + (kRecordArcsCount + 1) * st::historySendActionRecordDelta;
return st::historySendActionRecordPosition.x()
+ (kRecordArcsCount + 1) * st::historySendActionRecordDelta;
}
void paint(Painter &p, style::color color, int x, int y, int outerWidth, crl::time now) override;
void paint(
Painter &p,
style::color color,
int x,
int y,
int outerWidth,
crl::time now) override;
};
const RecordAnimation::MetaData RecordAnimation::kMeta = { 0, &RecordAnimation::create };
const RecordAnimation::MetaData RecordAnimation::kMeta = {
0,
&RecordAnimation::create,
};
void RecordAnimation::paint(Painter &p, style::color color, int x, int y, int outerWidth, crl::time now) {
void RecordAnimation::paint(
Painter &p,
style::color color,
int x,
int y,
int outerWidth,
crl::time now) {
PainterHighQualityEnabler hq(p);
const auto frameMs = frameTime(now);
auto pen = color->p;
pen.setWidth(st::historySendActionRecordStrokeNumerator / st::historySendActionRecordDenominator);
pen.setWidth(st::historySendActionRecordStrokeNumerator
/ st::historySendActionRecordDenominator);
pen.setJoinStyle(Qt::RoundJoin);
pen.setCapStyle(Qt::RoundCap);
p.setPen(pen);
p.setBrush(Qt::NoBrush);
auto progress = frameMs / float64(st::historySendActionRecordDuration);
auto size = st::historySendActionRecordPosition.x() + st::historySendActionRecordDelta * progress;
auto progress = frameMs / float64(period());
auto size = st::historySendActionRecordPosition.x()
+ st::historySendActionRecordDelta * progress;
y += st::historySendActionRecordPosition.y();
for (auto i = 0; i != kRecordArcsCount; ++i) {
p.setOpacity((i == 0) ? progress : (i == kRecordArcsCount - 1) ? (1. - progress) : 1.);
p.setOpacity((i == 0)
? progress
: (i == kRecordArcsCount - 1)
? (1. - progress)
: 1.);
auto rect = QRectF(x - size, y - size, 2 * size, 2 * size);
p.drawArc(rect, -FullArcLength / 24, FullArcLength / 12);
size += st::historySendActionRecordDelta;
@ -179,33 +235,64 @@ public:
}
int width() const override {
return st::historySendActionUploadPosition.x() + (kUploadArrowsCount + 1) * st::historySendActionUploadDelta;
return st::historySendActionUploadPosition.x()
+ (kUploadArrowsCount + 1) * st::historySendActionUploadDelta;
}
void paint(Painter &p, style::color color, int x, int y, int outerWidth, crl::time now) override;
void paint(
Painter &p,
style::color color,
int x,
int y,
int outerWidth,
crl::time now) override;
};
const UploadAnimation::MetaData UploadAnimation::kMeta = { 0, &UploadAnimation::create };
const UploadAnimation::MetaData UploadAnimation::kMeta = {
0,
&UploadAnimation::create,
};
void UploadAnimation::paint(Painter &p, style::color color, int x, int y, int outerWidth, crl::time now) {
void UploadAnimation::paint(
Painter &p,
style::color color,
int x,
int y,
int outerWidth,
crl::time now) {
PainterHighQualityEnabler hq(p);
const auto frameMs = frameTime(now);
auto pen = color->p;
pen.setWidth(st::historySendActionUploadStrokeNumerator / st::historySendActionUploadDenominator);
pen.setWidth(st::historySendActionUploadStrokeNumerator
/ st::historySendActionUploadDenominator);
pen.setJoinStyle(Qt::RoundJoin);
pen.setCapStyle(Qt::RoundCap);
p.setPen(pen);
p.setBrush(Qt::NoBrush);
auto progress = frameMs / float64(st::historySendActionUploadDuration);
auto position = QPointF(x + st::historySendActionUploadDelta * progress, y) + st::historySendActionUploadPosition;
auto progress = frameMs / float64(period());
auto position = st::historySendActionUploadPosition
+ QPointF(x + st::historySendActionUploadDelta * progress, y);
auto path = QPainterPath();
path.moveTo(0., -st::historySendActionUploadSizeNumerator / st::historySendActionUploadDenominator);
path.lineTo(st::historySendActionUploadSizeNumerator / st::historySendActionUploadDenominator, 0.);
path.lineTo(0., st::historySendActionUploadSizeNumerator / st::historySendActionUploadDenominator);
path.moveTo(
0.,
-st::historySendActionUploadSizeNumerator
/ st::historySendActionUploadDenominator);
path.lineTo(
st::historySendActionUploadSizeNumerator
/ st::historySendActionUploadDenominator,
0.);
path.lineTo(
0.,
st::historySendActionUploadSizeNumerator
/ st::historySendActionUploadDenominator);
p.translate(position);
for (auto i = 0; i != kUploadArrowsCount; ++i) {
p.setOpacity((i == 0) ? progress : (i == kUploadArrowsCount - 1) ? (1. - progress) : 1.);
p.setOpacity((i == 0)
? progress
: (i == kUploadArrowsCount - 1)
? (1. - progress)
: 1.);
p.drawPath(path);
position.setX(position.x() + st::historySendActionUploadDelta);
p.translate(st::historySendActionUploadDelta, 0);
@ -570,7 +657,8 @@ SendActionAnimation::~SendActionAnimation() = default;
bool SendActionAnimation::Impl::supports(Type type) const {
CreateImplementationsMap();
return Implementations->value(type, &TypingAnimation::kMeta) == metaData();
return Implementations->value(type, &TypingAnimation::kMeta)
== metaData();
}
void SendActionAnimation::start(Type type) {
@ -593,13 +681,24 @@ int SendActionAnimation::width() const {
return _impl ? _impl->width() : 0;
}
void SendActionAnimation::paint(Painter &p, style::color color, int x, int y, int outerWidth, crl::time ms) const {
void SendActionAnimation::paint(
Painter &p,
style::color color,
int x,
int y,
int outerWidth,
crl::time ms) const {
if (_impl) {
_impl->paint(p, color, x, y, outerWidth, ms);
}
}
void SendActionAnimation::PaintSpeakingIdle(Painter &p, style::color color, int x, int y, int outerWidth) {
void SendActionAnimation::PaintSpeakingIdle(
Painter &p,
style::color color,
int x,
int y,
int outerWidth) {
SpeakingAnimation::PaintIdle(p, color, x, y, outerWidth);
}

View file

@ -25,13 +25,24 @@ public:
void tryToFinish();
int width() const;
void paint(Painter &p, style::color color, int x, int y, int outerWidth, crl::time ms) const;
void paint(
Painter &p,
style::color color,
int x,
int y,
int outerWidth,
crl::time ms) const;
explicit operator bool() const {
return _impl != nullptr;
}
static void PaintSpeakingIdle(Painter &p, style::color color, int x, int y, int outerWidth);
static void PaintSpeakingIdle(
Painter &p,
style::color color,
int x,
int y,
int outerWidth);
private:
[[nodiscard]] static std::unique_ptr<Impl> CreateByType(Type type);