Support collapsible blockquotes in Ui::Text::String.

This commit is contained in:
John Preston 2024-05-30 15:05:13 +04:00
parent 974bf99921
commit 40fbd415ef
16 changed files with 84 additions and 31 deletions

View file

@ -837,14 +837,14 @@ PRIVATE
history/view/history_view_send_action.h
history/view/history_view_service_message.cpp
history/view/history_view_service_message.h
history/view/history_view_spoiler_click_handler.cpp
history/view/history_view_spoiler_click_handler.h
history/view/history_view_sponsored_click_handler.cpp
history/view/history_view_sponsored_click_handler.h
history/view/history_view_sticker_toast.cpp
history/view/history_view_sticker_toast.h
history/view/history_view_sublist_section.cpp
history/view/history_view_sublist_section.h
history/view/history_view_text_helper.cpp
history/view/history_view_text_helper.h
history/view/history_view_transcribe_button.cpp
history/view/history_view_transcribe_button.h
history/view/history_view_translate_bar.cpp

View file

@ -217,6 +217,7 @@ EntitiesInText EntitiesFromMTP(
EntityType::Blockquote,
d.voffset().v,
d.vlength().v,
d.is_collapsed() ? u"1"_q : QString(),
});
});
}
@ -311,8 +312,13 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
MTP_string(entity.data())));
} break;
case EntityType::Blockquote: {
using Flag = MTPDmessageEntityBlockquote::Flag;
const auto collapsed = !entity.data().isEmpty();
v.push_back(
MTP_messageEntityBlockquote(MTP_flags(0), offset, length));
MTP_messageEntityBlockquote(
MTP_flags(collapsed ? Flag::f_collapsed : Flag()),
offset,
length));
} break;
case EntityType::Spoiler: {
v.push_back(MTP_messageEntitySpoiler(offset, length));

View file

@ -748,7 +748,8 @@ void MessageLinksParser::parse() {
|| (tag == Ui::InputField::kTagUnderline)
|| (tag == Ui::InputField::kTagStrikeOut)
|| (tag == Ui::InputField::kTagSpoiler)
|| (tag == Ui::InputField::kTagBlockquote);
|| (tag == Ui::InputField::kTagBlockquote)
|| (tag == Ui::InputField::kTagBlockquoteCollapsed);
};
_ranges.clear();

View file

@ -1820,12 +1820,19 @@ rpl::producer<not_null<HistoryItem*>> Session::itemDataChanges() const {
}
void Session::requestItemTextRefresh(not_null<HistoryItem*> item) {
if (const auto i = _views.find(item); i != _views.end()) {
for (const auto &view : i->second) {
view->itemTextUpdated();
const auto call = [&](not_null<HistoryItem*> item) {
if (const auto i = _views.find(item); i != _views.end()) {
for (const auto &view : i->second) {
view->itemTextUpdated();
}
}
requestItemResize(item);
};
if (const auto group = groups().find(item)) {
call(group->items.front());
} else {
call(item);
}
requestItemResize(item);
}
void Session::registerHighlightProcess(

View file

@ -307,6 +307,8 @@ std::vector<TextPart> ParseText(
return NumberToString(data.vuser_id().v);
}, [](const MTPDmessageEntityCustomEmoji &data) {
return NumberToString(data.vdocument_id().v);
}, [](const MTPDmessageEntityBlockquote &data) {
return data.is_collapsed() ? Utf8String("1") : Utf8String();
}, [](const auto &) { return Utf8String(); });
result.push_back(std::move(part));

View file

@ -195,6 +195,8 @@ QByteArray SerializeText(
? "language"
: (part.type == Type::TextUrl)
? "href"
: (part.type == Type::Blockquote)
? "collapsed"
: "none";
const auto additionalValue = (part.type == Type::MentionName)
? part.additional
@ -202,6 +204,8 @@ QByteArray SerializeText(
|| part.type == Type::TextUrl
|| part.type == Type::CustomEmoji)
? SerializeString(part.additional)
: (part.type == Type::Blockquote)
? (part.additional.isEmpty() ? "false" : "true")
: QByteArray();
return SerializeObject(context, {
{ "type", SerializeString(typeString) },

View file

@ -18,7 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/reactions/history_view_reactions.h"
#include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_reply.h"
#include "history/view/history_view_spoiler_click_handler.h"
#include "history/view/history_view_text_helper.h"
#include "history/history.h"
#include "history/history_item_components.h"
#include "history/history_item_helpers.h"
@ -1027,7 +1027,7 @@ void Element::setTextWithLinks(
refreshMedia(nullptr);
}
}
FillTextWithAnimatedSpoilers(this, _text);
InitElementTextPart(this, _text);
_textWidth = -1;
_textHeight = 0;
}
@ -1464,6 +1464,12 @@ void Element::itemTextUpdated() {
}
}
void Element::blockquoteExpandChanged() {
_textWidth = -1;
_textHeight = 0;
history()->owner().requestViewResize(this);
}
void Element::unloadHeavyPart() {
history()->owner().unregisterHeavyViewPart(this);
if (_media) {

View file

@ -498,6 +498,7 @@ public:
virtual void itemDataChanged();
void itemTextUpdated();
void blockquoteExpandChanged();
[[nodiscard]] virtual bool hasHeavyPart() const;
virtual void unloadHeavyPart();

View file

@ -5,7 +5,7 @@ the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_spoiler_click_handler.h"
#include "history/view/history_view_text_helper.h"
#include "data/data_session.h"
#include "history/view/history_view_element.h"
@ -15,9 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView {
void FillTextWithAnimatedSpoilers(
not_null<Element*> view,
Ui::Text::String &text) {
void InitElementTextPart(not_null<Element*> view, Ui::Text::String &text) {
if (text.hasSpoilers()) {
text.setSpoilerLinkFilter([weak = base::make_weak(view)](
const ClickContext &context) {
@ -30,6 +28,14 @@ void FillTextWithAnimatedSpoilers(
return true;
});
}
if (text.hasCollapsedBlockquots()) {
const auto weak = base::make_weak(view);
text.setBlockquoteExpandCallback([=](int quoteIndex, bool expanded) {
if (const auto view = weak.get()) {
view->blockquoteExpandChanged();
}
});
}
}
} // namespace HistoryView

View file

@ -11,8 +11,6 @@ namespace HistoryView {
class Element;
void FillTextWithAnimatedSpoilers(
not_null<Element*> view,
Ui::Text::String &text);
void InitElementTextPart(not_null<Element*> view, Ui::Text::String &text);
} // namespace HistoryView

View file

@ -1490,8 +1490,12 @@ QMargins Document::bubbleMargins() const {
}
void Document::refreshCaption(bool last) {
const auto now = Get<HistoryDocumentCaptioned>();
auto caption = createCaption();
if (!caption.isEmpty()) {
if (now) {
return;
}
AddComponents(HistoryDocumentCaptioned::Bit());
auto captioned = Get<HistoryDocumentCaptioned>();
captioned->caption = std::move(caption);
@ -1503,7 +1507,7 @@ void Document::refreshCaption(bool last) {
} else {
captioned->caption.removeSkipBlock();
}
} else {
} else if (now) {
RemoveComponents(HistoryDocumentCaptioned::Bit());
}
}
@ -1637,7 +1641,7 @@ void Document::refreshParentId(not_null<HistoryItem*> realParent) {
}
void Document::parentTextUpdated() {
history()->owner().requestViewResize(_parent);
RemoveComponents(HistoryDocumentCaptioned::Bit());
}
void Document::hideSpoilers() {

View file

@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_spoiler_click_handler.h"
#include "history/view/history_view_text_helper.h"
#include "history/view/media/history_view_sticker.h"
#include "history/view/media/history_view_media_spoiler.h"
#include "storage/storage_shared_media.h"
@ -319,7 +319,7 @@ Ui::Text::String Media::createCaption(not_null<HistoryItem*> item) const {
item->translatedTextWithLocalEntities(),
Ui::ItemTextOptions(item),
context);
FillTextWithAnimatedSpoilers(_parent, result);
InitElementTextPart(_parent, result);
if (const auto width = _parent->skipBlockWidth()) {
result.updateSkipBlock(width, _parent->skipBlockHeight());
}

View file

@ -781,7 +781,13 @@ void GroupedMedia::unloadHeavyPart() {
void GroupedMedia::parentTextUpdated() {
if (_parent->media() == this) {
_captionItem = std::nullopt;
if (_mode == Mode::Column) {
for (const auto &part : _parts) {
part.content->parentTextUpdated();
}
} else {
_captionItem = std::nullopt;
}
}
}

View file

@ -282,7 +282,9 @@ WebPage::WebPage(
not_null<WebPageData*> data,
MediaWebPageFlags flags)
: Media(parent)
, _st(st::historyPagePreview)
, _st(data->type == WebPageType::Factcheck
? st::factcheckPage
: st::historyPagePreview)
, _data(data)
, _flags(flags)
, _siteName(st::msgMinWidth - _st.padding.left() - _st.padding.right())
@ -859,13 +861,14 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
FillBackgroundEmoji(p, outer, false, *backgroundEmojiCache);
}
} else if (factcheck && factcheck->expandable) {
const auto &icon = factcheck->expanded
? st::factcheckIconCollapse
: st::factcheckIconExpand;
const auto &icon = factcheck->expanded ? _st.collapse : _st.expand;
const auto &position = factcheck->expanded
? _st.collapsePosition
: _st.expandPosition;
icon.paint(
p,
outer.x() + outer.width() - icon.width() - _st.padding.right(),
outer.y() + _st.padding.top(),
outer.x() + outer.width() - icon.width() - position.x(),
outer.y() + outer.height() - icon.height() - position.y(),
width());
}

View file

@ -66,6 +66,10 @@ messageTextStyle: TextStyle(defaultTextStyle) {
padding: margins(10px, 2px, 20px, 2px);
icon: icon{{ "chat/mini_quote", windowFg }};
iconPosition: point(4px, 4px);
expand: icon{{ "intro_country_dropdown", windowFg }};
expandPosition: point(6px, 4px);
collapse: icon{{ "intro_country_dropdown-flip_vertical", windowFg }};
collapsePosition: point(6px, 4px);
}
pre: QuoteStyle(messageQuoteStyle) {
header: 20px;
@ -1137,8 +1141,13 @@ factcheckFooterSkip: 16px;
factcheckFooterStyle: TextStyle(defaultTextStyle) {
font: font(11px);
}
factcheckIconExpand: icon {{ "fast_to_original-rotate_cw", historyPeer1NameFg }};
factcheckIconCollapse: icon {{ "fast_to_original-rotate_ccw", historyPeer1NameFg }};
factcheckPage: QuoteStyle(historyPagePreview) {
padding: margins(10px, 5px, 22px, 7px);
expand: icon {{ "intro_country_dropdown", historyPeer1NameFg }};
expandPosition: point(6px, 4px);
collapse: icon {{ "intro_country_dropdown-flip_vertical", historyPeer1NameFg }};
collapsePosition: point(6px, 4px);
}
factcheckField: InputField(defaultInputField) {
textBg: transparent;
textMargins: margins(0px, 0px, 0px, 4px);

@ -1 +1 @@
Subproject commit 0835adcc2d3cb1f2cf0d3630f6d95485864621f9
Subproject commit 495ea0af50da469fb30769ac2d78251e4279a746