Merge tag 'v6.7.5' into dev

This commit is contained in:
AlexeyZavar
2026-04-07 22:26:47 +03:00
32 changed files with 444 additions and 51 deletions
+2 -2
View File
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
constexpr auto AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs;
constexpr auto AppVersion = 6007004;
constexpr auto AppVersionStr = "6.7.4";
constexpr auto AppVersion = 6007005;
constexpr auto AppVersionStr = "6.7.5";
constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
@@ -2065,6 +2065,16 @@ rpl::producer<not_null<ViewElement*>> Session::viewResizeRequest() const {
return _viewResizeRequest.events();
}
void Session::notifyViewHeightAdjusted(
not_null<ViewElement*> view,
int delta) {
_viewHeightAdjusted.fire({ view, delta });
}
rpl::producer<Session::ViewHeightAdjusted> Session::viewHeightAdjusted() const {
return _viewHeightAdjusted.events();
}
void Session::requestItemShowHighlight(not_null<HistoryItem*> item) {
_itemShowHighlightRequest.fire_copy(item);
}
@@ -2107,6 +2117,14 @@ void Session::requestItemTextRefresh(not_null<HistoryItem*> item) {
}
}
void Session::requestItemTextRefreshStreaming(
not_null<HistoryItem*> item) {
enumerateItemViews(item, [&](not_null<ViewElement*> view) {
view->itemTextUpdatedStreaming();
});
requestItemResize(item);
}
void Session::registerRestricted(
not_null<const HistoryItem*> item,
const QString &reason) {
+8
View File
@@ -395,11 +395,18 @@ public:
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemResizeRequest() const;
void requestViewResize(not_null<ViewElement*> view);
[[nodiscard]] rpl::producer<not_null<ViewElement*>> viewResizeRequest() const;
struct ViewHeightAdjusted {
not_null<ViewElement*> view;
int delta = 0;
};
void notifyViewHeightAdjusted(not_null<ViewElement*> view, int delta);
[[nodiscard]] rpl::producer<ViewHeightAdjusted> viewHeightAdjusted() const;
void requestItemShowHighlight(not_null<HistoryItem*> item);
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> itemShowHighlightRequest() const;
void requestItemViewRefresh(not_null<const HistoryItem*> item);
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemViewRefreshRequest() const;
void requestItemTextRefresh(not_null<HistoryItem*> item);
void requestItemTextRefreshStreaming(not_null<HistoryItem*> item);
void requestUnreadReactionsAnimation(not_null<HistoryItem*> item);
void notifyHistoryUnloaded(not_null<const History*> history);
[[nodiscard]] rpl::producer<not_null<const History*>> historyUnloaded() const;
@@ -1137,6 +1144,7 @@ private:
rpl::event_stream<RequestViewRepaint> _viewRepaintRequest;
rpl::event_stream<not_null<const HistoryItem*>> _itemResizeRequest;
rpl::event_stream<not_null<ViewElement*>> _viewResizeRequest;
rpl::event_stream<ViewHeightAdjusted> _viewHeightAdjusted;
rpl::event_stream<not_null<HistoryItem*>> _itemShowHighlightRequest;
rpl::event_stream<not_null<const HistoryItem*>> _itemViewRefreshRequest;
rpl::event_stream<not_null<HistoryItem*>> _itemTextRefreshRequest;
+2
View File
@@ -365,6 +365,8 @@ enum class MessageFlag : uint64 {
CanBeSummarized = (1ULL << 58),
HasUnreadPollVote = (1ULL << 59),
TextAppearing = (1ULL << 60),
AyuNoForwards = (1ULL << 63),
};
inline constexpr bool is_flag_type(MessageFlag) { return true; }
+32
View File
@@ -1494,6 +1494,38 @@ void History::applyServiceChanges(
});
}
void History::viewHeightAdjusted(not_null<Element*> view, int delta) {
if (view->data()->mainView() == view) {
mainViewHeightAdjusted(view, delta);
}
owner().notifyViewHeightAdjusted(view, delta);
}
void History::mainViewHeightAdjusted(not_null<Element*> view, int delta) {
const auto viewInBlock = view->indexInBlock();
if (viewInBlock < 0 || _width <= 0) {
return;
}
const auto block = view->block();
for (auto i = viewInBlock + 1, count = int(block->messages.size())
; i != count
; ++i) {
const auto view = block->messages[i].get();
view->setY(view->y() + delta);
}
block->resizeGetHeight(
_width,
HistoryBlock::ResizeRequest::ResizePending);
const auto blockInHistory = block->indexInHistory();
for (auto i = blockInHistory + 1, count = int(blocks.size())
; i != count
; ++i) {
const auto block = blocks[i].get();
block->setY(block->y() + delta);
}
_height += delta;
}
void History::mainViewRemoved(
not_null<HistoryBlock*> block,
not_null<HistoryView::Element*> view) {
+2
View File
@@ -420,6 +420,7 @@ public:
PeerId dataPeerId,
const MTPmessages_Messages &data);
void viewHeightAdjusted(not_null<Element*> view, int delta);
void forgetScrollState() {
scrollTopItem = nullptr;
}
@@ -558,6 +559,7 @@ private:
void mainViewRemoved(
not_null<HistoryBlock*> block,
not_null<Element*> view);
void mainViewHeightAdjusted(not_null<Element*> view, int delta);
TimeId adjustedChatListTimeId() const override;
void changedChatListPinHook() override;
+13 -1
View File
@@ -4113,7 +4113,8 @@ FullReplyTo HistoryItem::replyTo() const {
return result;
}
void HistoryItem::setText(const TextWithEntities &textWithEntities) {
void HistoryItem::detectTextLinks(
const TextWithEntities &textWithEntities) {
auto text = textWithEntities;
const auto &settings = AyuSettings::getInstance();
if (settings.filterZalgo()) {
@@ -4133,6 +4134,10 @@ void HistoryItem::setText(const TextWithEntities &textWithEntities) {
break;
}
}
}
void HistoryItem::setText(const TextWithEntities &textWithEntities) {
detectTextLinks(textWithEntities);
setTextValue((_media && _media->consumeMessageText(text))
? TextWithEntities()
: std::move(text));
@@ -4151,6 +4156,13 @@ void HistoryItem::setTextValue(TextWithEntities text, bool force) {
}
}
void HistoryItem::setTextStreaming(TextWithEntities text) {
detectTextLinks(text);
_text = std::move(text);
RemoveComponents(HistoryMessageTranslation::Bit());
history()->owner().requestItemTextRefreshStreaming(this);
}
bool HistoryItem::inHighlightProcess() const {
return _flags & MessageFlag::InHighlightProcess;
}
@@ -345,6 +345,9 @@ public:
[[nodiscard]] bool canBeSummarized() const {
return _flags & MessageFlag::CanBeSummarized;
}
[[nodiscard]] bool isTextAppearing() const {
return _flags & MessageFlag::TextAppearing;
}
[[nodiscard]] bool hasRealFromId() const;
[[nodiscard]] bool isPostHidingAuthor() const;
[[nodiscard]] bool isPostShowingAuthor() const;
@@ -528,6 +531,7 @@ public:
}
[[nodiscard]] bool computeDropForwardedInfo() const;
void setText(const TextWithEntities &textWithEntities);
void setTextStreaming(TextWithEntities text);
[[nodiscard]] MsgId replyToId() const;
[[nodiscard]] FullMsgId replyToFullId() const;
@@ -642,6 +646,7 @@ private:
[[nodiscard]] bool generateLocalEntitiesByReply() const;
[[nodiscard]] TextWithEntities withLocalEntities(
const TextWithEntities &textWithEntities) const;
void detectTextLinks(const TextWithEntities &textWithEntities);
void setTextValue(TextWithEntities text, bool force = false);
[[nodiscard]] bool isTooOldForEdit(TimeId now) const;
[[nodiscard]] bool isLegacyMessage() const {
@@ -56,7 +56,9 @@ void HistoryStreamedDrafts::apply(
_drafts.emplace(rootId, Draft{
.message = _history->addNewLocalMessage({
.id = _history->owner().nextLocalMessageId(),
.flags = MessageFlag::Local | MessageFlag::HasReplyInfo,
.flags = (MessageFlag::Local
| MessageFlag::HasReplyInfo
| MessageFlag::TextAppearing),
.from = fromId,
.replyTo = {
.messageId = replyToId,
@@ -80,7 +82,7 @@ bool HistoryStreamedDrafts::update(
if (i == end(_drafts) || i->second.randomId != randomId) {
return false;
}
i->second.message->setText(text);
i->second.message->setTextStreaming(text);
i->second.updated = crl::now();
return true;
}
@@ -94,6 +96,13 @@ void HistoryStreamedDrafts::clear(MsgId rootId) {
}
}
bool HistoryStreamedDrafts::hasFor(not_null<HistoryItem*> item) const {
const auto rootId = item->topicRootId();
const auto i = _drafts.find(rootId);
return (i != end(_drafts))
&& (i->second.message->from() == item->from());
}
void HistoryStreamedDrafts::applyItemAdded(not_null<HistoryItem*> item) {
const auto rootId = item->topicRootId();
const auto i = _drafts.find(rootId);
@@ -25,6 +25,7 @@ public:
TimeId when,
const MTPDsendMessageTextDraftAction &data);
[[nodiscard]] bool hasFor(not_null<HistoryItem*> item) const;
void applyItemAdded(not_null<HistoryItem*> item);
void applyItemRemoved(not_null<HistoryItem*> item);
@@ -101,6 +101,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_drag_area.h"
#include "history/history_inner_widget.h"
#include "history/history_item_components.h"
#include "history/history_streamed_drafts.h"
#include "history/history_unread_things.h"
#include "history/admin_log/history_admin_log_section.h"
#include "history/view/controls/history_view_characters_limit.h"
@@ -665,6 +666,15 @@ HistoryWidget::HistoryWidget(
updateHistoryGeometry();
}
}, lifetime());
session().data().viewHeightAdjusted(
) | rpl::on_next([=](Data::Session::ViewHeightAdjusted data) {
const auto item = data.view->data();
const auto history = item->history();
if (item->mainView() == data.view
&& (history == _history || history == _migrated)) {
updateHistoryGeometry();
}
}, lifetime());
session().data().itemShowHighlightRequest(
) | rpl::on_next([=](not_null<HistoryItem*> item) {
@@ -4013,7 +4023,9 @@ void HistoryWidget::newItemAdded(not_null<HistoryItem*> item) {
}
return;
}
_itemRevealPending.emplace(item);
if (!item->history()->streamedDrafts().hasFor(item)) {
_itemRevealPending.emplace(item);
}
}
void HistoryWidget::maybeMarkReactionsRead(not_null<HistoryItem*> item) {
@@ -99,7 +99,8 @@ private:
void listMarkContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) override;
MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) override;
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) override;
void listContentRefreshed() override;
void listUpdateDateLink(
ClickHandlerPtr &link,
@@ -648,7 +649,8 @@ void Item::listMarkContentsRead(
}
MessagesBarData Item::listMessagesBar(
const std::vector<not_null<Element*>> &elements) {
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) {
if (elements.empty()) {
return {};
} else if (!_replies && !_sublist && !_history->unreadCount()) {
@@ -3132,7 +3132,8 @@ void ChatWidget::listMarkContentsRead(
}
MessagesBarData ChatWidget::listMessagesBar(
const std::vector<not_null<Element*>> &elements) {
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) {
if ((!_sublist && !_replies) || elements.empty()) {
return {};
}
@@ -3143,7 +3144,15 @@ MessagesBarData ChatWidget::listMessagesBar(
for (auto i = 0, count = int(elements.size()); i != count; ++i) {
const auto item = elements[i]->data();
if (item->isRegular() && item->id > till) {
if (item->out() || (_replies && !item->replyToId())) {
if (markLastAsRead
|| item->out()
|| (_replies && !item->replyToId())) {
if (markLastAsRead) {
if (item->isUnreadMention() && !item->isUnreadMedia()) {
session().api().markContentsRead(item);
}
item->markClientSideAsRead();
}
if (_replies) {
_replies->readTill(item);
} else {
@@ -163,7 +163,8 @@ public:
void listMarkContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) override;
MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) override;
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) override;
void listContentRefreshed() override;
void listUpdateDateLink(
ClickHandlerPtr &link,
@@ -2672,6 +2672,12 @@ void Element::itemTextUpdated() {
}
}
void Element::itemTextUpdatedStreaming() {
clearSpecialOnlyEmoji();
_text = Ui::Text::String(st::msgMinWidth);
invalidateTextSizeCache();
}
void Element::blockquoteExpandChanged() {
invalidateTextSizeCache();
history()->owner().requestViewResize(this);
@@ -626,6 +626,7 @@ public:
virtual void itemDataChanged();
void itemTextUpdated();
void itemTextUpdatedStreaming();
void blockquoteExpandChanged();
virtual void unloadHeavyPart();
@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_components.h"
#include "history/history_item_helpers.h"
#include "history/history_item_text.h"
#include "history/history_streamed_drafts.h"
#include "history/view/media/history_view_media.h"
#include "history/view/media/history_view_sticker.h"
#include "history/view/reactions/history_view_reactions.h"
@@ -467,6 +468,12 @@ ListWidget::ListWidget(
resizeItem(view);
}
}, lifetime());
_session->data().viewHeightAdjusted(
) | rpl::on_next([this](Data::Session::ViewHeightAdjusted data) {
if (data.view->delegate() == this) {
viewHeightAdjusted(data.view);
}
}, lifetime());
_session->data().itemViewRefreshRequest(
) | rpl::on_next([this](auto item) {
if (const auto view = viewForItem(item)) {
@@ -645,6 +652,10 @@ void ListWidget::refreshRows(const Data::MessagesSlice &old) {
saveScrollState();
const auto scrolledTillEnd = _itemsKnownTillEnd
&& (_visibleBottom == height())
&& (_visibleBottom > _visibleTop);
const auto addedToEndFrom = (old.skippedAfter == 0
&& (_slice.skippedAfter == 0)
&& !old.ids.empty())
@@ -682,7 +693,10 @@ void ListWidget::refreshRows(const Data::MessagesSlice &old) {
_translateTracker->addBunchFrom(_items);
}
for (auto e = end(_items), i = e - addedToEndCount; i != e; ++i) {
_itemRevealPending.emplace(*i);
const auto item = (*i)->data();
if (!item->history()->streamedDrafts().hasFor(item)) {
_itemRevealPending.emplace(*i);
}
}
updateAroundPositionFromNearest(nearestIndex);
@@ -703,7 +717,8 @@ void ListWidget::refreshRows(const Data::MessagesSlice &old) {
}
_viewsCapacity.clear();
checkUnreadBarCreation();
const auto markLastAsRead = (scrolledTillEnd && markingMessagesRead());
checkUnreadBarCreation(markLastAsRead);
restoreScrollState();
if (!_itemsRevealHeight) {
mouseActionUpdate(QCursor::pos());
@@ -984,18 +999,21 @@ void ListWidget::computeScrollTo(
scrollTo(wanted, position, scrollDelta, type);
}
void ListWidget::checkUnreadBarCreation() {
if (!_bar.element) {
if (auto data = _delegate->listMessagesBar(_items); data.bar.element) {
_bar = std::move(data.bar);
_barText = std::move(data.text);
if (!_bar.hidden) {
_bar.element->createUnreadBar(_barText.value());
const auto i = ranges::find(_items, not_null{ _bar.element });
Assert(i != end(_items));
refreshAttachmentsAtIndex(i - begin(_items));
}
}
void ListWidget::checkUnreadBarCreation(bool markLastAsRead) {
if (_bar.element) {
return;
}
auto data = _delegate->listMessagesBar(_items, markLastAsRead);
if (!data.bar.element) {
return;
}
_bar = std::move(data.bar);
_barText = std::move(data.text);
if (!_bar.hidden) {
_bar.element->createUnreadBar(_barText.value());
const auto i = ranges::find(_items, not_null{ _bar.element });
Assert(i != end(_items));
refreshAttachmentsAtIndex(i - begin(_items));
}
}
@@ -4360,6 +4378,30 @@ void ListWidget::refreshAttachmentsFromTill(int from, int till) {
}
}
void ListWidget::viewHeightAdjusted(not_null<Element*> view) {
const auto i = ranges::find(_items, view);
if (i == end(_items)) {
return;
}
auto next = i + 1;
const auto was = (next != end(_items))
? (*next)->y()
: _itemsHeight;
const auto now = view->y() + view->height();
const auto delta = now - was;
for (; next != end(_items); ++next) {
(*next)->setY((*next)->y() + delta);
}
_itemsHeight += delta;
_itemsTop = (_minHeight > _itemsHeight + st::historyPaddingBottom)
? (_minHeight - _itemsHeight - st::historyPaddingBottom)
: 0;
resize(width(), _itemsTop + _itemsHeight + st::historyPaddingBottom);
restoreScrollPosition();
updateVisibleTopItem();
update();
}
void ListWidget::refreshItem(not_null<const Element*> view) {
const auto i = ranges::find(_items, view);
const auto index = i - begin(_items);
@@ -126,7 +126,8 @@ public:
virtual void listMarkContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) = 0;
virtual MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) = 0;
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) = 0;
virtual void listContentRefreshed() = 0;
virtual void listUpdateDateLink(
ClickHandlerPtr &link,
@@ -596,6 +597,7 @@ private:
void repaintItem(const Element *view, QRect rect);
void resizeItem(not_null<Element*> view);
void refreshItem(not_null<const Element*> view);
void viewHeightAdjusted(not_null<Element*> view);
void showItemHighlight(not_null<HistoryItem*> item);
void itemRemoved(not_null<const HistoryItem*> item);
QPoint mapPointToItem(QPoint point, const Element *view) const;
@@ -716,7 +718,7 @@ private:
TextSelection computeRenderSelection(
not_null<const SelectedMap*> selected,
not_null<const Element*> view) const;
void checkUnreadBarCreation();
void checkUnreadBarCreation(bool markLastAsRead = false);
void applyUpdatedScrollState();
void scrollToAnimationCallback(FullMsgId attachToId, int relativeTo);
void startItemRevealAnimations();
@@ -74,6 +74,8 @@ constexpr auto kSummarizeThreshold = 512;
constexpr auto kPlayStatusLimit = 12;
constexpr auto kMaxNiceToReadLines = 6;
const auto kPsaTooltipPrefix = "cloud_lng_tooltip_psa_";
constexpr auto kFullLineAppearDuration = crl::time(300);
constexpr auto kLineHeightAppearDuration = crl::time(100);
struct SecondRightAction {
std::unique_ptr<Ui::RippleAnimation> ripple;
@@ -668,6 +670,11 @@ QSize Message::performCountOptimalSize() {
} else {
RemoveComponents(Factcheck::Bit());
}
if (item->isTextAppearing()) {
AddComponents(TextAppearing::Bit());
} else {
RemoveComponents(TextAppearing::Bit());
}
refreshRightBadge();
const auto markup = item->inlineReplyMarkup();
@@ -901,6 +908,9 @@ QSize Message::performCountOptimalSize() {
minHeight -= text().minHeight();
minHeight += textHeightFor(bubbleTextWidth(maxWidth));
}
if (const auto appearing = Get<TextAppearing>()) {
appearing->geometryValid = false;
}
return QSize(maxWidth, minHeight);
}
@@ -2260,6 +2270,37 @@ void Message::paintText(
.outPath = &ripplePath,
};
const auto appearing = Get<TextAppearing>();
if (appearing
&& (appearing->shownLines > 0)
&& (appearing->shownLines <= int(appearing->lines.size()))) {
const auto lastLineIndex = appearing->shownLines - 1;
p.save();
auto clipPath = QPainterPath();
const auto prevBottom = (lastLineIndex > 0)
? appearing->lines[lastLineIndex - 1].top
: 0;
if (prevBottom > 0) {
clipPath.addRect(
trect.x(),
trect.y(),
trect.width(),
prevBottom);
}
const auto lastLineHeight = appearing->lines[lastLineIndex].top
- prevBottom;
const auto &lastLine = appearing->lines[lastLineIndex];
const auto clipLeft = lastLine.rtl
? (trect.x() + trect.width() - appearing->revealedLineWidth)
: trect.x();
clipPath.addRect(
clipLeft,
trect.y() + prevBottom,
appearing->revealedLineWidth,
lastLineHeight);
p.setClipPath(clipPath);
}
auto highlightRequest = context.computeHighlightCache();
text().draw(p, {
.position = trect.topLeft(),
@@ -2290,6 +2331,10 @@ void Message::paintText(
} else if (needRippleMask) {
_linkRipple = nullptr;
}
if (appearing && appearing->shownLines > 0
&& appearing->shownLines <= int(appearing->lines.size())) {
p.restore();
}
}
PointState Message::pointState(QPoint point) const {
@@ -4958,6 +5003,19 @@ QRect Message::countGeometry() const {
contentWidth = mediaWidth;
}
}
if (const auto appearing = Get<TextAppearing>()) {
if (appearing->shownWidth > 0) {
const auto animatedWidth = st::msgPadding.left()
+ appearing->shownWidth
+ st::msgPadding.right();
const auto minWidth = _bottomInfo.optimalSize().width()
+ st::msgPadding.left()
+ st::msgPadding.right();
accumulate_min(contentWidth, std::max(
animatedWidth,
minWidth));
}
}
if (contentWidth < availableWidth
&& delegate()->elementChatMode() != ElementChatMode::Wide) {
if (outbg) {
@@ -5117,7 +5175,8 @@ int Message::resizeContentGetHeight(int newWidth) {
_reactions->resizeGetHeight(textWidth);
}
if (contentWidth == maxWidth()) {
const auto appearing = Get<TextAppearing>();
if (contentWidth == maxWidth() && !appearing) {
if (mediaDisplayed) {
if (check) {
newHeight += check->resizeGetHeight(contentWidth) + st::mediaInBubbleSkip;
@@ -5141,7 +5200,31 @@ int Message::resizeContentGetHeight(int newWidth) {
if (botTop) {
newHeight += botTop->height;
}
newHeight += textHeightFor(textWidth);
const auto fullTextHeight = textHeightFor(textWidth);
if (appearing) {
if (!appearing->geometryValid
|| appearing->textWidth != textWidth) {
appearing->textWidth = textWidth;
appearing->lines = text().countLinesGeometry(
textWidth);
appearing->geometryValid = true;
if (appearing->shownHeight <= 0) {
appearing->shownHeight = appearing->lines.empty()
? text().lineHeight()
: appearing->lines.front().top;
appearing->shownLines = 1;
appearing->revealedLineWidth = 0;
appearing->shownWidth = 0;
startTextAppearingWidthAnimation();
} else if (!appearing->heightStarted
&& !appearing->widthAnimation.animating()) {
startTextAppearingHeightAnimation();
}
}
newHeight += appearing->shownHeight;
} else {
newHeight += fullTextHeight;
}
}
if (!mediaOnBottom && (!_viewButton || !reactionsInBubble)) {
newHeight += st::msgPadding.bottom();
@@ -5255,6 +5338,119 @@ void Message::invalidateTextDependentCache() {
_bubbleTextualWidthCache = 0;
}
void Message::startTextAppearingWidthAnimation() {
const auto appearing = Get<TextAppearing>();
if (!appearing || appearing->lines.empty()) {
return;
}
const auto lineIndex = appearing->shownLines - 1;
if (lineIndex < 0
|| lineIndex >= int(appearing->lines.size())) {
return;
}
appearing->heightStarted = false;
appearing->revealedLineWidth = 0;
const auto lineWidth = appearing->lines[lineIndex].width;
const auto duration = std::max(
kFullLineAppearDuration * lineWidth / st::msgMaxWidth,
crl::time(10));
appearing->widthDuration = duration;
appearing->widthAnimation.start(
[=] { textAppearingTick(); },
0.,
1.,
duration,
anim::linear);
}
void Message::startTextAppearingHeightAnimation() {
const auto appearing = Get<TextAppearing>();
if (!appearing
|| appearing->heightStarted
|| (appearing->shownLines >= int(appearing->lines.size()))) {
return;
}
appearing->heightStarted = true;
const auto oldHeight = appearing->shownHeight;
const auto newTargetHeight = appearing->lines[appearing->shownLines].top;
appearing->heightAnimation.start(
[=] { textAppearingHeightTick(); },
double(oldHeight),
double(newTargetHeight),
kLineHeightAppearDuration,
anim::easeOutCubic);
}
void Message::textAppearingTick() {
auto appearing = Get<TextAppearing>();
if (!appearing) {
return;
}
const auto lineIndex = appearing->shownLines - 1;
if (lineIndex < 0
|| lineIndex >= int(appearing->lines.size())) {
return;
}
const auto progress = appearing->widthAnimation.value(1.);
appearing->revealedLineWidth = int(
appearing->lines[lineIndex].width * progress);
appearing->shownWidth = std::max(
appearing->shownWidth,
appearing->revealedLineWidth);
const auto hasMoreLines =
(appearing->shownLines < int(appearing->lines.size()));
const auto remaining = crl::time(
appearing->widthDuration * (1. - progress));
if (hasMoreLines
&& (remaining <= kLineHeightAppearDuration)
&& !appearing->heightStarted) {
startTextAppearingHeightAnimation();
}
if (!appearing->widthAnimation.animating()) {
tryAdvanceTextAppearing();
}
repaint();
}
void Message::textAppearingHeightTick() {
auto appearing = Get<TextAppearing>();
if (!appearing) {
return;
}
const auto targetHeight = appearing->lines[appearing->shownLines].top;
const auto oldShownHeight = appearing->shownHeight;
appearing->shownHeight = int(base::SafeRound(
appearing->heightAnimation.value(targetHeight)));
const auto delta = appearing->shownHeight - oldShownHeight;
if (delta) {
adjustHeight(delta);
history()->viewHeightAdjusted(this, delta);
}
if (!appearing->heightAnimation.animating()) {
tryAdvanceTextAppearing();
}
}
void Message::tryAdvanceTextAppearing() {
auto appearing = Get<TextAppearing>();
if (!appearing) {
return;
}
if (appearing->widthAnimation.animating()
|| appearing->heightAnimation.animating()) {
return;
}
if (appearing->shownLines < int(appearing->lines.size())) {
appearing->shownLines++;
startTextAppearingWidthAnimation();
}
}
bool Message::needInfoDisplay() const {
const auto media = this->media();
const auto mediaDisplayed = media ? media->isDisplayed() : false;
@@ -83,6 +83,20 @@ struct RightBadge : RuntimeComponent<RightBadge, Element> {
mutable QPoint lastPoint;
};
struct TextAppearing : RuntimeComponent<TextAppearing, Element> {
std::vector<Ui::Text::LineLayoutInfo> lines;
int textWidth = 0;
int shownLines = 0;
int revealedLineWidth = 0;
int shownWidth = 0;
int shownHeight = 0;
crl::time widthDuration = 0;
Ui::Animations::Simple widthAnimation;
Ui::Animations::Simple heightAnimation;
bool geometryValid = false;
bool heightStarted = false;
};
struct BottomRippleMask {
QImage image;
int shift = 0;
@@ -373,6 +387,11 @@ private:
[[nodiscard]] ClickHandlerPtr psaTooltipLink() const;
void psaTooltipToggled(bool shown) const;
void invalidateTextDependentCache() override;
void startTextAppearingWidthAnimation();
void startTextAppearingHeightAnimation();
void textAppearingTick();
void textAppearingHeightTick();
void tryAdvanceTextAppearing();
void refreshRightBadge();
[[nodiscard]] int rightBadgeWidth() const;
@@ -54,6 +54,9 @@ protected:
_width = size.width();
_height = size.height();
}
void adjustHeight(int delta) {
_height += delta;
}
private:
virtual QSize countOptimalSize() = 0;
@@ -608,7 +608,8 @@ void PinnedWidget::listMarkContentsRead(
}
MessagesBarData PinnedWidget::listMessagesBar(
const std::vector<not_null<Element*>> &elements) {
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) {
return {};
}
@@ -97,7 +97,8 @@ public:
void listMarkContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) override;
MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) override;
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) override;
void listContentRefreshed() override;
void listUpdateDateLink(
ClickHandlerPtr &link,
@@ -1472,7 +1472,8 @@ void ScheduledWidget::listMarkContentsRead(
}
MessagesBarData ScheduledWidget::listMessagesBar(
const std::vector<not_null<Element*>> &elements) {
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) {
return {};
}
@@ -139,7 +139,8 @@ public:
void listMarkContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) override;
MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) override;
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) override;
void listContentRefreshed() override;
void listUpdateDateLink(
ClickHandlerPtr &link,
@@ -106,8 +106,8 @@ private:
void listMarkContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) override;
HistoryView::MessagesBarData listMessagesBar(
const std::vector<not_null<HistoryView::Element*>> &elements)
override;
const std::vector<not_null<HistoryView::Element*>> &elements,
bool markLastAsRead) override;
void listContentRefreshed() override;
void listUpdateDateLink(
ClickHandlerPtr &link,
@@ -522,7 +522,8 @@ void ListWidget::Inner::listMarkContentsRead(
}
HistoryView::MessagesBarData ListWidget::Inner::listMessagesBar(
const std::vector<not_null<HistoryView::Element*>> &elements) {
const std::vector<not_null<HistoryView::Element*>> &elements,
bool markLastAsRead) {
return {};
}
@@ -128,7 +128,8 @@ private:
void listMarkContentsRead(
const base::flat_set<not_null<HistoryItem*>> &items) override;
MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) override;
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) override;
void listContentRefreshed() override;
void listUpdateDateLink(
ClickHandlerPtr &link,
@@ -911,7 +912,8 @@ void ShortcutMessages::listMarkContentsRead(
}
MessagesBarData ShortcutMessages::listMessagesBar(
const std::vector<not_null<Element*>> &elements) {
const std::vector<not_null<Element*>> &elements,
bool markLastAsRead) {
return {};
}