diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp index 03c5ba517d..9148a7aaae 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp @@ -407,7 +407,7 @@ struct Poll::RecentVoter { mutable Ui::PeerUserpicView userpic; }; -struct Poll::Part { +struct Poll::Part : public base::has_weak_ptr { explicit Part(not_null owner) : _owner(owner) {} virtual ~Part() = default; @@ -963,13 +963,65 @@ struct Poll::Header : public Poll::Part { bool hasHeavyPart() const override; void unloadHeavyPart() override; uint16 selectionLength() const override; + + void updateDescription(); + void updateAttachedMedia(); + [[nodiscard]] int countTopContentSkip(int pollWidth = 0) const; + [[nodiscard]] int countTopMediaHeight(int pollWidth = 0) const; + [[nodiscard]] int countAttachHeight(int pollWidth = 0) const; + [[nodiscard]] QRect countTopMediaRect(int top) const; + [[nodiscard]] Ui::BubbleRounding topMediaRounding() const; + void validateTopMediaCache(QSize size) const; + [[nodiscard]] int countDescriptionHeight(int innerWidth) const; + [[nodiscard]] int countQuestionTop( + int innerWidth, + int pollWidth = 0) const; + [[nodiscard]] uint16 solutionSelectionLength() const; + [[nodiscard]] TextSelection toSolutionSelection( + TextSelection selection) const; + [[nodiscard]] TextSelection fromSolutionSelection( + TextSelection selection) const; + [[nodiscard]] TextSelection toQuestionSelection( + TextSelection selection) const; + [[nodiscard]] TextSelection fromQuestionSelection( + TextSelection selection) const; + void updateRecentVoters(); + void paintRecentVoters( + Painter &p, + int left, + int top, + const PaintContext &context) const; + void paintShowSolution( + Painter &p, + int right, + int top, + const PaintContext &context) const; + void showSolution() const; + void solutionToggled( + bool solutionShown, + anim::type animated = anim::type::normal) const; + [[nodiscard]] bool canShowSolution() const; + [[nodiscard]] bool inShowSolution( + QPoint point, + int right, + int top) const; + void updateSolutionText(); + void updateSolutionMedia(); + [[nodiscard]] int countSolutionBlockHeight(int innerWidth) const; + [[nodiscard]] int countSolutionMediaHeight(int mediaWidth) const; + void paintSolutionBlock( + Painter &p, + int left, + int top, + int paintw, + const PaintContext &context) const; }; int Poll::Header::countHeight(int innerWidth) const { const auto pollWidth = innerWidth + st::msgPadding.left() + st::msgPadding.right(); - return _owner->countQuestionTop(innerWidth, pollWidth) + return countQuestionTop(innerWidth, pollWidth) + _owner->_question.countHeight(innerWidth) + st::historyPollSubtitleSkip + st::msgDateFont->height @@ -983,13 +1035,13 @@ void Poll::Header::draw( int outerWidth, const PaintContext &context) const { const auto stm = context.messageStyle(); - auto tshift = _owner->countTopContentSkip(); + auto tshift = countTopContentSkip(); - if (const auto mediaHeight = _owner->countTopMediaHeight()) { + if (const auto mediaHeight = countTopMediaHeight()) { if (_owner->_attachedMediaAttach) { const auto sideSkip = st::historyPollMediaSideSkip; _owner->_attachedMediaAttach->setBubbleRounding( - _owner->topMediaRounding()); + topMediaRounding()); p.translate(sideSkip, tshift); _owner->_attachedMediaAttach->draw( p, @@ -997,7 +1049,7 @@ void Poll::Header::draw( .withSelection(TextSelection())); p.translate(-sideSkip, -tshift); } else { - const auto target = _owner->countTopMediaRect(tshift); + const auto target = countTopMediaRect(tshift); p.setPen(Qt::NoPen); p.setBrush(stm->msgFileBg); PainterHighQualityEnabler hq(p); @@ -1040,7 +1092,7 @@ void Poll::Header::draw( p.restore(); } } else { - _owner->validateTopMediaCache(target.size()); + validateTopMediaCache(target.size()); if (!_owner->_attachedMediaCache.isNull()) { p.drawImage(target.topLeft(), _owner->_attachedMediaCache); @@ -1051,7 +1103,7 @@ void Poll::Header::draw( } if (const auto descriptionHeight - = _owner->countDescriptionHeight(innerWidth)) { + = countDescriptionHeight(innerWidth)) { p.setPen(stm->historyTextFg); _owner->_parent->prepareCustomEmojiPaint( p, context, _owner->_description); @@ -1070,8 +1122,8 @@ void Poll::Header::draw( } if (const auto solutionHeight - = _owner->countSolutionBlockHeight(innerWidth)) { - _owner->paintSolutionBlock( + = countSolutionBlockHeight(innerWidth)) { + paintSolutionBlock( p, left, tshift, innerWidth, context); tshift += solutionHeight + st::historyPollExplanationSkip; } @@ -1086,16 +1138,16 @@ void Poll::Header::draw( style::al_left, 0, -1, - _owner->toQuestionSelection(context.selection)); + toQuestionSelection(context.selection)); tshift += _owner->_question.countHeight(innerWidth) + st::historyPollSubtitleSkip; p.setPen(stm->msgDateFg); _owner->_subtitle.drawLeftElided( p, left, tshift, innerWidth, outerWidth); - _owner->paintRecentVoters( + paintRecentVoters( p, left + _owner->_subtitle.maxWidth(), tshift, context); - _owner->paintShowSolution( + paintShowSolution( p, left + innerWidth, tshift, context); } @@ -1106,9 +1158,9 @@ TextState Poll::Header::textState( int outerWidth, StateRequest request) const { TextState result(_owner->_parent); - auto tshift = _owner->countTopContentSkip(); + auto tshift = countTopContentSkip(); - if (const auto mediaHeight = _owner->countTopMediaHeight()) { + if (const auto mediaHeight = countTopMediaHeight()) { if (_owner->_attachedMediaAttach) { const auto sideSkip = st::historyPollMediaSideSkip; if (QRect( @@ -1134,7 +1186,7 @@ TextState Poll::Header::textState( auto symbolAdd = uint16(0); if (const auto descriptionHeight - = _owner->countDescriptionHeight(innerWidth)) { + = countDescriptionHeight(innerWidth)) { if (QRect(left, tshift, innerWidth, descriptionHeight) .contains(point)) { result = TextState( @@ -1153,7 +1205,7 @@ TextState Poll::Header::textState( } if (const auto solutionHeight - = _owner->countSolutionBlockHeight(innerWidth)) { + = countSolutionBlockHeight(innerWidth)) { if (QRect(left, tshift, innerWidth, solutionHeight) .contains(point)) { const auto &qst = st::historyPagePreview; @@ -1197,7 +1249,7 @@ TextState Poll::Header::textState( } if (_owner->_solutionAttach) { if (const auto mh - = _owner->countSolutionMediaHeight( + = countSolutionMediaHeight( textWidth)) { const auto mediaTop = textTop + textHeight @@ -1255,7 +1307,7 @@ TextState Poll::Header::textState( symbolAdd += _owner->_question.length(); } tshift += questionH + st::historyPollSubtitleSkip; - if (_owner->inShowSolution( + if (inShowSolution( point, left + innerWidth, tshift)) { result.link = _owner->_showSolutionLink; return result; @@ -1328,13 +1380,76 @@ struct Poll::Options : public Poll::Part { void checkSendingAnimation() const; void unloadHeavyPart() override; + + [[nodiscard]] int countAnswerContentWidth( + const Answer &answer, + int innerWidth) const; + [[nodiscard]] int countAnswerHeight( + const Answer &answer, + int innerWidth) const; + void resetAnswersAnimation() const; + void radialAnimationCallback() const; + int paintAnswer( + Painter &p, + const Answer &answer, + const AnswerAnimation *animation, + int left, + int top, + int width, + int outerWidth, + const PaintContext &context) const; + void paintRadio( + Painter &p, + const Answer &answer, + int left, + int top, + const PaintContext &context) const; + void paintPercent( + Painter &p, + const QString &percent, + int percentWidth, + int left, + int top, + int topPadding, + int outerWidth, + const PaintContext &context) const; + void paintFilling( + Painter &p, + bool chosen, + bool correct, + float64 filling, + int left, + int top, + int topPadding, + int width, + int contentWidth, + const PaintContext &context) const; + [[nodiscard]] bool checkAnimationStart() const; + [[nodiscard]] bool answerVotesChanged() const; + void saveStateInAnimation() const; + void startAnswersAnimation() const; + void toggleRipple(Answer &answer, bool pressed); + void toggleMultiOption(const QByteArray &option); + void sendMultiOptions(); + void showResults(); + void showAnswerVotesTooltip(const QByteArray &option); + void checkQuizAnswered(); + [[nodiscard]] ClickHandlerPtr createAnswerClickHandler( + const Answer &answer); + void updateAnswers(); + void updateAnswerVotes(); + void updateAnswerVotesFromOriginal( + Answer &answer, + const PollAnswer &original, + int percent, + int maxVotes); }; int Poll::Options::countHeight(int innerWidth) const { return ranges::accumulate(ranges::views::all( _owner->_answers ) | ranges::views::transform([&](const Answer &answer) { - return _owner->countAnswerHeight(answer, innerWidth); + return countAnswerHeight(answer, innerWidth); }), 0); } @@ -1350,7 +1465,7 @@ void Poll::Options::draw( ? _owner->_answersAnimation->progress.value(1.) : 1.; if (progress == 1.) { - _owner->resetAnswersAnimation(); + resetAnswersAnimation(); } auto tshift = 0; @@ -1370,7 +1485,7 @@ void Poll::Options::draw( : anim::linear); animation->opacity.update(progress, anim::linear); } - const auto height = _owner->paintAnswer( + const auto height = paintAnswer( p, answer, animation, @@ -1395,7 +1510,7 @@ TextState Poll::Options::textState( auto tshift = 0; for (const auto &answer : _owner->_answers) { - const auto height = _owner->countAnswerHeight(answer, innerWidth); + const auto height = countAnswerHeight(answer, innerWidth); if (point.y() >= tshift && point.y() < tshift + height) { const auto media = answer.thumbnail ? PollAnswerMediaSize() @@ -1451,7 +1566,7 @@ void Poll::Options::clickHandlerPressedChanged( &Answer::handler); if (i != end(_owner->_answers)) { if (_owner->canVote()) { - _owner->toggleRipple(*i, pressed); + toggleRipple(*i, pressed); } } } @@ -1544,32 +1659,32 @@ Poll::Poll( , _showResultsLink( std::make_shared(crl::guard( this, - [=] { showResults(); }))) + [=] { _optionsPart->showResults(); }))) , _sendVotesLink( std::make_shared(crl::guard( this, - [=] { sendMultiOptions(); }))) + [=] { _optionsPart->sendMultiOptions(); }))) , _adminVotesLink( std::make_shared(crl::guard( this, [=] { if (_flags & PollData::Flag::PublicVotes) { - showResults(); + _optionsPart->showResults(); } else { - saveStateInAnimation(); + _optionsPart->saveStateInAnimation(); _adminShowResults = true; - updateAnswerVotes(); - startAnswersAnimation(); + _optionsPart->updateAnswerVotes(); + _optionsPart->startAnswersAnimation(); } }))) , _adminBackVoteLink( std::make_shared(crl::guard( this, [=] { - saveStateInAnimation(); + _optionsPart->saveStateInAnimation(); _adminShowResults = false; - updateAnswerVotes(); - startAnswersAnimation(); + _optionsPart->updateAnswerVotes(); + _optionsPart->startAnswersAnimation(); }))) , _addOptionLink( std::make_shared(crl::guard( @@ -1607,7 +1722,7 @@ Poll::Poll( _addOptionPart = std::make_unique(this); _footerPart = std::make_unique