diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 8667b03fb0..2163ec9554 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -2095,6 +2095,11 @@ void Session::requestItemTextRefresh(not_null item) { view->itemTextUpdated(); }); requestItemResize(item); + if (item->textAppearing()) { + enumerateItemViews(item, [&](not_null view) { + view->skipInactiveTextAppearing(); + }); + } }; if (const auto group = groups().find(item)) { call(group->items.front()); diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index 2a1dc3b616..54381b6330 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -366,6 +366,7 @@ enum class MessageFlag : uint64 { HasUnreadPollVote = (1ULL << 59), TextAppearing = (1ULL << 60), + TextAppearingStarted = (1ULL << 61), }; inline constexpr bool is_flag_type(MessageFlag) { return true; } using MessageFlags = base::flags; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 1a36f2bd1c..f84a4d1d3c 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -2715,16 +2715,19 @@ QString HistoryItem::notificationHeader() const { return QString(); } -void HistoryItem::markBeingSentForAdoption() { - _flags |= MessageFlag::BeingSent; +void HistoryItem::markTextAppearingStarted() { + _flags |= MessageFlag::TextAppearingStarted; } void HistoryItem::setRealId(MsgId newId) { - Expects(_flags & MessageFlag::BeingSent); + Expects(isSending() || textAppearing()); Expects(IsClientMsgId(id)); const auto oldId = std::exchange(id, newId); _flags &= ~(MessageFlag::BeingSent | MessageFlag::Local); + if (textAppearing()) { + markTextAppearingStarted(); + } if (isBusinessShortcut()) { _date = 0; } diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 9d30f6d271..dd189bccef 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -343,9 +343,12 @@ public: [[nodiscard]] bool canBeSummarized() const { return _flags & MessageFlag::CanBeSummarized; } - [[nodiscard]] bool isTextAppearing() const { + [[nodiscard]] bool textAppearing() const { return _flags & MessageFlag::TextAppearing; } + [[nodiscard]] bool textAppearingStarted() const { + return _flags & MessageFlag::TextAppearingStarted; + } [[nodiscard]] bool hasRealFromId() const; [[nodiscard]] bool isPostHidingAuthor() const; [[nodiscard]] bool isPostShowingAuthor() const; @@ -440,7 +443,7 @@ public: bool isForumPost); void setPostAuthor(const QString &author); void setRealId(MsgId newId); - void markBeingSentForAdoption(); + void markTextAppearingStarted(); void incrementReplyToTopCounter(); void applyEffectWatchedOnUnreadKnown(); diff --git a/Telegram/SourceFiles/history/history_streamed_drafts.cpp b/Telegram/SourceFiles/history/history_streamed_drafts.cpp index 8a3ba345ab..4c0721ebe5 100644 --- a/Telegram/SourceFiles/history/history_streamed_drafts.cpp +++ b/Telegram/SourceFiles/history/history_streamed_drafts.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "history/history.h" #include "history/history_item.h" +#include "main/main_session.h" namespace { @@ -57,9 +58,8 @@ void HistoryStreamedDrafts::apply( clearByRandomId(randomId); return; } - const auto text = Api::ParseTextWithEntities( - &_history->session(), - data.vtext()); + const auto session = &_history->session(); + const auto text = Api::ParseTextWithEntities(session, data.vtext()); if (update(randomId, text)) { return; } @@ -83,6 +83,17 @@ void HistoryStreamedDrafts::apply( if (!_checkTimer.isActive()) { _checkTimer.callOnce(kClearTimeout); } + crl::on_main(this, [=] { + crl::on_main(this, [=] { + // Thread topics create views for messages in double on_main: + // - First we postpone HistoryUpdate::Flag::ClientSideMessages. + // - Then we postpone RepliesList push of new messages list. + const auto i = _drafts.find(randomId); + if (i != end(_drafts)) { + i->second.message->markTextAppearingStarted(); + } + }); + }); } bool HistoryStreamedDrafts::update( @@ -178,7 +189,6 @@ HistoryItem *HistoryStreamedDrafts::adoptIncoming( const auto item = best->second.message.get(); _drafts.erase(best); - item->markBeingSentForAdoption(); item->setRealId(data.vid().v); if (const auto topic = item->topic()) { topic->applyMaybeLast(item); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index e568895c74..6845dc7acd 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -67,6 +67,7 @@ namespace { // A new message from the same sender is attached to previous within 15 minutes. constexpr int kAttachMessageToPreviousSecondsDelta = 900; +constexpr auto kMaxShownLine = 1024 * 1024; Element *HoveredElement/* = nullptr*/; Element *PressedElement/* = nullptr*/; @@ -1596,6 +1597,23 @@ Ui::Text::OnlyCustomEmoji Element::onlyCustomEmoji() const { return _text.toOnlyCustomEmoji(); } +void Element::skipInactiveTextAppearing() { + if (pendingResize()) { + // This message isn't displayed right now, + // so we can skip text animation. + if (const auto appearing = Get()) { + appearing->widthAnimation.stop(); + appearing->heightAnimation.stop(); + appearing->shownLine = kMaxShownLine; + appearing->shownWidth + = appearing->shownHeight + = appearing->revealedLineWidth + = 0; + appearing->geometryValid = false; + } + } +} + const Ui::Text::String &Element::text() const { return _text; } diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 08a1e3d55e..5c26a2e8b8 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -488,6 +488,7 @@ public: [[nodiscard]] HistoryItem *textItem() const; [[nodiscard]] Ui::Text::IsolatedEmoji isolatedEmoji() const; [[nodiscard]] Ui::Text::OnlyCustomEmoji onlyCustomEmoji() const; + void skipInactiveTextAppearing(); [[nodiscard]] OnlyEmojiAndSpaces isOnlyEmojiAndSpaces() const; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 994bac5fdd..6b69af99c9 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -216,12 +216,11 @@ Message::Message( } initPaidInformation(); - if (data->isTextAppearing()) { + if (data->textAppearing()) { AddComponents(TextAppearing::Bit()); - + const auto appearing = Get(); if (replacing) { if (const auto was = replacing->Get()) { - const auto appearing = Get(); *appearing = std::move(*was); appearing->widthAnimation.setCallback([=] { textAppearWidthCallback(); @@ -231,6 +230,11 @@ Message::Message( }); } } + if (data->textAppearingStarted() + && !appearing->widthAnimation.animating() + && !appearing->heightAnimation.animating()) { + skipInactiveTextAppearing(); + } } } @@ -5024,15 +5028,6 @@ int Message::resizeContentGetHeight(int newWidth) { } } - auto newHeight = minHeight(); - - if (const auto service = Get()) { - service->resizeToWidth(newWidth, delegate()->elementChatMode()); - } - - const auto botTop = item->isFakeAboutView() - ? Get() - : nullptr; const auto media = this->media(); const auto mediaDisplayed = media ? media->isDisplayed() : false; const auto bubble = drawBubble(); @@ -5076,12 +5071,34 @@ int Message::resizeContentGetHeight(int newWidth) { const auto textWidth = bubble ? bubbleTextWidth(contentWidth) : bottomInfoWidth; + + auto appearing = Get(); + if (appearing) { + if (appearing->textWidth != textWidth) { + appearing->geometryValid = false; + appearing->textWidth = textWidth; + } + // This may invalidate composer structure by removing TextAppearing. + if (!textAppearValidate(appearing)) { + appearing = nullptr; + } + } + const auto reactionsInBubble = _reactions && embedReactionsInBubble(); const auto bottomInfoHeight = _bottomInfo.resizeGetHeight( std::min( _bottomInfo.optimalSize().width(), bottomInfoWidth - 2 * st::msgDateDelta.x())); + auto newHeight = minHeight(); + + if (const auto service = Get()) { + service->resizeToWidth(newWidth, delegate()->elementChatMode()); + } + + const auto botTop = item->isFakeAboutView() + ? Get() + : nullptr; if (bubble) { auto reply = Get(); auto via = item->Get(); @@ -5095,17 +5112,6 @@ int Message::resizeContentGetHeight(int newWidth) { if (reactionsInBubble) { _reactions->resizeGetHeight(textWidth); } - - auto appearing = Get(); - if (appearing) { - if (appearing->textWidth != textWidth) { - appearing->geometryValid = false; - appearing->textWidth = textWidth; - } - if (!textAppearValidate(appearing)) { - appearing = nullptr; - } - } if (contentWidth == maxWidth() && !appearing) { if (mediaDisplayed) { if (check) { @@ -5279,10 +5285,12 @@ bool Message::textAppearCheckLine(not_null appearing) { if (data()->isRegular()) { RemoveComponents(TextAppearing::Bit()); return false; - } else if (recount) { + } else if (recount && lines) { appearing->shownLine = lines - 1; - appearing->revealedLineWidth = line ? line->width : 0; - appearing->shownHeight = line ? line->bottom : 0; + const auto &line = appearing->lines.back(); + appearing->revealedLineWidth = line.width; + appearing->shownWidth = appearing->textWidth; + appearing->shownHeight = line.bottom; appearing->widthAnimation.stop(); appearing->heightAnimation.stop(); }