Add poll vote sending animation.

This commit is contained in:
John Preston 2018-12-22 23:32:04 +04:00
parent ac2dce4bb1
commit 93c8e9aa1f
5 changed files with 141 additions and 39 deletions

View File

@ -5360,10 +5360,26 @@ void ApiWrap::sendPollVotes(
return;
}
const auto item = App::histItemById(itemId);
const auto media = item ? item->media() : nullptr;
const auto poll = media ? media->poll() : nullptr;
if (!item) {
return;
}
const auto showSending = poll && !options.empty();
const auto hideSending = [=] {
if (showSending) {
if (const auto item = App::histItemById(itemId)) {
poll->sendingVote = QByteArray();
_session->data().requestItemRepaint(item);
}
}
};
if (showSending) {
poll->sendingVote = options.front();
_session->data().requestItemRepaint(item);
}
auto prepared = QVector<MTPbytes>();
prepared.reserve(options.size());
ranges::transform(
@ -5376,9 +5392,11 @@ void ApiWrap::sendPollVotes(
MTP_vector<MTPbytes>(prepared)
)).done([=](const MTPUpdates &result) {
_pollVotesRequestIds.erase(itemId);
hideSending();
applyUpdates(result);
}).fail([=](const RPCError &error) {
_pollVotesRequestIds.erase(itemId);
hideSending();
}).send();
_pollVotesRequestIds.emplace(itemId, requestId);
}

View File

