diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index f67db3492..4cdb45a56 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -621,6 +621,8 @@ PRIVATE history/view/media/history_view_theme_document.cpp history/view/media/history_view_web_page.h history/view/media/history_view_web_page.cpp + history/view/history_view_bottom_info.cpp + history/view/history_view_bottom_info.h history/view/history_view_contact_status.cpp history/view/history_view_contact_status.h history/view/history_view_context_menu.cpp diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 80e10391c..11a465158 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -1163,7 +1163,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) { auto needToAdd = true; if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview const auto &data = d.vmessage().c_message(); - if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks + if (_session->data().updateExistingMessage(data)) { // already in blocks LOG(("Skipping message, because it is already in blocks!")); needToAdd = false; } @@ -1257,7 +1257,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) { auto needToAdd = true; if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview const auto &data = d.vmessage().c_message(); - if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks + if (_session->data().updateExistingMessage(data)) { // already in blocks LOG(("Skipping message, because it is already in blocks!")); needToAdd = false; } @@ -2163,7 +2163,9 @@ void Updates::feedUpdate(const MTPUpdate &update) { const auto &d = update.c_updateChannelMessageViews(); const auto peerId = peerFromChannel(d.vchannel_id()); if (const auto item = session().data().message(peerId, d.vid().v)) { - item->setViewsCount(d.vviews().v); + if (item->changeViewsCount(d.vviews().v)) { + session().data().notifyItemDataChange(item); + } } } break; diff --git a/Telegram/SourceFiles/api/api_views.cpp b/Telegram/SourceFiles/api/api_views.cpp index 462c5deea..dda9d7e69 100644 --- a/Telegram/SourceFiles/api/api_views.cpp +++ b/Telegram/SourceFiles/api/api_views.cpp @@ -99,7 +99,9 @@ void ViewsManager::done( if (const auto item = owner.message(peer->id, ids[j].v)) { v[j].match([&](const MTPDmessageViews &data) { if (const auto views = data.vviews()) { - item->setViewsCount(views->v); + if (item->changeViewsCount(views->v)) { + _session->data().notifyItemDataChange(item); + } } if (const auto forwards = data.vforwards()) { item->setForwardsCount(forwards->v); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 5d6154ac8..b82005903 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1448,6 +1448,14 @@ rpl::producer> Session::itemViewRefreshRequest() const { return _itemViewRefreshRequest.events(); } +void Session::notifyItemDataChange(not_null item) { + _itemDataChanges.fire_copy(item); +} + +rpl::producer> Session::itemDataChanges() const { + return _itemDataChanges.events(); +} + void Session::requestItemTextRefresh(not_null item) { if (const auto i = _views.find(item); i != _views.end()) { for (const auto view : i->second) { @@ -1806,7 +1814,7 @@ void Session::reorderTwoPinnedChats( notifyPinnedDialogsOrderUpdated(); } -bool Session::checkEntitiesAndViewsUpdate(const MTPDmessage &data) { +bool Session::updateExistingMessage(const MTPDmessage &data) { const auto peer = peerFromMTP(data.vpeer_id()); const auto existing = message(peer, data.vid().v); if (!existing) { @@ -1834,7 +1842,7 @@ void Session::updateEditedMessage(const MTPMessage &data) { return; } if (existing->isLocalUpdateMedia() && data.type() == mtpc_message) { - checkEntitiesAndViewsUpdate(data.c_message()); + updateExistingMessage(data.c_message()); } data.match([](const MTPDmessageEmpty &) { }, [&](const MTPDmessageService &data) { @@ -1854,7 +1862,7 @@ void Session::processMessages( const auto &data = message.c_message(); // new message, index my forwarded messages to links overview if ((type == NewMessageType::Unread) - && checkEntitiesAndViewsUpdate(data)) { + && updateExistingMessage(data)) { continue; } } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index c3d5a859f..f5f9ed779 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -251,6 +251,8 @@ public: [[nodiscard]] rpl::producer> animationPlayInlineRequest() const; void notifyHistoryUnloaded(not_null history); [[nodiscard]] rpl::producer> historyUnloaded() const; + void notifyItemDataChange(not_null item); + [[nodiscard]] rpl::producer> itemDataChanges() const; [[nodiscard]] rpl::producer> itemRemoved() const; [[nodiscard]] rpl::producer> itemRemoved( @@ -337,7 +339,7 @@ public: void unregisterMessageTTL(TimeId when, not_null item); // Returns true if item found and it is not detached. - bool checkEntitiesAndViewsUpdate(const MTPDmessage &data); + bool updateExistingMessage(const MTPDmessage &data); void updateEditedMessage(const MTPMessage &data); void processMessages( const QVector &data, @@ -832,6 +834,7 @@ private: rpl::event_stream> _viewResizeRequest; rpl::event_stream> _itemViewRefreshRequest; rpl::event_stream> _itemTextRefreshRequest; + rpl::event_stream> _itemDataChanges; rpl::event_stream> _animationPlayInlineRequest; rpl::event_stream> _itemRemoved; rpl::event_stream> _viewRemoved; diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index 9662744ce..37d737b92 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -285,6 +285,12 @@ InnerWidget::InnerWidget( } } }, lifetime()); + session().data().itemDataChanges( + ) | rpl::start_with_next([=](not_null item) { + if (const auto view = viewForItem(item)) { + view->itemDataChanged(); + } + }, lifetime()); session().data().animationPlayInlineRequest( ) | rpl::start_with_next([=](auto item) { if (const auto view = viewForItem(item)) { diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 43c351a7e..aa430e29f 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -245,6 +245,14 @@ HistoryInner::HistoryInner( }) | rpl::start_with_next([this](not_null view) { mouseActionUpdate(); }, lifetime()); + + session().data().itemDataChanges( + ) | rpl::filter([=](not_null item) { + return item->mainView() != nullptr; + }) | rpl::start_with_next([=](not_null item) { + item->mainView()->itemDataChanged(); + }, lifetime()); + session().changes().historyUpdates( _history, Data::HistoryUpdate::Flag::OutboxRead diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index b9dcc70a9..a332f0a48 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -524,7 +524,7 @@ void HistoryItem::applySentMessage(const MTPDmessage &data) { }, data.vmedia()); updateReplyMarkup(HistoryMessageMarkupData(data.vreply_markup())); updateForwardedInfo(data.vfwd_from()); - setViewsCount(data.vviews().value_or(-1)); + changeViewsCount(data.vviews().value_or(-1)); if (const auto replies = data.vreplies()) { setReplies(HistoryMessageRepliesData(replies)); } else { @@ -541,6 +541,7 @@ void HistoryItem::applySentMessage(const MTPDmessage &data) { setPostAuthor(data.vpost_author().value_or_empty()); contributeToSlowmode(data.vdate().v); indexAsNewItem(); + history()->owner().notifyItemDataChange(this); history()->owner().requestItemTextRefresh(this); history()->owner().updateDependentMessages(this); } @@ -596,6 +597,7 @@ void HistoryItem::setRealId(MsgId newId) { } } + _history->owner().notifyItemDataChange(this); _history->owner().requestItemRepaint(this); } @@ -914,6 +916,7 @@ void HistoryItem::sendFailed() { Expects(!(_flags & MessageFlag::SendingFailed)); _flags = (_flags | MessageFlag::SendingFailed) & ~MessageFlag::BeingSent; + _history->owner().notifyItemDataChange(this); history()->session().changes().historyUpdated( history(), Data::HistoryUpdate::Flag::ClientSideMessages); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 2920d28bd..0172e093d 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -352,7 +352,8 @@ public: return TextForMimeData(); } - virtual void setViewsCount(int count) { + virtual bool changeViewsCount(int count) { + return false; } virtual void setForwardsCount(int count) { } diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 62bf2c695..7aebfa46e 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -84,38 +84,6 @@ void HistoryMessageVia::resize(int32 availw) const { } } -void HistoryMessageSigned::refresh(const QString &date) { - Expects(!isAnonymousRank); - - auto name = author; - const auto time = qsl(", ") + date; - const auto timew = st::msgDateFont->width(time); - const auto namew = st::msgDateFont->width(name); - isElided = (timew + namew > st::maxSignatureSize); - if (isElided) { - name = st::msgDateFont->elided(author, st::maxSignatureSize - timew); - } - signature.setText( - st::msgDateTextStyle, - name + time, - Ui::NameTextOptions()); -} - -int HistoryMessageSigned::maxWidth() const { - return signature.maxWidth(); -} - -void HistoryMessageEdited::refresh(const QString &date, bool displayed) { - const auto prefix = displayed - ? (tr::lng_edited(tr::now) + ' ') - : QString(); - text.setText(st::msgDateTextStyle, prefix + date, Ui::NameTextOptions()); -} - -int HistoryMessageEdited::maxWidth() const { - return text.maxWidth(); -} - HistoryMessageSponsored::HistoryMessageSponsored() { text.setText( st::msgDateTextStyle, diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 880b10639..776134533 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -60,21 +60,12 @@ struct HistoryMessageViews : public RuntimeComponent { - void refresh(const QString &date); - int maxWidth() const; - QString author; - Ui::Text::String signature; - bool isElided = false; bool isAnonymousRank = false; }; struct HistoryMessageEdited : public RuntimeComponent { - void refresh(const QString &date, bool displayed); - int maxWidth() const; - TimeId date = 0; - Ui::Text::String text; }; struct HistoryMessageSponsored : public RuntimeComponent< diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 19ccda5af..39c7774d9 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -1124,7 +1124,7 @@ void HistoryMessage::createComponents(CreateConfig &&config) { via->create(&history()->owner(), config.viaBotId); } if (const auto views = Get()) { - setViewsCount(config.viewsCount); + changeViewsCount(config.viewsCount); if (config.replies.isNull && isSending() && config.markup.isNull()) { @@ -1423,7 +1423,7 @@ void HistoryMessage::applyEdition(HistoryMessageEdition &&edition) { if (!isLocalUpdateMedia()) { refreshMedia(edition.mtpMedia); } - setViewsCount(edition.views); + changeViewsCount(edition.views); setForwardsCount(edition.forwards); setText(_media ? edition.textWithEntities @@ -1449,7 +1449,7 @@ void HistoryMessage::applyEdition(const MTPDmessageService &message) { setReplyMarkup({}); refreshMedia(nullptr); setEmptyText(); - setViewsCount(-1); + changeViewsCount(-1); setForwardsCount(-1); if (wasGrouped) { history()->owner().groups().unregisterMessage(this); @@ -1744,27 +1744,16 @@ bool HistoryMessage::textHasLinks() const { return emptyText() ? false : _text.hasLinks(); } -void HistoryMessage::setViewsCount(int count) { +bool HistoryMessage::changeViewsCount(int count) { const auto views = Get(); if (!views || views->views.count == count || (count >= 0 && views->views.count > count)) { - return; + return false; } views->views.count = count; - views->views.text = Lang::FormatCountToShort( - std::max(views->views.count, 1) - ).string; - const auto was = views->views.textWidth; - views->views.textWidth = views->views.text.isEmpty() - ? 0 - : st::msgDateFont->width(views->views.text); - if (was == views->views.textWidth) { - history()->owner().requestItemRepaint(this); - } else { - history()->owner().requestItemResize(this); - } + return true; } void HistoryMessage::setForwardsCount(int count) { @@ -1852,7 +1841,6 @@ void HistoryMessage::clearReplies() { void HistoryMessage::refreshRepliesText( not_null views, bool forceResize) { - const auto was = views->replies.textWidth; if (views->commentsMegagroupId) { views->replies.text = (views->replies.count > 0) ? tr::lng_comments_open_count( @@ -1867,15 +1855,8 @@ void HistoryMessage::refreshRepliesText( : QString(); views->repliesSmall.textWidth = st::semiboldFont->width( views->repliesSmall.text); - } else { - views->replies.text = (views->replies.count > 0) - ? Lang::FormatCountToShort(views->replies.count).string - : QString(); - views->replies.textWidth = views->replies.text.isEmpty() - ? 0 - : st::msgDateFont->width(views->replies.text); } - if (forceResize || views->replies.textWidth != was) { + if (forceResize) { history()->owner().requestItemResize(this); } else { history()->owner().requestItemRepaint(this); diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index 7611933e5..3f91da06d 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -129,7 +129,7 @@ public: [[nodiscard]] bool allowsSendNow() const override; [[nodiscard]] bool allowsEdit(TimeId now) const override; - void setViewsCount(int count) override; + bool changeViewsCount(int count) override; void setForwardsCount(int count) override; void setReplies(HistoryMessageRepliesData &&data) override; void clearReplies() override; @@ -263,10 +263,7 @@ private: [[nodiscard]] bool checkRepliesPts( const HistoryMessageRepliesData &data) const; - QString _timeText; - int _timeWidth = 0; - - mutable int32 _fromNameVersion = 0; + mutable int _fromNameVersion = 0; friend class HistoryView::Element; friend class HistoryView::Message; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 3e5a66f13..71819e4ad 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -507,6 +507,13 @@ HistoryWidget::HistoryWidget( } }, lifetime()); + session().data().itemDataChanges( + ) | rpl::filter([=](not_null item) { + return !_list && (item->mainView() != nullptr); + }) | rpl::start_with_next([=](not_null item) { + item->mainView()->itemDataChanged(); + }, lifetime()); + Core::App().settings().largeEmojiChanges( ) | rpl::start_with_next([=] { crl::on_main(this, [=] { diff --git a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp new file mode 100644 index 000000000..e94524ad1 --- /dev/null +++ b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp @@ -0,0 +1,303 @@ +/* +This file is part of Telegram Desktop, +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_bottom_info.h" + +#include "ui/chat/message_bubble.h" +#include "ui/chat/chat_style.h" +#include "ui/text/text_options.h" +#include "lang/lang_keys.h" +#include "history/history_item_components.h" +#include "history/history_message.h" +#include "history/view/history_view_message.h" +#include "styles/style_chat.h" +#include "styles/style_dialogs.h" + +namespace HistoryView { + +BottomInfo::BottomInfo(Data &&data) : _data(std::move(data)) { + layout(); +} + +void BottomInfo::update(Data &&data) { + _data = std::move(data); + layout(); + if (!_size.isEmpty()) { + resizeToWidth(_size.width()); + } +} + +QSize BottomInfo::optimalSize() const { + return _optimalSize; +} + +QSize BottomInfo::size() const { + return _size; +} + +bool BottomInfo::pointInTime(QPoint position) const { + return QRect( + _size.width() - _dateWidth, + 0, + _dateWidth, + st::msgDateFont->height + ).contains(position); +} + +bool BottomInfo::isSignedAuthorElided() const { + return _authorElided; +} + +void BottomInfo::paint( + Painter &p, + QPoint position, + int outerWidth, + bool unread, + bool inverted, + const PaintContext &context) const { + const auto st = context.st; + const auto sti = context.imageStyle(); + const auto stm = context.messageStyle(); + + auto right = position.x() + _size.width(); + const auto firstLineBottom = position.y() + st::msgDateFont->height; + if (_data.flags & Data::Flag::OutLayout) { + const auto &icon = (_data.flags & Data::Flag::Sending) + ? (inverted + ? st->historySendingInvertedIcon() + : st->historySendingIcon()) + : unread + ? (inverted + ? st->historySentInvertedIcon() + : stm->historySentIcon) + : (inverted + ? st->historyReceivedInvertedIcon() + : stm->historyReceivedIcon); + icon.paint( + p, + QPoint(right, firstLineBottom) + st::historySendStatePosition, + outerWidth); + right -= st::historySendStateSpace; + } + + const auto authorEditedWidth = _authorEditedDate.maxWidth(); + right -= authorEditedWidth; + _authorEditedDate.drawLeft( + p, + right, + position.y(), + authorEditedWidth, + outerWidth); + + if (!_views.isEmpty()) { + const auto viewsWidth = _views.maxWidth(); + right -= st::historyViewsSpace + viewsWidth; + _views.drawLeft(p, right, position.y(), viewsWidth, outerWidth); + + const auto &icon = inverted + ? st->historyViewsInvertedIcon() + : stm->historyViewsIcon; + icon.paint( + p, + right - st::historyViewsWidth, + firstLineBottom + st::historyViewsTop, + outerWidth); + } + if (!_replies.isEmpty()) { + const auto repliesWidth = _replies.maxWidth(); + right -= st::historyViewsSpace + repliesWidth; + _replies.drawLeft(p, right, position.y(), repliesWidth, outerWidth); + + const auto &icon = inverted + ? st->historyRepliesInvertedIcon() + : stm->historyRepliesIcon; + icon.paint( + p, + right - st::historyViewsWidth, + firstLineBottom + st::historyViewsTop, + outerWidth); + } + if ((_data.flags & Data::Flag::Sending) + && !(_data.flags & Data::Flag::OutLayout)) { + right -= st::historySendStateSpace; + const auto &icon = inverted + ? st->historyViewsSendingInvertedIcon() + : st->historyViewsSendingIcon(); + icon.paint( + p, + right, + firstLineBottom + st::historyViewsTop, + outerWidth); + } + if (!_reactions.isEmpty()) { + if (_size.height() == _optimalSize.height()) { + _reactions.drawLeft( + p, + position.x(), + position.y(), + _reactions.maxWidth(), + outerWidth); + } else { + const auto available = _size.width(); + const auto use = std::min(available, _reactions.maxWidth()); + _reactions.drawLeftElided( + p, + position.x() + _size.width() - use, + position.y() + st::msgDateFont->height, + use, + outerWidth); + } + } +} + +int BottomInfo::resizeToWidth(int newWidth) { + if (newWidth >= _optimalSize.width()) { + _size = _optimalSize; + return _size.height(); + } + return 2 * st::msgDateFont->height; +} + +void BottomInfo::layout() { + layoutDateText(); + layoutViewsText(); + layoutReactionsText(); + countOptimalSize(); +} + +void BottomInfo::layoutDateText() { + const auto edited = (_data.flags & Data::Flag::Edited) + ? (tr::lng_edited(tr::now) + ' ') + : QString(); + const auto author = _data.author; + const auto prefix = author.isEmpty() ? qsl(", ") : QString(); + const auto date = _data.date.toString(cTimeFormat()); + _dateWidth = st::msgDateFont->width(date); + const auto afterAuthor = prefix + edited + date; + const auto afterAuthorWidth = st::msgDateFont->width(afterAuthor); + const auto authorWidth = st::msgDateFont->width(author); + const auto maxWidth = st::maxSignatureSize; + _authorElided = !author.isEmpty() + && (authorWidth + afterAuthorWidth > maxWidth); + const auto name = _authorElided + ? st::msgDateFont->elided(author, maxWidth - afterAuthorWidth) + : author; + const auto full = name + date; + _authorEditedDate.setText( + st::msgDateTextStyle, + full, + Ui::NameTextOptions()); +} + +void BottomInfo::layoutViewsText() { + if (!_data.views || (_data.flags & Data::Flag::Sending)) { + _views.clear(); + return; + } + _views.setText( + st::msgDateTextStyle, + Lang::FormatCountToShort(std::max(*_data.views, 1)).string, + Ui::NameTextOptions()); +} + +void BottomInfo::layoutRepliesText() { + if (!_data.replies + || !*_data.replies + || (_data.flags & Data::Flag::RepliesContext) + || (_data.flags & Data::Flag::Sending)) { + _replies.clear(); + return; + } + _replies.setText( + st::msgDateTextStyle, + Lang::FormatCountToShort(*_data.replies).string, + Ui::NameTextOptions()); +} + +void BottomInfo::layoutReactionsText() { + if (_data.reactions.empty()) { + _reactions.clear(); + return; + } + auto sorted = ranges::view::all( + _data.reactions + ) | ranges::view::transform([](const auto &pair) { + return std::make_pair(pair.first, pair.second); + }) | ranges::to_vector; + ranges::sort(sorted, std::greater<>(), &std::pair::second); + + auto fullCount = 0; + auto text = QString(); + for (const auto &[string, count] : sorted) { + text.append(string); + fullCount += count; + } + text += QString::number(fullCount); + + _reactions.setText(st::msgDateTextStyle, text, Ui::NameTextOptions()); +} + +void BottomInfo::countOptimalSize() { + auto width = 0; + if (_data.flags & (Data::Flag::OutLayout | Data::Flag::Sending)) { + width += st::historySendStateSpace; + } + width += _authorEditedDate.maxWidth(); + if (!_views.isEmpty()) { + width += st::historyViewsSpace + + _views.maxWidth() + + st::historyViewsWidth; + } + if (!_reactions.isEmpty()) { + width += st::historyReactionsSkip + _reactions.maxWidth(); + } + _optimalSize = QSize(width, st::msgDateFont->height); +} + +BottomInfo::Data BottomInfoDataFromMessage(not_null message) { + using Flag = BottomInfo::Data::Flag; + + auto result = BottomInfo::Data(); + + const auto item = message->message(); + result.date = message->dateTime(); + result.reactions = item->reactions(); + if (message->hasOutLayout()) { + result.flags |= Flag::OutLayout; + } + if (message->context() == Context::Replies) { + result.flags |= Flag::RepliesContext; + } + if (const auto msgsigned = item->Get()) { + if (!msgsigned->isAnonymousRank) { + result.author = msgsigned->author; + } + } + if (!item->hideEditedBadge()) { + if (const auto edited = message->displayedEditBadge()) { + result.flags |= Flag::Edited; + } + } + if (const auto views = item->Get()) { + if (views->views.count >= 0) { + result.views = views->views.count; + } + if (views->replies.count >= 0 && !views->commentsMegagroupId) { + result.replies = views->replies.count; + } + } + if (item->isSending() || item->hasFailed()) { + result.flags |= Flag::Sending; + } + // We don't want to pass and update it in Date for now. + //if (item->unread()) { + // result.flags |= Flag::Unread; + //} + return result; +} + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_bottom_info.h b/Telegram/SourceFiles/history/view/history_view_bottom_info.h new file mode 100644 index 000000000..e7ffd27f0 --- /dev/null +++ b/Telegram/SourceFiles/history/view/history_view_bottom_info.h @@ -0,0 +1,85 @@ +/* +This file is part of Telegram Desktop, +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 +*/ +#pragma once + +#include "ui/text/text.h" +#include "base/flags.h" + +namespace Ui { +struct ChatPaintContext; +} // namespace Ui + +namespace HistoryView { + +using PaintContext = Ui::ChatPaintContext; + +class Message; + +class BottomInfo { +public: + struct Data { + enum class Flag { + Edited = 0x01, + OutLayout = 0x02, + Sending = 0x04, + RepliesContext = 0x08, + //Unread, // We don't want to pass and update it in Date for now. + }; + friend inline constexpr bool is_flag_type(Flag) { return true; }; + using Flags = base::flags; + + QDateTime date; + QString author; + base::flat_map reactions; + std::optional views; + std::optional replies; + Flags flags; + }; + explicit BottomInfo(Data &&data); + + void update(Data &&data); + + [[nodiscard]] QSize optimalSize() const; + [[nodiscard]] QSize size() const; + [[nodiscard]] bool pointInTime(QPoint position) const; + [[nodiscard]] bool isSignedAuthorElided() const; + + void paint( + Painter &p, + QPoint position, + int outerWidth, + bool unread, + bool inverted, + const PaintContext &context) const; + + int resizeToWidth(int newWidth); + +private: + void layout(); + void layoutDateText(); + void layoutViewsText(); + void layoutRepliesText(); + void layoutReactionsText(); + void countOptimalSize(); + + Data _data; + QSize _optimalSize; + QSize _size; + Ui::Text::String _authorEditedDate; + Ui::Text::String _views; + Ui::Text::String _replies; + Ui::Text::String _reactions; + int _dateWidth = 0; + bool _authorElided = false; + +}; + +[[nodiscard]] BottomInfo::Data BottomInfoDataFromMessage( + not_null message); + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 3fe06f426..5d0ff8f85 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -231,8 +231,8 @@ QString DateTooltipText(not_null view) { + "\n\n" + dateText; } } - if (const auto msgsigned = view->data()->Get()) { - if (msgsigned->isElided && !msgsigned->isAnonymousRank) { + if (view->isSignedAuthorElided()) { + if (const auto msgsigned = view->data()->Get()) { dateText += '\n' + tr::lng_signed_author(tr::now, lt_user, msgsigned->author); } @@ -841,6 +841,13 @@ void Element::checkHeavyPart() { } } +bool Element::isSignedAuthorElided() const { + return false; +} + +void Element::itemDataChanged() { +} + void Element::unloadHeavyPart() { history()->owner().unregisterHeavyViewPart(this); if (_media) { diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 1522ac402..5f5d2312d 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -318,31 +318,31 @@ public: // hasFromPhoto() returns true even if we don't display the photo // but we need to skip a place at the left side for this photo - virtual bool hasFromPhoto() const; - virtual bool displayFromPhoto() const; - virtual bool hasFromName() const; - virtual bool displayFromName() const; - virtual bool displayForwardedFrom() const; - virtual bool hasOutLayout() const; - virtual bool drawBubble() const; - virtual bool hasBubble() const; - virtual int minWidthForMedia() const { + [[nodiscard]] virtual bool hasFromPhoto() const; + [[nodiscard]] virtual bool displayFromPhoto() const; + [[nodiscard]] virtual bool hasFromName() const; + [[nodiscard]] virtual bool displayFromName() const; + [[nodiscard]] virtual bool displayForwardedFrom() const; + [[nodiscard]] virtual bool hasOutLayout() const; + [[nodiscard]] virtual bool drawBubble() const; + [[nodiscard]] virtual bool hasBubble() const; + [[nodiscard]] virtual int minWidthForMedia() const { return 0; } - virtual bool hasFastReply() const; - virtual bool displayFastReply() const; - virtual std::optional rightActionSize() const; + [[nodiscard]] virtual bool hasFastReply() const; + [[nodiscard]] virtual bool displayFastReply() const; + [[nodiscard]] virtual std::optional rightActionSize() const; virtual void drawRightAction( Painter &p, const PaintContext &context, int left, int top, int outerWidth) const; - virtual ClickHandlerPtr rightActionLink() const; - virtual bool displayEditedBadge() const; - virtual TimeId displayedEditDate() const; - virtual bool hasVisibleText() const; - virtual HistoryMessageReply *displayedReply() const; + [[nodiscard]] virtual ClickHandlerPtr rightActionLink() const; + [[nodiscard]] virtual bool displayEditedBadge() const; + [[nodiscard]] virtual TimeId displayedEditDate() const; + [[nodiscard]] virtual bool hasVisibleText() const; + [[nodiscard]] virtual HistoryMessageReply *displayedReply() const; virtual void applyGroupAdminChanges( const base::flat_set &changes) { } @@ -355,6 +355,10 @@ public: }; [[nodiscard]] virtual VerticalRepaintRange verticalRepaintRange() const; + [[nodiscard]] virtual bool isSignedAuthorElided() const; + + virtual void itemDataChanged(); + virtual bool hasHeavyPart() const; virtual void unloadHeavyPart(); void checkHeavyPart(); diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 78ee5c917..8a969639a 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -294,6 +294,12 @@ ListWidget::ListWidget( } } }, lifetime()); + session().data().itemDataChanges( + ) | rpl::start_with_next([=](not_null item) { + if (const auto view = viewForItem(item)) { + view->itemDataChanged(); + } + }, lifetime()); session().data().animationPlayInlineRequest( ) | rpl::start_with_next([this](auto item) { if (const auto view = viewForItem(item)) { diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 288e777d5..d947dfae8 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -237,30 +237,12 @@ LogEntryOriginal &LogEntryOriginal::operator=(LogEntryOriginal &&other) { LogEntryOriginal::~LogEntryOriginal() = default; -void Reactions::update(const base::flat_map &list) { - auto sorted = ranges::view::all( - list - ) | ranges::view::transform([](const auto &pair) { - return std::make_pair(pair.first, pair.second); - }) | ranges::to_vector; - ranges::sort(sorted, std::greater<>(), &std::pair::second); - - auto fullCount = 0; - auto composed = QString(); - for (const auto &[string, count] : sorted) { - composed.append(string); - fullCount += count; - } - composed += QString::number(fullCount); - - text.setText(st::msgDateTextStyle, composed, Ui::NameTextOptions()); -} - Message::Message( not_null delegate, not_null data, Element *replacing) -: Element(delegate, data, replacing) { +: Element(delegate, data, replacing) +, _bottomInfo(BottomInfoDataFromMessage(this)) { initLogEntryOriginal(); initPsa(); } @@ -334,16 +316,8 @@ QSize Message::performCountOptimalSize() { updateViewButtonExistence(); updateMediaInBubbleState(); - refreshEditedBadge(); refreshRightBadge(); - - if (const auto list = item->reactions(); !list.empty()) { - AddComponents(Reactions::Bit()); - const auto reactions = Get(); - reactions->update(list); - } else { - RemoveComponents(Reactions::Bit()); - } + initTime(); if (drawBubble()) { const auto forwarded = item->Get(); @@ -1776,111 +1750,25 @@ void Message::drawInfo( break; } - const auto item = message(); - auto infoW = infoWidth(); - if (rtl()) infoRight = width - infoRight + infoW; - - auto dateX = infoRight - infoW; - auto dateY = infoBottom - st::msgDateFont->height; + const auto size = _bottomInfo.size(); + const auto dateX = infoRight - size.width(); + const auto dateY = infoBottom - size.height(); if (type == InfoDisplayType::Image) { - auto dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); + const auto dateW = size.width() + 2 * st::msgDateImgPadding.x(); + const auto dateH = size.height() + 2 * st::msgDateImgPadding.y(); Ui::FillRoundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, sti->msgDateImgBg, sti->msgDateImgBgCorners); } else if (type == InfoDisplayType::Background) { - auto dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); + const auto dateW = size.width() + 2 * st::msgDateImgPadding.x(); + const auto dateH = size.height() + 2 * st::msgDateImgPadding.y(); Ui::FillRoundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, sti->msgServiceBg, sti->msgServiceBgCorners); } - dateX += timeLeft(); - - if (const auto msgsigned = item->Get() - ; msgsigned && !msgsigned->isAnonymousRank) { - msgsigned->signature.drawElided(p, dateX, dateY, item->_timeWidth); - } else if (const auto sponsored = displayedSponsorBadge()) { - const auto skipY = viewButtonHeight(); - sponsored->text.drawElided(p, dateX, dateY - skipY, item->_timeWidth); - } else if (const auto edited = displayedEditBadge()) { - edited->text.drawElided(p, dateX, dateY, item->_timeWidth); - } else { - p.drawText(dateX, dateY + st::msgDateFont->ascent, item->_timeText); - } - - const auto viewIconTop = infoBottom + st::historyViewsTop; - const auto pinIconTop = infoBottom + st::historyPinTop; - auto left = infoRight - infoW; - if (const auto reactions = Get()) { - reactions->text.draw(p, left, dateY, reactions->text.maxWidth()); - left += reactions->text.maxWidth() + st::historyReactionsSkip; - } - if (const auto views = item->Get()) { - const auto textTop = infoBottom - st::msgDateFont->descent; - if (views->replies.count > 0 - && !views->commentsMegagroupId - && this->context() != Context::Replies) { - const auto &icon = (!item->isSending() && !item->hasFailed()) - ? (invertedsprites - ? st->historyRepliesInvertedIcon() - : stm->historyRepliesIcon) - : (invertedsprites - ? st->historyViewsSendingInvertedIcon() - : st->historyViewsSendingIcon()); - if (!item->isSending() && !item->hasFailed()) { - icon.paint(p, left, viewIconTop, width); - p.drawText(left + st::historyViewsWidth, textTop, views->replies.text); - } else if (!context.outbg && views->views.count < 0) { // sending outbg icon will be painted below - auto iconSkip = st::historyViewsSpace + views->replies.textWidth; - icon.paint(p, left + iconSkip, viewIconTop, width); - } - left += st::historyViewsSpace - + views->replies.textWidth - + st::historyViewsWidth; - } - if (views->views.count >= 0) { - const auto &icon = (!item->isSending() && !item->hasFailed()) - ? (invertedsprites - ? st->historyViewsInvertedIcon() - : stm->historyViewsIcon) - : (invertedsprites - ? st->historyViewsSendingInvertedIcon() - : st->historyViewsSendingIcon()); - if (!item->isSending() && !item->hasFailed()) { - icon.paint(p, left, viewIconTop, width); - p.drawText(left + st::historyViewsWidth, textTop, views->views.text); - } else if (!context.outbg) { // sending outbg icon will be painted below - auto iconSkip = st::historyViewsSpace + views->views.textWidth; - icon.paint(p, left + iconSkip, viewIconTop, width); - } - left += st::historyViewsSpace - + views->views.textWidth - + st::historyViewsWidth; - } - } else if ((item->isSending() || item->hasFailed()) - && item->history()->peer->isSelf() - && !context.outbg) { - const auto &icon = invertedsprites - ? st->historyViewsSendingInvertedIcon() - : st->historyViewsSendingIcon(); - icon.paint(p, left, viewIconTop, width); - } - if (displayPinIcon()) { - const auto &icon = invertedsprites - ? st->historyPinInvertedIcon() - : stm->historyPinIcon; - icon.paint(p, left, pinIconTop, width); - left += st::historyPinWidth; - } - if (context.outbg) { - const auto &icon = (item->isSending() || item->hasFailed()) - ? (invertedsprites - ? st->historySendingInvertedIcon() - : st->historySendingIcon()) - : delegate()->elementShownUnread(this) - ? (invertedsprites - ? st->historySentInvertedIcon() - : stm->historySentIcon) - : (invertedsprites - ? st->historyReceivedInvertedIcon() - : stm->historyReceivedIcon); - icon.paint(p, QPoint(infoRight, infoBottom) + st::historySendStatePosition, width); - } + _bottomInfo.paint( + p, + { dateX, dateY }, + width, + delegate()->elementShownUnread(this), + invertedsprites, + context); } bool Message::pointInTime( @@ -1904,53 +1792,28 @@ bool Message::pointInTime( infoBottom -= st::msgDateImgPadding.y(); break; } - const auto item = message(); - auto dateX = infoRight - infoWidth() + timeLeft(); - auto dateY = infoBottom - st::msgDateFont->height; - return QRect( - dateX, - dateY, - item->_timeWidth, - st::msgDateFont->height).contains(point); + const auto size = _bottomInfo.size(); + const auto infoLeft = infoRight - size.width(); + const auto infoTop = infoBottom - size.height(); + return _bottomInfo.pointInTime({ infoLeft, infoTop }); } int Message::infoWidth() const { - const auto item = message(); - auto result = item->_timeWidth; - if (const auto views = item->Get()) { - if (views->views.count >= 0) { - result += st::historyViewsSpace - + views->views.textWidth - + st::historyViewsWidth; - } - if (views->replies.count > 0 - && !views->commentsMegagroupId - && context() != Context::Replies) { - result += st::historyViewsSpace - + views->replies.textWidth - + st::historyViewsWidth; - } - } else if ((item->isSending() || item->hasFailed()) - && item->history()->peer->isSelf()) { - if (!hasOutLayout()) { - result += st::historySendStateSpace; - } - } - if (displayPinIcon()) { - result += st::historyPinWidth; - } + return _bottomInfo.optimalSize().width(); +} - // When message is scheduled until online, time is not displayed, - // so message should have less space. - if (!item->_timeWidth) { - result += st::historyScheduledUntilOnlineStateSpace; - } else if (hasOutLayout()) { - result += st::historySendStateSpace; +bool Message::isSignedAuthorElided() const { + return _bottomInfo.isSignedAuthorElided(); +} + +void Message::itemDataChanged() { + const auto was = _bottomInfo.size(); + _bottomInfo.update(BottomInfoDataFromMessage(this)); + if (was != _bottomInfo.size()) { + history()->owner().requestViewResize(this); + } else { + history()->owner().requestViewRepaint(this); } - if (const auto reactions = Get()) { - result += st::historyReactionsSkip + reactions->text.maxWidth(); - } - return result; } auto Message::verticalRepaintRange() const -> VerticalRepaintRange { @@ -1974,34 +1837,6 @@ void Message::refreshDataIdHook() { } } -int Message::timeLeft() const { - const auto item = message(); - auto result = 0; - if (auto views = item->Get()) { - if (views->views.count >= 0) { - result += st::historyViewsSpace + views->views.textWidth + st::historyViewsWidth; - } - if (views->replies.count > 0 - && !views->commentsMegagroupId - && context() != Context::Replies) { - result += st::historyViewsSpace + views->replies.textWidth + st::historyViewsWidth; - } - } else if ((item->isSending() || item->hasFailed()) - && item->history()->peer->isSelf()) { - if (!hasOutLayout()) { - result += st::historySendStateSpace; - } - } - if (displayPinIcon()) { - result += st::historyPinWidth; - } - - if (const auto reactions = Get()) { - result += st::historyReactionsSkip + reactions->text.maxWidth(); - } - return result; -} - int Message::plainMaxWidth() const { return st::msgPadding.left() + (hasVisibleText() ? message()->_text.maxWidth() : 0) @@ -2629,6 +2464,8 @@ int Message::resizeContentGetHeight(int newWidth) { } } } + _bottomInfo.resizeToWidth( + std::min(_bottomInfo.optimalSize().width(), contentWidth)); if (bubble) { auto reply = displayedReply(); @@ -2733,46 +2570,8 @@ QSize Message::performCountCurrentSize(int newWidth) { return { newWidth, newHeight }; } -void Message::refreshEditedBadge() { - const auto item = message(); - const auto edited = displayedEditBadge(); - const auto editDate = displayedEditDate(); - const auto dateText = dateTime().toString(cTimeFormat()); - if (edited) { - edited->refresh(dateText, editDate != 0); - } - if (const auto msgsigned = item->Get()) { - if (!msgsigned->isAnonymousRank) { - const auto text = (!edited || !editDate) - ? dateText - : edited->text.toString(); - msgsigned->refresh(text); - } - } - initTime(); -} - void Message::initTime() const { const auto item = message(); - if (const auto msgsigned = item->Get() - ; msgsigned && !msgsigned->isAnonymousRank) { - item->_timeWidth = msgsigned->maxWidth(); - } else if (const auto sponsored = displayedSponsorBadge()) { - item->_timeWidth = sponsored->maxWidth(); - } else if (const auto edited = displayedEditBadge()) { - item->_timeWidth = edited->maxWidth(); - } else { - const auto forwarded = item->Get(); - if (forwarded && forwarded->imported) { - const auto date = base::unixtime::parse(forwarded->originalDate); - item->_timeText = date.toString( - cDateFormat() + u", "_q + cTimeFormat() + ' ' - ) + tr::lng_imported(tr::now); - } else { - item->_timeText = dateTime().toString(cTimeFormat()); - } - item->_timeWidth = st::msgDateFont->width(item->_timeText); - } if (item->_text.hasSkipBlock()) { if (item->_text.updateSkipBlock(skipBlockWidth(), skipBlockHeight())) { item->_textWidth = -1; diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index fa3beaf94..8e649ede3 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "history/view/history_view_element.h" +#include "history/view/history_view_bottom_info.h" #include "ui/effects/animations.h" #include "base/weak_ptr.h" @@ -39,12 +40,6 @@ struct PsaTooltipState : public RuntimeComponent { mutable bool buttonVisible = true; }; -struct Reactions : public RuntimeComponent { - void update(const base::flat_map &list); - - Ui::Text::String text; -}; - class Message : public Element, public base::has_weak_ptr { public: Message( @@ -57,6 +52,11 @@ public: const ClickHandlerPtr &handler, bool pressed) override; + not_null message() const; + + const HistoryMessageEdited *displayedEditBadge() const; + HistoryMessageEdited *displayedEditBadge(); + int marginTop() const override; int marginBottom() const override; void draw(Painter &p, const PaintContext &context) const override; @@ -113,6 +113,9 @@ public: bool toggleSelectionByHandlerClick( const ClickHandlerPtr &handler) const override; int infoWidth() const override; + bool isSignedAuthorElided() const override; + + void itemDataChanged() override; VerticalRepaintRange verticalRepaintRange() const override; @@ -125,11 +128,8 @@ protected: private: struct CommentsButton; - not_null message() const; - void initLogEntryOriginal(); void initPsa(); - void refreshEditedBadge(); void fromNameUpdated(int width) const; [[nodiscard]] bool showForwardsFromSender( @@ -208,14 +208,11 @@ private: [[nodiscard]] bool displayFastShare() const; [[nodiscard]] bool displayGoToOriginal() const; [[nodiscard]] ClickHandlerPtr fastReplyLink() const; - [[nodiscard]] const HistoryMessageEdited *displayedEditBadge() const; - [[nodiscard]] HistoryMessageEdited *displayedEditBadge(); [[nodiscard]] auto displayedSponsorBadge() const -> const HistoryMessageSponsored*; [[nodiscard]] bool displayPinIcon() const; void initTime() const; - [[nodiscard]] int timeLeft() const; [[nodiscard]] int plainMaxWidth() const; [[nodiscard]] int monospaceMaxWidth() const; @@ -238,6 +235,8 @@ private: Ui::Text::String _rightBadge; int _bubbleWidthLimit = 0; + BottomInfo _bottomInfo; + }; } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 530427fa4..9482f452f 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -154,7 +154,10 @@ QSize Gif::countOptimalSize() { } _thumbw = tw; _thumbh = th; - auto maxWidth = qMax(tw, st::minPhotoSize); + auto maxWidth = std::clamp( + std::max(tw, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())), + st::minPhotoSize, + maxSize); auto minHeight = qMax(th, st::minPhotoSize); if (!activeCurrentStreamed()) { accumulate_max(maxWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); @@ -211,7 +214,10 @@ QSize Gif::countCurrentSize(int newWidth) { _thumbw = tw; _thumbh = th; - newWidth = qMax(tw, st::minPhotoSize); + newWidth = std::clamp( + std::max(tw, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())), + st::minPhotoSize, + maxSize); auto newHeight = qMax(th, st::minPhotoSize); if (!activeCurrentStreamed()) { accumulate_max(newWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); diff --git a/Telegram/SourceFiles/history/view/media/history_view_location.cpp b/Telegram/SourceFiles/history/view/media/history_view_location.cpp index b78703af8..affed2807 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_location.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_location.cpp @@ -82,7 +82,10 @@ QSize Location::countOptimalSize() { th = (st::maxMediaSize * th) / tw; tw = st::maxMediaSize; } - auto minWidth = qMax(st::minPhotoSize, _parent->minWidthForMedia()); + auto minWidth = std::clamp( + _parent->minWidthForMedia(), + st::minPhotoSize, + st::maxMediaSize); auto maxWidth = qMax(tw, minWidth); auto minHeight = qMax(th, st::minPhotoSize); @@ -118,7 +121,10 @@ QSize Location::countCurrentSize(int newWidth) { } else { newWidth = tw; } - auto minWidth = qMax(st::minPhotoSize, _parent->minWidthForMedia()); + auto minWidth = std::clamp( + _parent->minWidthForMedia(), + st::minPhotoSize, + st::maxMediaSize); accumulate_max(newWidth, minWidth); accumulate_max(newHeight, st::minPhotoSize); if (_parent->hasBubble()) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp index 1ec17cbaa..7d36d2a25 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp @@ -408,19 +408,19 @@ int UnwrappedMedia::calculateFullRight(const QRect &inner) const { + st::msgDateImgPadding.x() * 2 + st::msgReplyPadding.left(); const auto rightActionSize = _parent->rightActionSize(); + const auto rightSkip = st::msgPadding.left() + + (_parent->hasFromPhoto() + ? st::msgMargin.right() + : st::msgPadding.right()); const auto rightActionWidth = rightActionSize ? (st::historyFastShareLeft * 2 - + rightActionSize->width() - + st::msgPadding.left() - + (_parent->hasFromPhoto() - ? st::msgMargin.right() - : st::msgPadding.right())) + + rightActionSize->width()) : 0; auto fullRight = inner.x() + inner.width() + (rightAligned ? 0 : infoWidth); - if (fullRight + rightActionWidth > _parent->width()) { - fullRight = _parent->width() - rightActionWidth; + if (fullRight + rightActionWidth + rightSkip > _parent->width()) { + fullRight = _parent->width() - rightActionWidth - rightSkip; } return fullRight; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 22221a31d..e0aedeb49 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -164,9 +164,10 @@ QSize Photo::countOptimalSize() { if (_serviceWidth > 0) { return { _serviceWidth, _serviceWidth }; } - const auto minWidth = qMax( + const auto minWidth = std::clamp( + _parent->minWidthForMedia(), (_parent->hasBubble() ? st::historyPhotoBubbleMinWidth : st::minPhotoSize), - _parent->minWidthForMedia()); + st::maxMediaSize); const auto maxActualWidth = qMax(tw, minWidth); maxWidth = qMax(maxActualWidth, th); minHeight = qMax(th, st::minPhotoSize); @@ -206,9 +207,10 @@ QSize Photo::countCurrentSize(int newWidth) { if (_pixw < 1) _pixw = 1; if (_pixh < 1) _pixh = 1; - auto minWidth = qMax( + const auto minWidth = std::clamp( + _parent->minWidthForMedia(), (_parent->hasBubble() ? st::historyPhotoBubbleMinWidth : st::minPhotoSize), - _parent->minWidthForMedia()); + st::maxMediaSize); newWidth = qMax(_pixw, minWidth); auto newHeight = qMax(_pixh, st::minPhotoSize); if (_parent->hasBubble() && !_caption.isEmpty()) {