From b2eeab53c5bf69e2be4eddc8b8f626415c7a41c2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 6 Nov 2023 12:35:27 +0400 Subject: [PATCH] Improve 5-line reply text elision. --- .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 4 +- .../dialogs/ui/dialogs_topics_view.cpp | 2 +- Telegram/SourceFiles/history/history_item.cpp | 10 +-- .../history/history_item_components.cpp | 19 ++++-- .../history/history_item_components.h | 2 + .../SourceFiles/history/history_widget.cpp | 2 +- .../history_view_compose_controls.cpp | 2 +- .../controls/history_view_draft_options.cpp | 4 ++ .../controls/history_view_forward_panel.cpp | 2 +- .../history/view/history_view_reply.cpp | 61 ++++++++----------- .../history/view/history_view_reply.h | 6 +- .../view/media/history_view_giveaway.cpp | 2 +- Telegram/SourceFiles/ui/chat/message_bar.cpp | 2 +- .../window/notifications_manager_default.cpp | 2 +- Telegram/lib_ui | 2 +- 15 files changed, 65 insertions(+), 57 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 4b9c3fe87..e71c3cefd 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -420,7 +420,7 @@ void PaintRow( .now = context.now, .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), - .elisionOneLine = true, + .elisionLines = 1, }); } else if (draft || (supportMode @@ -514,7 +514,7 @@ void PaintRow( .now = context.now, .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), - .elisionOneLine = true, + .elisionLines = 1, }); } } else if (!item) { diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_topics_view.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_topics_view.cpp index f9fe16062..cd312fd85 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_topics_view.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_topics_view.cpp @@ -141,7 +141,7 @@ void TopicsView::paint( .now = context.now, .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), - .elisionOneLine = true, + .elisionLines = 1, }); const auto skip = skipBig ? context.st->topicsSkipBig diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 0a3d3563d..18235872c 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -3349,13 +3349,15 @@ void HistoryItem::createComponentsHelper( : (replyTo.messageId.peer == history()->peer->id) ? replyTo.messageId.msg : MsgId(); + const auto forum = _history->asForum(); + const auto topic = forum + ? forum->topicFor(replyTo.topicRootId) + : nullptr; if (!config.reply.externalPeerId - && to - && config.reply.topicPost - && replyTo.topicRootId != to->topicRootId()) { + && topic + && topic->rootId() != to->topicRootId()) { config.reply.externalPeerId = replyTo.messageId.peer; } - const auto forum = _history->asForum(); config.reply.topicPost = config.reply.externalPeerId ? (replyTo.topicRootId && (replyTo.topicRootId != Data::ForumTopic::kGeneralId)) diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index e4438b1c5..66e30a58d 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -424,12 +424,14 @@ bool HistoryMessageReply::updateData( } } - const auto external = this->external(); - _multiline = !_fields.storyId && (external || !_fields.quote.empty()); + const auto asExternal = displayAsExternal(holder); + const auto nonEmptyQuote = !_fields.quote.empty() + && (asExternal || _fields.manualQuote); + _multiline = !_fields.storyId && (asExternal || nonEmptyQuote); const auto displaying = resolvedMessage || resolvedStory - || ((!_fields.quote.empty() || _fields.externalMedia) + || ((nonEmptyQuote || _fields.externalMedia) && (!_fields.messageId || force)); _displaying = displaying ? 1 : 0; @@ -446,7 +448,7 @@ bool HistoryMessageReply::updateData( } return resolvedMessage || resolvedStory - || (external && !_fields.messageId && !_fields.storyId) + || (!_fields.messageId && !_fields.storyId && external()) || _unavailable; } @@ -508,6 +510,15 @@ bool HistoryMessageReply::external() const { || !_fields.externalSenderName.isEmpty(); } +bool HistoryMessageReply::displayAsExternal( + not_null holder) const { + // Don't display replies that could be local as external. + return external() + && (!resolvedMessage + || (holder->history() != resolvedMessage->history()) + || (holder->topicRootId() != resolvedMessage->topicRootId())); +} + void HistoryMessageReply::itemRemoved( not_null holder, not_null removed) { diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index f78671ba3..3d363225f 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -279,6 +279,8 @@ struct HistoryMessageReply void clearData(not_null holder); [[nodiscard]] bool external() const; + [[nodiscard]] bool displayAsExternal( + not_null holder) const; void itemRemoved( not_null holder, not_null removed); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 60c32aded..7206e6a2b 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -7951,7 +7951,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { .now = now, .pausedEmoji = paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = pausedSpoiler, - .elisionOneLine = true, + .elisionLines = 1, }); } else { p.setFont(st::msgDateFont); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 21ce63e1a..540d4ca5f 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -629,7 +629,7 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) { .now = crl::now(), .pausedEmoji = p.inactive() || On(PowerSaving::kEmojiChat), .pausedSpoiler = p.inactive() || On(PowerSaving::kChatSpoiler), - .elisionOneLine = true, + .elisionLines = 1, }); } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index 65a1cd6de..850ecfe6b 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -669,6 +669,7 @@ void DraftOptionsBox( }); } + const auto weak = Ui::MakeWeak(box); Settings::AddButton( bottom, tr::lng_reply_show_in_chat(), @@ -676,6 +677,9 @@ void DraftOptionsBox( { &st::menuIconShowInChat } )->setClickedCallback([=] { highlight(resolveReply()); + if (const auto strong = weak.data()) { + strong->closeBox(); + } }); Settings::AddButton( diff --git a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp index 98799149f..85dadd5d8 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp @@ -396,7 +396,7 @@ void ForwardPanel::paint( .now = now, .pausedEmoji = paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = pausedSpoiler, - .elisionOneLine = true, + .elisionLines = 1, }); } diff --git a/Telegram/SourceFiles/history/view/history_view_reply.cpp b/Telegram/SourceFiles/history/view/history_view_reply.cpp index 287337823..f6c069db7 100644 --- a/Telegram/SourceFiles/history/view/history_view_reply.cpp +++ b/Telegram/SourceFiles/history/view/history_view_reply.cpp @@ -210,10 +210,10 @@ void Reply::update( const auto text = (!_displaying && data->unavailable()) ? TextWithEntities() + : (message && (fields.quote.empty() || !fields.manualQuote)) + ? message->inReplyText() : !fields.quote.empty() ? fields.quote - : message - ? message->inReplyText() : story ? story->inReplyText() : externalMedia @@ -400,7 +400,9 @@ void Reply::updateName( const auto externalPeer = fields.externalPeerId ? view->history()->owner().peer(fields.externalPeerId).get() : nullptr; - const auto groupNameAdded = externalPeer + const auto displayAsExternal = data->displayAsExternal(view->data()); + const auto groupNameAdded = displayAsExternal + && externalPeer && (externalPeer != sender) && (externalPeer->isChat() || externalPeer->isMegagroup()); const auto shorten = !viaBotUsername.isEmpty() || groupNameAdded; @@ -433,7 +435,7 @@ void Reply::updateName( icon.second)); }; auto nameFull = TextWithEntities(); - if (!groupNameAdded && data->external() && !fields.storyId) { + if (displayAsExternal && !groupNameAdded && !fields.storyId) { nameFull.append(peerEmoji(sender)); } nameFull.append(name); @@ -509,7 +511,7 @@ int Reply::resizeToWidth(int width) const { : 0; if (width >= _maxWidth || !_multiline) { _nameTwoLines = 0; - _expandable = 0; + _expandable = _minHeightExpandable; _height = _minHeight; return height(); } @@ -521,20 +523,13 @@ int Reply::resizeToWidth(int width) const { _nameTwoLines = (desiredNameHeight > st::semiboldFont->height) ? 1 : 0; const auto nameh = (_nameTwoLines ? 2 : 1) * st::semiboldFont->height; const auto firstLineSkip = _nameTwoLines ? 0 : previewSkip; - auto lineCounter = 0; auto elided = false; const auto texth = _text.countDimensions( - textGeometry(innerw, firstLineSkip, &lineCounter, &elided)).height; - const auto useh = elided - ? (kNonExpandedLinesLimit * st::normalFont->height) - : std::max(texth, st::normalFont->height); - if (!texth) { - int a = 0; - } - _expandable = (_multiline && elided) ? 1 : 0; + textGeometry(innerw, firstLineSkip, &elided)).height; + _expandable = elided ? 1 : 0; _height = st::historyReplyPadding.top() + nameh - + useh + + std::max(texth, st::normalFont->height) + st::historyReplyPadding.bottom(); return height(); } @@ -542,21 +537,17 @@ int Reply::resizeToWidth(int width) const { Ui::Text::GeometryDescriptor Reply::textGeometry( int available, int firstLineSkip, - not_null line, - not_null outElided) const { - return { .layout = [=](Ui::Text::LineGeometry in) { - const auto skip = (*line ? 0 : firstLineSkip); - ++*line; - *outElided = *outElided - || !_multiline - || (!_expanded - && (*line == kNonExpandedLinesLimit) - && in.width > available - skip); - in.width = available - skip; - in.left += skip; - in.elided = *outElided; - return in; - } }; + bool *outElided) const { + return { .layout = [=](int line) { + const auto skip = (line ? 0 : firstLineSkip); + const auto elided = !_multiline + || (!_expanded && (line + 1 >= kNonExpandedLinesLimit)); + return Ui::Text::LineGeometry{ + .left = skip, + .width = available - skip, + .elided = elided, + }; + }, .outElided = outElided }; } int Reply::height() const { @@ -570,10 +561,10 @@ QMargins Reply::margins() const { QSize Reply::countMultilineOptimalSize( int previewSkip) const { auto elided = false; - auto lineCounter = 0; const auto max = previewSkip + _text.maxWidth(); const auto result = _text.countDimensions( - textGeometry(max, previewSkip, &lineCounter, &elided)); + textGeometry(max, previewSkip, &elided)); + _minHeightExpandable = elided ? 1 : 0; return { result.width, std::max(result.height, st::normalFont->height), @@ -767,18 +758,16 @@ void Reply::paint( copy->linkFg = owned->color(); replyToTextPalette = &*copy; } - auto l = 0; - auto e = false; _text.draw(p, { .position = { textLeft, textTop }, - .geometry = textGeometry(textw, firstLineSkip, &l, &e), + .geometry = textGeometry(textw, firstLineSkip), .palette = replyToTextPalette, .spoiler = Ui::Text::DefaultSpoilerCache(), .now = context.now, .pausedEmoji = (context.paused || On(PowerSaving::kEmojiChat)), .pausedSpoiler = pausedSpoiler, - .elisionOneLine = true, + .elisionLines = 1, }); p.setTextPalette(stm->textPalette); } diff --git a/Telegram/SourceFiles/history/view/history_view_reply.h b/Telegram/SourceFiles/history/view/history_view_reply.h index 10b5ebb9b..5322d5c09 100644 --- a/Telegram/SourceFiles/history/view/history_view_reply.h +++ b/Telegram/SourceFiles/history/view/history_view_reply.h @@ -67,8 +67,7 @@ private: [[nodiscard]] Ui::Text::GeometryDescriptor textGeometry( int available, int firstLineSkip, - not_null line, - not_null outElided) const; + bool *outElided = nullptr) const; [[nodiscard]] QSize countMultilineOptimalSize( int firstLineSkip) const; void setLinkFrom( @@ -101,11 +100,12 @@ private: mutable int _minHeight = 0; mutable int _height = 0; mutable int _nameVersion = 0; - uint8 _hiddenSenderColorIndexPlusOne = 0; + uint8 _hiddenSenderColorIndexPlusOne : 7 = 0; uint8 _hasQuoteIcon : 1 = 0; uint8 _replyToStory : 1 = 0; uint8 _expanded : 1 = 0; mutable uint8 _expandable : 1 = 0; + mutable uint8 _minHeightExpandable : 1 = 0; mutable uint8 _nameTwoLines : 1 = 0; mutable uint8 _hasPreview : 1 = 0; mutable uint8 _displaying : 1 = 0; diff --git a/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp b/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp index dceb0cd1d..350ba3668 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp @@ -388,7 +388,7 @@ void Giveaway::paintChannels( .align = style::al_left, .palette = &stm->textPalette, .now = context.now, - .elisionOneLine = true, + .elisionLines = 1, .elisionBreakEverywhere = true, }); } diff --git a/Telegram/SourceFiles/ui/chat/message_bar.cpp b/Telegram/SourceFiles/ui/chat/message_bar.cpp index d6b441771..47f7056e4 100644 --- a/Telegram/SourceFiles/ui/chat/message_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/message_bar.cpp @@ -455,7 +455,7 @@ void MessageBar::paint(Painter &p) { .now = now, .pausedEmoji = paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = pausedSpoiler, - .elisionOneLine = true, + .elisionLines = 1, }); } } else if (_animation->bodyAnimation == BodyAnimation::Text) { diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index 4454587d2..ec2e8a1c0 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -828,7 +828,7 @@ void Notification::paintTitle(Painter &p) { .spoiler = Ui::Text::DefaultSpoilerCache(), .pausedEmoji = On(PowerSaving::kEmojiChat), .pausedSpoiler = On(PowerSaving::kChatSpoiler), - .elisionOneLine = true, + .elisionLines = 1, }); } diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 08235c5e0..65310f32d 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 08235c5e06ac56564157f2856702804a2149d45e +Subproject commit 65310f32dcc980aeca0b13253b1278a6f3ce722e