From 71637d2a0e7d221c4f0015a9cf418cdd2885948e Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 10 Apr 2020 13:29:49 +0400 Subject: [PATCH] Show progress left to close by timer in polls. --- Telegram/Resources/icons/quiz_timer.png | Bin 0 -> 409 bytes Telegram/Resources/icons/quiz_timer@2x.png | Bin 0 -> 819 bytes Telegram/Resources/icons/quiz_timer@3x.png | Bin 0 -> 1189 bytes Telegram/SourceFiles/history/history.style | 4 + .../history/view/media/history_view_poll.cpp | 99 ++++++++++++++++++ .../history/view/media/history_view_poll.h | 11 +- 6 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 Telegram/Resources/icons/quiz_timer.png create mode 100644 Telegram/Resources/icons/quiz_timer@2x.png create mode 100644 Telegram/Resources/icons/quiz_timer@3x.png diff --git a/Telegram/Resources/icons/quiz_timer.png b/Telegram/Resources/icons/quiz_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..9c075162ff07702f65b2db9bef70cd3e4d9ec30f GIT binary patch literal 409 zcmV;K0cQS*P)4DEcxleluL2k{CDUcd{va_>eDp(hYLhad?3eVM6* z-}bl8FfbE{hV&(`O_Sb)5K`&eF7=r6h$NDo>pNM4@t1z;JYER)&k1 zZ8f7P5@lJ6q9{a?B!pSlRrGx?+O`$PaaiNH6DP20nx=A|XH}8A?E5aETCfI;EB@hk zC*QV>a&=uNvn-Qw9FxL^4+4yb#3WEt|ahbzn|b272D6&HX`(U00000NkvXXu0mjf D%{8o( literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/quiz_timer@2x.png b/Telegram/Resources/icons/quiz_timer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0a839c03e297ce170a4a632a3556d4b8ac0a8cd GIT binary patch literal 819 zcmV-31I+x1P)Yc z2tmV7qJ;t~KcDCt4IzmqiQ(QnWu(YXJaat9Gd5$sgb-3aiIqQz_59oMl)z6%Fpa=} z7lC%WEq1$|kWxN9_=d4}2#!%}k8)J`?kyOzITx@JzXuRetE-~YM0!O5-!Nu-zOQdU z5J{vYK860;T=r}>D_X6VXf~UoR4R!=q2R!uPA9S7@5OvR7t`rf+-^6U)5hNe)oN9a zMk9H>UcHYW@)bJJg^gliKEx0lOB zu2w7OLEle+0jwA#!V|!R+wJznr_E*~2ZMpE)oL#e;Ty)F;}&4WAQ6rLLhfF9wJBx4 z-)E%*?4b)AD!`1GPT>e3Z>gNmXIZb;Usl|d60m_S6=0j}JjVG1aB|QMi&c!`ymkV% zG!np$a60h`;P|70RM5`2TU}C^N(f+3!5nTZ!#j_F`jL7%=dl@sa+cOZ==(VV47#!L zJAt|U^gX`w2y{9fx=_xE;sN%U_(@s41nJ^*qJp`C^ywJ87D9PIWjr3!*I0cwR-@5i z#JVlBmDQFndYUa#kr&~P4olTb`Lm&uNOA2=Ki53F1+Csb_{xDO_iiKtX6 z51XJ4uz;y0OvKm`n9XJy-)Xzu?$djm7dI9zK4FA)=7#+tQx33jKlVcghr*N+Tml~} zCE!rvi#d=;bU6(I$XOc~8d{d44q7Z0fyH4!O7b=v1xWOjQWF6QcO+;<`KvGWngr4b zd%~R#l!#v+Hn0VT#*5g7Pa*e2IGu3B;xb|q=s-8Z)zOov)jxNC;;%)k1XN@`F6>(9 xTPOi1m3o^OyD#E%!PWJ+CN2<7}Zrj>n#8P002ovPDHLkV1gS;Y)t?F literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/quiz_timer@3x.png b/Telegram/Resources/icons/quiz_timer@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..ad6c49b50c182c209972e8c0b8ec2c077eba9f20 GIT binary patch literal 1189 zcmV;W1X}xvP)S+vCm3w3CNwkZWG>CP`Z zaLdI_&^CpSUpBjk1H(2t-00X=XqyU9vRlj!_*Y0WK*QnC8IVs~XQdtulZ3CGcn#*3 zrdthlXoI$PJV~ylFT)-@|F5RWZn58jIRg@YslHGjwR$iZ6u8#b*5(%s+PPMVt)D z?sf~fnA8En(w|!)yUsb)+>mb$2sS8zPl2{2IzW4Sdz62(Crw-0l&qPUO6;b9o2-u?5N$|~8M?*UuAZk~RgEu@7aOa4&@`)pDS;@m^wT>tgp>x-fCGfGSpH!#1 z#kd1KyMeTJyA{qR=cA8zD#9VQ8rE5r59l9js{xQI=R#~&wLUELW;H~*LkoyYci^a6 ztK0V1MNo)@nZ}2OPncnFIpyjQWjSdtK*B_sk9`D4`QT6hg!w2RJqwV0UtZYQ*kB*U zfAZx8L=hlKkyPC`;Z>K%$H)2WFZldtUw^5tX)q^o6L%F*+t1J);bnz-MC%rcRUp)7 zJl(h@KwB{A2c6JO*$iA37f|Ue7L(i&wGXI2_Y!9b2!F9H!QKrUTq+B|fkIpKLEk{< z?aq;x^nW#QsE2baWCD?iEVGfw0^&km`u_et>5Jq^0okZpcu{2(7k+dB9L#_Oh#61@ zBoGj)a|C5T0s)~qM^FYN5D= ripple; }; +struct Poll::CloseInformation { + CloseInformation(TimeId date, TimeId period, Fn repaint); + + crl::time start = 0; + crl::time finish = 0; + crl::time duration = 0; + base::Timer timer; + Ui::Animations::Basic radial; +}; + template Poll::SendingAnimation::SendingAnimation( const QByteArray &option, @@ -197,6 +211,16 @@ void Poll::Answer::fillData( Ui::WebpageTextTitleOptions()); } +Poll::CloseInformation::CloseInformation( + TimeId date, + TimeId period, + Fn repaint) +: duration(period * crl::time(1000)) +, timer(std::move(repaint)) { + const auto left = std::clamp(date - base::unixtime::now(), 0, period); + finish = crl::now() + left * crl::time(1000); +} + Poll::Poll( not_null parent, not_null poll) @@ -676,6 +700,7 @@ void Poll::draw(Painter &p, const QRect &r, TextSelection selection, crl::time m p.setPen(regular); _subtitle.drawLeftElided(p, padding.left(), tshift, paintw, width()); paintRecentVoters(p, padding.left() + _subtitle.maxWidth(), tshift, selection); + paintCloseByTimer(p, padding.left() + paintw, tshift, selection); paintShowSolution(p, padding.left() + paintw, tshift, selection); tshift += st::msgDateFont->height + st::historyPollAnswersSkip; @@ -823,6 +848,80 @@ void Poll::paintRecentVoters( } } +void Poll::paintCloseByTimer( + Painter &p, + int right, + int top, + TextSelection selection) const { + if (!canVote() || _poll->closeDate <= 0 || _poll->closePeriod <= 0) { + _close = nullptr; + return; + } + if (!_close) { + _close = std::make_unique( + _poll->closeDate, + _poll->closePeriod, + [=] { history()->owner().requestViewRepaint(_parent); }); + } + const auto now = crl::now(); + const auto left = std::max(_close->finish - now, crl::time(0)); + const auto radial = std::min(_close->duration, kLargestRadialDuration); + if (!left) { + _close->radial.stop(); + } else if (left < radial && !anim::Disabled()) { + if (!_close->radial.animating()) { + _close->radial.init([=] { + history()->owner().requestViewRepaint(_parent); + }); + _close->radial.start(); + } + } else { + _close->radial.stop(); + } + const auto time = formatDurationText(int(std::ceil(left / 1000.))); + const auto outbg = _parent->hasOutLayout(); + const auto selected = (selection == FullSelection); + const auto &icon = selected + ? (outbg + ? st::historyQuizTimerOutSelected + : st::historyQuizTimerInSelected) + : (outbg ? st::historyQuizTimerOut : st::historyQuizTimerIn); + const auto x = right - icon.width(); + const auto y = top + + (st::normalFont->height - icon.height()) / 2 + - st::lineWidth; + const auto ®ular = (left < kCriticalCloseDuration) + ? st::boxTextFgError + : selected + ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) + : (outbg ? st::msgOutDateFg : st::msgInDateFg); + p.setPen(regular); + const auto timeWidth = st::normalFont->width(time); + p.drawTextLeft(x - timeWidth, top, width(), time, timeWidth); + if (left < radial) { + auto hq = PainterHighQualityEnabler(p); + const auto part = std::max( + left / float64(radial), + 1. / FullArcLength); + const auto length = int(std::round(FullArcLength * part)); + auto pen = regular->p; + pen.setWidth(st::historyPollRadio.thickness); + pen.setCapStyle(Qt::RoundCap); + p.setPen(pen); + const auto size = icon.width() / 2; + const auto left = (x + (icon.width() - size) / 2); + const auto top = (y + (icon.height() - size) / 2) + st::lineWidth; + p.drawArc(left, top, size, size, (FullArcLength / 4), length); + } else { + icon.paint(p, x, y, width()); + } + + if (left > (anim::Disabled() ? 0 : (radial - 1))) { + const auto next = (left % 1000); + _close->timer.callOnce((next ? next : 1000) + 1); + } +} + void Poll::paintShowSolution( Painter &p, int right, diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.h b/Telegram/SourceFiles/history/view/media/history_view_poll.h index ebc9d04e20..28d19d80b4 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.h +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.h @@ -24,6 +24,7 @@ public: Poll( not_null parent, not_null poll); + ~Poll(); void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override; TextState textState(QPoint point, StateRequest request) const override; @@ -53,13 +54,12 @@ public: const ClickHandlerPtr &handler, bool pressed) override; - ~Poll(); - private: struct AnswerAnimation; struct AnswersAnimation; struct SendingAnimation; struct Answer; + struct CloseInformation; QSize countOptimalSize() override; QSize countCurrentSize(int newWidth) override; @@ -96,6 +96,11 @@ private: int left, int top, TextSelection selection) const; + void paintCloseByTimer( + Painter &p, + int right, + int top, + TextSelection selection) const; void paintShowSolution( Painter &p, int right, @@ -194,6 +199,8 @@ private: Ui::Animations::Simple _wrongAnswerAnimation; mutable QPoint _lastLinkPoint; + mutable std::unique_ptr _close; + bool _hasSelected = false; bool _votedFromHere = false; mutable bool _wrongAnswerAnimated = false;