@ -39,6 +39,7 @@ struct PollData {
std::vector<PollAnswer> answers;
int totalVoters = 0;
bool closed = false;
QByteArray sendingVote;
int version = 0;

View File

@ -525,6 +525,10 @@ historyPollRadio: Radio(defaultRadio) {
historyPollRadioOpacity: 0.7;
historyPollRadioOpacityOver: 1.;
historyPollDuration: 300;
historyPollRadialAnimation: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
thickness: 2px;
size: size(18px, 18px);
}
boxAttachEmoji: IconButton(historyAttachEmoji) {
width: 30px;

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_cursor_state.h"
#include "calls/calls_instance.h"
#include "ui/text_options.h"
#include "ui/effects/radial_animation.h"
#include "data/data_media_types.h"
#include "data/data_poll.h"
#include "data/data_session.h"
@ -61,6 +62,48 @@ FormattedLargeNumber FormatLargeNumber(int64 number) {
} // namespace
struct HistoryPoll::AnswerAnimation {
anim::value percent;
anim::value filling;
anim::value opacity;
};
struct HistoryPoll::AnswersAnimation {
std::vector<AnswerAnimation> data;
Animation progress;
};
struct HistoryPoll::SendingAnimation {
SendingAnimation(
const QByteArray &option,
AnimationCallbacks &&callbacks);
QByteArray option;
Ui::InfiniteRadialAnimation animation;
};
struct HistoryPoll::Answer {
Answer();
void fillText(const PollAnswer &original);
Text text;
QByteArray option;
mutable int votes = 0;
mutable int votesPercentWidth = 0;
mutable float64 filling = 0.;
mutable QString votesPercent;
mutable bool chosen = false;
ClickHandlerPtr handler;
};
HistoryPoll::SendingAnimation::SendingAnimation(
const QByteArray &option,
AnimationCallbacks &&callbacks)
: option(option)
, animation(std::move(callbacks), st::historyPollRadialAnimation) {
}
HistoryPoll::Answer::Answer() : text(st::msgMinWidth / 2) {
}
@ -187,7 +230,7 @@ void HistoryPoll::updateTexts() {
updateVotes();
if (willStartAnimation) {
startAnimation();
startAnswersAnimation();
}
}
@ -218,7 +261,7 @@ void HistoryPoll::updateAnswers() {
answer.handler = createAnswerClickHandler(answer);
}
_answersAnimation = nullptr;
resetAnswersAnimation();
}
ClickHandlerPtr HistoryPoll::createAnswerClickHandler(
@ -236,12 +279,32 @@ void HistoryPoll::updateVotes() const {
updateTotalVotes();
}
void HistoryPoll::updateVotesCheckAnimation() const {
void HistoryPoll::updateVotesCheckAnimations() const {
const auto willStartAnimation = checkAnimationStart();
updateVotes();
if (willStartAnimation) {
startAnimation();
startAnswersAnimation();
}
const auto &sending = _poll->sendingVote;
if (sending.isEmpty() == !_sendingAnimation) {
if (_sendingAnimation) {
_sendingAnimation->option = sending;
}
return;
}
if (sending.isEmpty()) {
if (!_answersAnimation) {
_sendingAnimation = nullptr;
}
return;
}
_sendingAnimation = std::make_unique<SendingAnimation>(
sending,
animation(
const_cast<HistoryPoll*>(this),
&HistoryPoll::step_radial));
_sendingAnimation->animation.start();
}
void HistoryPoll::updateTotalVotes() const {
@ -307,7 +370,7 @@ void HistoryPoll::draw(Painter &p, const QRect &r, TextSelection selection, Time
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
auto paintx = 0, painty = 0, paintw = width(), painth = height();
updateVotesCheckAnimation();
updateVotesCheckAnimations();
const auto outbg = _parent->hasOutLayout();
const auto selected = (selection == FullSelection);
@ -332,7 +395,7 @@ void HistoryPoll::draw(Painter &p, const QRect &r, TextSelection selection, Time
? _answersAnimation->progress.current(ms, 1.)
: 1.;
if (progress == 1.) {
_answersAnimation = nullptr;
resetAnswersAnimation();
}
auto &&answers = ranges::view::zip(
@ -366,6 +429,19 @@ void HistoryPoll::draw(Painter &p, const QRect &r, TextSelection selection, Time
}
}
void HistoryPoll::resetAnswersAnimation() const {
_answersAnimation = nullptr;
if (_poll->sendingVote.isEmpty()) {
_sendingAnimation = nullptr;
}
}
void HistoryPoll::step_radial(TimeMs ms, bool timer) {
if (timer && !anim::Disabled()) {
Auth().data().requestViewRepaint(_parent);
}
}
int HistoryPoll::paintAnswer(
Painter &p,
const Answer &answer,
@ -457,13 +533,34 @@ void HistoryPoll::paintRadio(
const auto &st = st::historyPollRadio;
const auto over = ClickHandler::showAsActive(answer.handler);
const auto &regular = selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg);
auto pen = regular->p;
pen.setWidth(st.thickness);
p.setPen(pen);
p.setBrush(Qt::NoBrush);
const auto o = p.opacity();
p.setOpacity(o * (over ? st::historyPollRadioOpacityOver : st::historyPollRadioOpacity));
p.drawEllipse(QRectF(left, top, st.diameter, st.diameter).marginsRemoved(QMarginsF(st.thickness / 2., st.thickness / 2., st.thickness / 2., st.thickness / 2.)));
const auto rect = QRectF(left, top, st.diameter, st.diameter).marginsRemoved(QMarginsF(st.thickness / 2., st.thickness / 2., st.thickness / 2., st.thickness / 2.));
if (_sendingAnimation && _sendingAnimation->option == answer.option) {
const auto &active = selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg);
if (anim::Disabled()) {
anim::DrawStaticLoading(p, rect, st.thickness, active);
} else {
const auto state = _sendingAnimation->animation.computeState();
auto pen = anim::pen(regular, active, state.shown);
pen.setWidth(st.thickness);
pen.setCapStyle(Qt::RoundCap);
p.setPen(pen);
p.drawArc(
rect,
state.arcFrom,
state.arcLength);
}
} else {
auto pen = regular->p;
pen.setWidth(st.thickness);
p.setPen(pen);
p.drawEllipse(rect);
}
p.setOpacity(o);
}
@ -564,7 +661,7 @@ bool HistoryPoll::checkAnimationStart() const {
return result;
}
void HistoryPoll::startAnimation() const {
void HistoryPoll::startAnswersAnimation() const {
if (!_answersAnimation) {
return;
}
@ -587,7 +684,7 @@ void HistoryPoll::startAnimation() const {
TextState HistoryPoll::textState(QPoint point, StateRequest request) const {
auto result = TextState(_parent);
if (!canVote()) {
if (!canVote() || !_poll->sendingVote.isEmpty()) {
return result;
}

View File

@ -37,31 +37,10 @@ public:
~HistoryPoll();
private:
struct AnswerAnimation {
anim::value percent;
anim::value filling;
anim::value opacity;
};
struct AnswersAnimation {
std::vector<AnswerAnimation> data;
Animation progress;
};
struct Answer {
Answer();
void fillText(const PollAnswer &original);
Text text;
QByteArray option;
mutable int votes = 0;
mutable int votesPercentWidth = 0;
mutable float64 filling = 0.;
mutable QString votesPercent;
mutable bool chosen = false;
ClickHandlerPtr handler;
};
struct AnswerAnimation;
struct AnswersAnimation;
struct SendingAnimation;
struct Answer;
QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override;
@ -81,7 +60,7 @@ private:
const PollAnswer &original,
int totalVotes,
int maxVotes) const;
void updateVotesCheckAnimation() const;
void updateVotesCheckAnimations() const;
int paintAnswer(
Painter &p,
@ -119,7 +98,9 @@ private:
bool checkAnimationStart() const;
bool answerVotesChanged() const;
void saveStateInAnimation() const;
void startAnimation() const;
void startAnswersAnimation() const;
void resetAnswersAnimation() const;
void step_radial(TimeMs ms, bool timer);
not_null<PollData*> _poll;
int _pollVersion = 0;
@ -133,5 +114,6 @@ private:
mutable Text _totalVotesLabel;
mutable std::unique_ptr<AnswersAnimation> _answersAnimation;
mutable std::unique_ptr<SendingAnimation> _sendingAnimation;
};