diff --git a/Telegram/SourceFiles/ayu/ui/ayu_styles.style b/Telegram/SourceFiles/ayu/ui/ayu_styles.style index db9bf0a2bd..66059b4460 100644 --- a/Telegram/SourceFiles/ayu/ui/ayu_styles.style +++ b/Telegram/SourceFiles/ayu/ui/ayu_styles.style @@ -117,3 +117,10 @@ ghostPickerButton: LinkButton(defaultLinkButton) { } ayuBetaBadgePadding: margins(4px, 1px, 4px, 1px); + +ayuServiceTimeBadgeFont: font(11px semibold); +ayuServiceTimeBadgeHorizontalPadding: 7px; +ayuServiceTimeBadgeVerticalPadding: 2px; +ayuServiceTimeBadgeGap: 8px; +ayuServiceTimeBadgeTrailingInset: 3px; +ayuServiceTimeBadgeLastLineWidthAdd: 9px; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index ada788a8fb..11736577e6 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1367,20 +1367,11 @@ void HistoryItem::setCommentsItemId(FullMsgId id) { } void HistoryItem::setServiceText(PreparedServiceText &&prepared) { - auto text = std::move(prepared.text); - - if (date() > 0) { - const auto timeString = QString(" (%1)").arg(formatMessageTime(base::unixtime::parse(_date).time())); - if (!text.text.isEmpty() && !text.text.contains(timeString)) { - text = text.append(timeString); - } - } - AddComponents(HistoryServiceData::Bit()); _flags &= ~MessageFlag::HasTextLinks; const auto data = Get(); const auto had = !_text.empty(); - _text = std::move(text); + _text = std::move(prepared.text); data->textLinks = std::move(prepared.links); if (had) { _history->owner().requestItemTextRefresh(this); diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.cpp b/Telegram/SourceFiles/history/view/history_view_service_message.cpp index 2c08e5bb70..7ea910a114 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_service_message.cpp @@ -32,6 +32,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_chat.h" #include "styles/style_info.h" +// AyuGram includes +#include "ayu/utils/telegram_helpers.h" +#include "styles/style_ayu_styles.h" + + namespace HistoryView { namespace { @@ -200,6 +205,64 @@ void SetText(Ui::Text::String &text, const QString &content) { text.setText(st::serviceTextStyle, content, EmptyLineOptions); } +struct ServiceTimeMetrics { + int width = 0; + int height = 0; + int additionalWidth = 0; +}; + +[[nodiscard]] ServiceTimeMetrics ComputeServiceTimeMetrics(const QString &text) { + auto result = ServiceTimeMetrics(); + if (text.isEmpty()) { + return result; + } + const auto &font = st::ayuServiceTimeBadgeFont; + result.width = font->width(text) + + 2 * st::ayuServiceTimeBadgeHorizontalPadding; + result.height = font->height + 2 * st::ayuServiceTimeBadgeVerticalPadding; + result.additionalWidth = std::max( + st::ayuServiceTimeBadgeGap + + result.width + + st::ayuServiceTimeBadgeTrailingInset + - st::msgServicePadding.right(), + 0); + return result; +} + +void PaintServiceTime( + Painter &p, + not_null st, + int left, + int top, + const QString &text, + const ServiceTimeMetrics &metrics) { + if (text.isEmpty() || !metrics.width) { + return; + } + const auto rect = QRect( + left, + top, + metrics.width, + metrics.height); + const auto bg = QColor(0x00, 0x00, 0x00, 0x1e); + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + p.setBrush(bg); + const auto radius = rect.height() / 2.; + p.drawRoundedRect( + rect, + radius, + radius); + p.setPen(st->msgServiceFg()); + p.setFont(st::ayuServiceTimeBadgeFont); + p.drawText( + rect.x() + st::ayuServiceTimeBadgeHorizontalPadding, + rect.y() + + st::ayuServiceTimeBadgeVerticalPadding + + st::ayuServiceTimeBadgeFont->ascent, + text); +} + [[nodiscard]] Ui::BubbleRounding KeyboardRounding() { return Ui::BubbleRounding{ .topLeft = Ui::BubbleCornerRounding::Large, @@ -311,8 +374,9 @@ void ServiceMessagePainter::PaintComplexBubble( int left, int width, const Ui::Text::String &text, - const QRect &textRect) { - const auto lineWidths = CountLineWidths(text, textRect); + const QRect &textRect, + int lastLineWidthAdd) { + const auto lineWidths = CountLineWidths(text, textRect, lastLineWidthAdd); int y = st::msgServiceMargin.top(), previousRichWidth = 0; bool previousShrink = false, forceShrink = false; @@ -372,7 +436,8 @@ void ServiceMessagePainter::PaintComplexBubble( std::vector ServiceMessagePainter::CountLineWidths( const Ui::Text::String &text, - const QRect &textRect) { + const QRect &textRect, + int lastLineWidthAdd) { const auto linesCount = qMax( textRect.height() / st::msgServiceFont->height, 1); @@ -409,6 +474,12 @@ std::vector ServiceMessagePainter::CountLineWidths( } } } + if (lastLineWidthAdd > 0 + && result.size() > 1 + && result.back() > 0 + && result.back() < result[result.size() - 2]) { + result.back() += lastLineWidthAdd; + } return result; } @@ -445,6 +516,18 @@ bool Service::consumeHorizontalScroll(QPoint position, int delta) { return false; } +namespace { + +[[nodiscard]] QString ServiceTimeText( + const Ui::Text::String &text, + const QDateTime &dateTime) { + return (!text.isEmpty() && dateTime.isValid()) + ? formatMessageTime(dateTime.time()) + : QString(); +} + +} // namespace + QRect Service::countGeometry() const { auto result = QRect(0, 0, width(), height()); if (delegate()->elementChatMode() == ElementChatMode::Wide) { @@ -485,6 +568,9 @@ QSize Service::performCountCurrentSize(int newWidth) { } const auto media = this->media(); const auto mediaDisplayed = media && media->isDisplayed(); + const auto hideText = mediaDisplayed && media->hideServiceText(); + const auto timeText = hideText ? QString() : ServiceTimeText(text(), dateTime()); + const auto timeMetrics = ComputeServiceTimeMetrics(timeText); auto contentWidth = newWidth; if (delegate()->elementChatMode() == ElementChatMode::Wide) { accumulate_min(contentWidth, st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()); @@ -493,10 +579,14 @@ QSize Service::performCountCurrentSize(int newWidth) { if (contentWidth < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) { contentWidth = st::msgServicePadding.left() + st::msgServicePadding.right() + 1; } - if (mediaDisplayed && media->hideServiceText()) { + const auto nwidth = qMax(contentWidth - st::msgServicePadding.left() - st::msgServicePadding.right(), 0); + validateTextSkipBlock( + !timeText.isEmpty(), + timeMetrics.additionalWidth, + qMax(timeMetrics.height, st::msgServiceFont->height)); + if (hideText) { newHeight += media->resizeGetHeight(newWidth) + marginBottom(); } else if (!text().isEmpty()) { - auto nwidth = qMax(contentWidth - st::msgServicePadding.left() - st::msgServicePadding.right(), 0); newHeight += (contentWidth >= maxWidth()) ? minHeight() : textHeightFor(nwidth); @@ -533,7 +623,6 @@ QSize Service::performCountCurrentSize(int newWidth) { QSize Service::performCountOptimalSize() { const auto markup = data()->inlineReplyMarkup(); validateText(); - validateInlineKeyboard(markup); if (_reactions) { _reactions->initDimensions(); @@ -542,9 +631,18 @@ QSize Service::performCountOptimalSize() { if (const auto media = this->media()) { media->initDimensions(); if (media->hideServiceText()) { + validateTextSkipBlock(false, 0, 0); + validateInlineKeyboard(markup); return { media->maxWidth(), media->minHeight() }; } } + const auto timeText = ServiceTimeText(text(), dateTime()); + const auto timeMetrics = ComputeServiceTimeMetrics(timeText); + validateTextSkipBlock( + !timeText.isEmpty(), + timeMetrics.additionalWidth, + qMax(timeMetrics.height, st::msgServiceFont->height)); + validateInlineKeyboard(markup); auto maxWidth = text().maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right(); auto minHeight = text().minHeight(); return { maxWidth, minHeight }; @@ -623,6 +721,8 @@ void Service::draw(Painter &p, const PaintContext &context) const { const auto media = this->media(); const auto mediaDisplayed = media && media->isDisplayed(); const auto onlyMedia = (mediaDisplayed && media->hideServiceText()); + const auto timeText = onlyMedia ? QString() : ServiceTimeText(text(), dateTime()); + const auto timeMetrics = ComputeServiceTimeMetrics(timeText); if (_reactions) { const auto reactionsHeight = st::mediaInBubbleSkip + _reactions->height(); @@ -665,6 +765,15 @@ void Service::draw(Painter &p, const PaintContext &context) const { const auto mediaSkip = mediaDisplayed ? (st::msgServiceMargin.top() + media->height()) : 0; const auto trect = QRect(g.left(), g.top(), g.width(), g.height() - mediaSkip) - st::msgServicePadding; + auto lineWidths = text().countLineWidths(trect.width()); + for (auto &lineWidth : lineWidths) { + lineWidth = qMax(lineWidth, 0); + } + const auto lastLineWidthAdd = (lineWidths.size() > 1 + && lineWidths.back() > timeMetrics.additionalWidth + && lineWidths.back() < lineWidths[lineWidths.size() - 2]) + ? st::ayuServiceTimeBadgeLastLineWidthAdd + : 0; p.translate(0, g.top() - st::msgServiceMargin.top()); ServiceMessagePainter::PaintComplexBubble( @@ -673,7 +782,8 @@ void Service::draw(Painter &p, const PaintContext &context) const { g.left(), g.width(), text(), - trect); + trect, + lastLineWidthAdd); p.translate(0, -g.top() + st::msgServiceMargin.top()); p.setBrush(Qt::NoBrush); @@ -692,6 +802,27 @@ void Service::draw(Painter &p, const PaintContext &context) const { .fullWidthSelection = false, .selection = context.selection, }); + + if (!timeText.isEmpty() && !lineWidths.empty()) { + const auto lastLineWidth = lineWidths.back(); + const auto lastTextWidth = qMax( + lastLineWidth - timeMetrics.additionalWidth, + 0); + const auto gap = lastTextWidth ? st::ayuServiceTimeBadgeGap : 0; + const auto lastLineTop = trect.y() + + (int(lineWidths.size()) - 1) * st::msgServiceFont->height; + PaintServiceTime( + p, + context.st, + trect.x() + + ((trect.width() - lastLineWidth) / 2) + + lastTextWidth + + gap, + lastLineTop + + ((st::msgServiceFont->height - timeMetrics.height) / 2), + timeText, + timeMetrics); + } } if (mediaDisplayed) { const auto left = g.left() + (g.width() - media->width()) / 2; diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.h b/Telegram/SourceFiles/history/view/history_view_service_message.h index a4adae0b51..df2c8b8476 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.h +++ b/Telegram/SourceFiles/history/view/history_view_service_message.h @@ -121,12 +121,14 @@ public: int left, int width, const Ui::Text::String &text, - const QRect &textRect); + const QRect &textRect, + int lastLineWidthAdd = 0); private: static std::vector CountLineWidths( const Ui::Text::String &text, - const QRect &textRect); + const QRect &textRect, + int lastLineWidthAdd = 0); };