From cb653df0f6eafdbde8620e878731a5276b34dc00 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 5 Dec 2022 16:18:10 +0400 Subject: [PATCH] Support adaptive forum userpic rounding radius. --- Telegram/SourceFiles/api/api_chat_invite.cpp | 7 +- Telegram/SourceFiles/api/api_chat_invite.h | 6 +- Telegram/SourceFiles/api/api_who_reacted.cpp | 4 +- .../boxes/filters/edit_filter_box.cpp | 2 +- .../boxes/filters/edit_filter_chats_list.cpp | 2 +- Telegram/SourceFiles/boxes/peer_list_box.cpp | 14 +- Telegram/SourceFiles/boxes/peer_list_box.h | 5 +- .../boxes/peer_list_controllers.cpp | 2 +- .../boxes/peers/edit_peer_invite_link.cpp | 7 +- .../boxes/peers/prepare_short_info_box.cpp | 13 +- Telegram/SourceFiles/boxes/share_box.cpp | 8 +- Telegram/SourceFiles/calls/calls_panel.h | 1 - Telegram/SourceFiles/calls/calls_userpic.cpp | 9 +- Telegram/SourceFiles/calls/calls_userpic.h | 4 +- .../calls/group/calls_group_members_row.cpp | 4 +- .../calls/group/calls_group_members_row.h | 5 +- .../calls/group/calls_group_menu.cpp | 2 +- .../calls/group/calls_group_panel.h | 1 - .../group/calls_group_viewport_opengl.cpp | 2 +- .../group/calls_group_viewport_raster.cpp | 2 +- .../chat_helpers/field_autocomplete.cpp | 14 ++ .../chat_helpers/field_autocomplete.h | 17 +- .../chat_helpers/stickers_list_footer.h | 4 +- Telegram/SourceFiles/data/data_cloud_file.cpp | 49 ++--- Telegram/SourceFiles/data/data_cloud_file.h | 21 +- Telegram/SourceFiles/data/data_folder.cpp | 2 +- Telegram/SourceFiles/data/data_folder.h | 2 +- .../SourceFiles/data/data_forum_topic.cpp | 2 +- Telegram/SourceFiles/data/data_forum_topic.h | 2 +- Telegram/SourceFiles/data/data_peer.cpp | 197 +++++++----------- Telegram/SourceFiles/data/data_peer.h | 42 ++-- .../SourceFiles/data/data_peer_values.cpp | 14 +- Telegram/SourceFiles/data/data_peer_values.h | 4 - Telegram/SourceFiles/data/data_user.cpp | 9 +- Telegram/SourceFiles/dialogs/dialogs_entry.h | 4 +- .../dialogs/dialogs_inner_widget.cpp | 8 +- .../dialogs/dialogs_inner_widget.h | 10 +- Telegram/SourceFiles/dialogs/dialogs_row.cpp | 8 +- Telegram/SourceFiles/dialogs/dialogs_row.h | 12 +- .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 10 +- .../SourceFiles/dialogs/ui/dialogs_layout.h | 4 +- .../dialogs/ui/dialogs_video_userpic.cpp | 4 +- .../dialogs/ui/dialogs_video_userpic.h | 11 +- Telegram/SourceFiles/editor/editor_crop.cpp | 3 +- .../admin_log/history_admin_log_filter.cpp | 6 +- .../admin_log/history_admin_log_inner.h | 10 +- Telegram/SourceFiles/history/history.cpp | 2 +- Telegram/SourceFiles/history/history.h | 2 +- .../history/history_inner_widget.cpp | 20 +- .../history/history_inner_widget.h | 11 +- .../history/history_item_components.cpp | 31 ++- .../history/history_item_components.h | 2 + .../view/history_view_group_call_bar.cpp | 4 +- .../view/history_view_group_call_bar.h | 4 +- .../history/view/history_view_list_widget.cpp | 20 +- .../history/view/history_view_list_widget.h | 11 +- .../history/view/history_view_message.cpp | 4 +- .../view/history_view_requests_bar.cpp | 4 +- .../view/media/history_view_contact.cpp | 16 +- .../history/view/media/history_view_contact.h | 7 +- .../view/media/history_view_location.cpp | 11 +- .../view/media/history_view_location.h | 3 +- .../history/view/media/history_view_photo.cpp | 89 +++++--- .../history/view/media/history_view_photo.h | 6 +- .../history/view/media/history_view_poll.cpp | 13 +- .../history/view/media/history_view_poll.h | 10 +- .../view/reactions/history_view_reactions.cpp | 4 +- .../view/reactions/history_view_reactions.h | 1 - .../inline_bot_layout_internal.cpp | 14 +- .../inline_bots/inline_bot_layout_item.cpp | 6 +- .../inline_bots/inline_bot_layout_item.h | 8 +- Telegram/SourceFiles/main/main_session.cpp | 5 +- Telegram/SourceFiles/main/main_session.h | 3 +- .../media/view/media_view_overlay_widget.cpp | 15 +- .../linux/notifications_manager_linux.cpp | 15 +- .../linux/notifications_manager_linux.h | 2 +- .../platform/mac/notifications_manager_mac.h | 2 +- .../platform/mac/notifications_manager_mac.mm | 15 +- .../touchbar/items/mac_pinned_chats_item.mm | 4 +- .../win/notifications_manager_win.cpp | 21 +- .../platform/win/notifications_manager_win.h | 2 +- .../profile/profile_block_peer_list.h | 7 +- .../settings/settings_information.cpp | 2 +- .../SourceFiles/ui/effects/round_checkbox.cpp | 11 +- .../SourceFiles/ui/effects/round_checkbox.h | 4 +- Telegram/SourceFiles/ui/empty_userpic.cpp | 105 +--------- Telegram/SourceFiles/ui/empty_userpic.h | 40 +--- Telegram/SourceFiles/ui/special_buttons.cpp | 23 +- Telegram/SourceFiles/ui/special_buttons.h | 22 +- Telegram/SourceFiles/ui/userpic_view.cpp | 80 +++++++ Telegram/SourceFiles/ui/userpic_view.h | 41 ++++ .../window/notifications_manager.h | 9 +- .../window/notifications_manager_default.cpp | 6 +- .../window/notifications_manager_default.h | 7 +- .../window/notifications_utilities.cpp | 39 ++-- .../window/notifications_utilities.h | 26 +-- .../window/themes/window_theme_preview.cpp | 2 +- Telegram/cmake/td_ui.cmake | 2 + Telegram/lib_base | 2 +- Telegram/lib_ui | 2 +- 100 files changed, 662 insertions(+), 724 deletions(-) create mode 100644 Telegram/SourceFiles/ui/userpic_view.cpp create mode 100644 Telegram/SourceFiles/ui/userpic_view.h diff --git a/Telegram/SourceFiles/api/api_chat_invite.cpp b/Telegram/SourceFiles/api/api_chat_invite.cpp index e0afbabf4..eb1883ea6 100644 --- a/Telegram/SourceFiles/api/api_chat_invite.cpp +++ b/Telegram/SourceFiles/api/api_chat_invite.cpp @@ -171,6 +171,11 @@ void CheckChatInvite( } // namespace Api +struct ConfirmInviteBox::Participant { + not_null user; + Ui::PeerUserpicView userpic; +}; + ConfirmInviteBox::ConfirmInviteBox( QWidget*, not_null session, @@ -356,7 +361,7 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) { { .options = Images::Option::RoundCircle })); } } else if (_photoEmpty) { - _photoEmpty->paint( + _photoEmpty->paintCircle( p, (width() - st::confirmInvitePhotoSize) / 2, st::confirmInvitePhotoTop, diff --git a/Telegram/SourceFiles/api/api_chat_invite.h b/Telegram/SourceFiles/api/api_chat_invite.h index 95b42cbf5..1ae6f2529 100644 --- a/Telegram/SourceFiles/api/api_chat_invite.h +++ b/Telegram/SourceFiles/api/api_chat_invite.h @@ -21,7 +21,6 @@ class SessionController; } // namespace Window namespace Data { -class CloudImageView; class PhotoMedia; } // namespace Data @@ -55,10 +54,7 @@ protected: void paintEvent(QPaintEvent *e) override; private: - struct Participant { - not_null user; - std::shared_ptr userpic; - }; + struct Participant; struct ChatInvite { QString title; QString about; diff --git a/Telegram/SourceFiles/api/api_who_reacted.cpp b/Telegram/SourceFiles/api/api_who_reacted.cpp index 596a41cbe..7ebabbb72 100644 --- a/Telegram/SourceFiles/api/api_who_reacted.cpp +++ b/Telegram/SourceFiles/api/api_who_reacted.cpp @@ -114,7 +114,7 @@ struct Context { struct Userpic { not_null peer; QString customEntityData; - mutable std::shared_ptr view; + mutable Ui::PeerUserpicView view; mutable InMemoryKey uniqueKey; }; @@ -380,7 +380,7 @@ bool UpdateUserpics( const auto peer = not_null{ resolved.peer }; const auto &data = ReactionEntityData(resolved.reaction); const auto i = ranges::find(was, peer, &Userpic::peer); - if (i != end(was) && i->view) { + if (i != end(was) && i->view.cloud) { now.push_back(std::move(*i)); now.back().customEntityData = data; continue; diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp index c5d94f52c..e8fd6a843 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp @@ -84,7 +84,7 @@ private: }; struct PeerButton { not_null history; - std::shared_ptr userpic; + Ui::PeerUserpicView userpic; Ui::Text::String name; Button button; }; diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp index 4e4507a46..75b1487fa 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_chats_list.cpp @@ -157,7 +157,7 @@ PaintRoundImageCallback ExceptionRow::generatePaintUserpicCallback() { const auto peer = this->peer(); const auto saved = peer->isSelf(); const auto replies = peer->isRepliesChat(); - auto userpic = saved ? nullptr : ensureUserpicView(); + auto userpic = saved ? Ui::PeerUserpicView() : ensureUserpicView(); return [=](Painter &p, int x, int y, int outerWidth, int size) mutable { if (saved) { Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size); diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index 2ed495a55..c4bd163f5 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -48,7 +48,7 @@ PaintRoundImageCallback PaintUserpicCallback( }; } } - auto userpic = std::shared_ptr(); + auto userpic = Ui::PeerUserpicView(); return [=](Painter &p, int x, int y, int outerWidth, int size) mutable { peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size); }; @@ -635,8 +635,8 @@ QString PeerListRow::generateShortName() { : peer()->shortName(); } -std::shared_ptr &PeerListRow::ensureUserpicView() { - if (!_userpic) { +Ui::PeerUserpicView &PeerListRow::ensureUserpicView() { + if (!_userpic.cloud && peer()->hasUserpic()) { _userpic = peer()->createUserpicView(); } return _userpic; @@ -646,7 +646,7 @@ PaintRoundImageCallback PeerListRow::generatePaintUserpicCallback() { const auto saved = _isSavedMessagesChat; const auto replies = _isRepliesMessagesChat; const auto peer = this->peer(); - auto userpic = saved ? nullptr : ensureUserpicView(); + auto userpic = saved ? Ui::PeerUserpicView() : ensureUserpicView(); return [=](Painter &p, int x, int y, int outerWidth, int size) mutable { if (saved) { Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size); @@ -840,10 +840,10 @@ void PeerListRow::lazyInitialize(const style::PeerListItem &st) { void PeerListRow::createCheckbox( const style::RoundImageCheckbox &st, Fn updateCallback) { - const auto generateRadius = [=] { + const auto generateRadius = [=](int size) { return (!special() && peer()->isForum()) - ? ImageRoundRadius::Large - : ImageRoundRadius::Ellipse; + ? int(size * Ui::ForumUserpicRadiusMultiplier()) + : std::optional(); }; _checkbox = std::make_unique( st, diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index f416d74ba..f0c887d6b 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rp_widget.h" #include "ui/empty_userpic.h" #include "ui/unread_badge.h" +#include "ui/userpic_view.h" #include "boxes/abstract_box.h" #include "mtproto/sender.h" #include "data/data_cloud_file.h" @@ -84,7 +85,7 @@ public: return _id; } - [[nodiscard]] std::shared_ptr &ensureUserpicView(); + [[nodiscard]] Ui::PeerUserpicView &ensureUserpicView(); [[nodiscard]] virtual QString generateName(); [[nodiscard]] virtual QString generateShortName(); @@ -262,7 +263,7 @@ private: PeerListRowId _id = 0; PeerData *_peer = nullptr; - mutable std::shared_ptr _userpic; + mutable Ui::PeerUserpicView _userpic; std::unique_ptr _ripple; std::unique_ptr _checkbox; Ui::Text::String _name; diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index b1584b0f4..35613e4b8 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -632,7 +632,7 @@ auto ChooseTopicBoxController::Row::generatePaintUserpicCallback() int y, int outerWidth, int size) { - auto view = std::shared_ptr(); + auto view = Ui::PeerUserpicView(); p.translate(x, y); _topic->paintUserpic(p, view, { .st = &st::forumTopicRow, diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp index 6064d9208..f9a24c72b 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp @@ -1042,11 +1042,12 @@ void AddPermanentLinkBlock( state->allUserpicsLoaded = ranges::all_of( state->list, [](const HistoryView::UserpicInRow &element) { - return !element.peer->hasUserpic() || element.view->image(); + return !element.peer->hasUserpic() + || !Ui::PeerUserpicLoading(element.view); }); state->content = Ui::JoinedCountContent{ .count = state->count, - .userpics = state->cachedUserpics + .userpics = state->cachedUserpics, }; }; value->value( @@ -1087,7 +1088,7 @@ void AddPermanentLinkBlock( } else if (element.peer->userpicUniqueKey(element.view) != element.uniqueKey) { pushing = true; - } else if (!element.view->image()) { + } else if (Ui::PeerUserpicLoading(element.view)) { state->allUserpicsLoaded = false; } } diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp index a78c4b10e..520b46d4c 100644 --- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp @@ -36,7 +36,7 @@ struct UserpicState { PeerShortInfoUserpic current; std::optional userSlice; PhotoId userpicPhotoId = PeerData::kUnknownPhotoId; - std::shared_ptr userpicView; + Ui::PeerUserpicView userpicView; std::shared_ptr photoView; std::vector> photoPreloads; InMemoryKey userpicKey; @@ -76,27 +76,26 @@ void ProcessUserpic( not_null state) { state->current.videoDocument = nullptr; state->userpicKey = peer->userpicUniqueKey(state->userpicView); - if (!state->userpicView) { + if (!state->userpicView.cloud) { GenerateImage( state, peer->generateUserpicImage( state->userpicView, st::shortInfoWidth * style::DevicePixelRatio(), - ImageRoundRadius::None), + 0), false); state->current.photoLoadingProgress = 1.; state->photoView = nullptr; return; } peer->loadUserpic(); - const auto image = state->userpicView->image(); - if (!image) { + if (Ui::PeerUserpicLoading(state->userpicView)) { state->current.photoLoadingProgress = 0.; state->current.photo = QImage(); state->waitingLoad = true; return; } - GenerateImage(state, image, true); + GenerateImage(state, *state->userpicView.cloud, true); state->current.photoLoadingProgress = peer->userpicPhotoId() ? 0. : 1.; state->photoView = nullptr; } @@ -411,7 +410,7 @@ bool ProcessCurrent( return state->waitingLoad && (state->photoView ? (!!state->photoView->image(Data::PhotoSize::Large)) - : (state->userpicView && state->userpicView->image())); + : (!Ui::PeerUserpicLoading(state->userpicView))); }) | rpl::start_with_next([=] { push(); }, lifetime); diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index 95d9978a2..65a643710 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -536,7 +536,7 @@ void ShareBox::applyFilterUpdate(const QString &query) { } PaintRoundImageCallback ForceRoundUserpicCallback(not_null peer) { - auto userpic = std::shared_ptr(); + auto userpic = Ui::PeerUserpicView(); auto cache = std::make_shared(); return [=](Painter &p, int x, int y, int outerWidth, int size) mutable { const auto ratio = style::DevicePixelRatio(); @@ -956,9 +956,9 @@ ShareBox::Inner::Chat::Chat( st.checkbox, updateCallback, PaintUserpicCallback(peer, true), - [=] { return peer->isForum() - ? ImageRoundRadius::Large - : ImageRoundRadius::Ellipse; }) + [=](int size) { return peer->isForum() + ? int(size * Ui::ForumUserpicRadiusMultiplier()) + : std::optional(); }) , name(st.checkbox.imageRadius * 2) { } diff --git a/Telegram/SourceFiles/calls/calls_panel.h b/Telegram/SourceFiles/calls/calls_panel.h index 5e448857e..f891835c0 100644 --- a/Telegram/SourceFiles/calls/calls_panel.h +++ b/Telegram/SourceFiles/calls/calls_panel.h @@ -25,7 +25,6 @@ class PowerSaveBlocker; namespace Data { class PhotoMedia; -class CloudImageView; } // namespace Data namespace Ui { diff --git a/Telegram/SourceFiles/calls/calls_userpic.cpp b/Telegram/SourceFiles/calls/calls_userpic.cpp index 400299f29..f296ef0c6 100644 --- a/Telegram/SourceFiles/calls/calls_userpic.cpp +++ b/Telegram/SourceFiles/calls/calls_userpic.cpp @@ -159,7 +159,12 @@ void Userpic::refreshPhoto() { _userPhotoFull = true; createCache(_photo->image(Data::PhotoSize::Thumbnail)); } else if (_userPhoto.isNull()) { - createCache(_userpic ? _userpic->image() : nullptr); + if (const auto cloud = _peer->userpicCloudImage(_userpic)) { + auto image = Image(base::duplicate(*cloud)); + createCache(&image); + } else { + createCache(nullptr); + } } } @@ -200,7 +205,7 @@ void Userpic::createCache(Image *image) { Ui::EmptyUserpic::UserpicColor( Data::PeerColorIndex(_peer->id)), _peer->name() - ).paint(p, 0, 0, size, size); + ).paintCircle(p, 0, 0, size, size); } //_userPhoto = Images::PixmapFast(Images::Round( // std::move(filled), diff --git a/Telegram/SourceFiles/calls/calls_userpic.h b/Telegram/SourceFiles/calls/calls_userpic.h index 54bfcd8a5..369635348 100644 --- a/Telegram/SourceFiles/calls/calls_userpic.h +++ b/Telegram/SourceFiles/calls/calls_userpic.h @@ -8,13 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "ui/rp_widget.h" +#include "ui/userpic_view.h" #include "ui/effects/animations.h" class PeerData; class Image; namespace Data { -class CloudImageView; class PhotoMedia; } // namespace Data @@ -51,7 +51,7 @@ private: Ui::RpWidget _content; not_null _peer; - std::shared_ptr _userpic; + Ui::PeerUserpicView _userpic; std::shared_ptr _photo; Ui::Animations::Simple _mutedAnimation; QPixmap _userPhoto; diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp index f8e5a8a4c..7081c9dc0 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp @@ -350,7 +350,7 @@ void MembersRow::updateBlobAnimation(crl::time now) { } void MembersRow::ensureUserpicCache( - std::shared_ptr &view, + Ui::PeerUserpicView &view, int size) { Expects(_blobsAnimation != nullptr); @@ -401,7 +401,7 @@ void MembersRow::paintBlobs( void MembersRow::paintScaledUserpic( Painter &p, - std::shared_ptr &userpic, + Ui::PeerUserpicView &userpic, int x, int y, int outerWidth, diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.h b/Telegram/SourceFiles/calls/group/calls_group_members_row.h index 123ca3ec8..745b32459 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.h +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.h @@ -19,6 +19,7 @@ struct GroupCallParticipant; namespace Ui { class RippleAnimation; +struct PeerUserpicView; } // namespace Ui namespace Calls::Group { @@ -180,7 +181,7 @@ private: void setVolume(int volume); void ensureUserpicCache( - std::shared_ptr &view, + Ui::PeerUserpicView &view, int size); void paintBlobs( Painter &p, @@ -190,7 +191,7 @@ private: int sizeh, PanelMode mode); void paintScaledUserpic( Painter &p, - std::shared_ptr &userpic, + Ui::PeerUserpicView &userpic, int x, int y, int outerWidth, diff --git a/Telegram/SourceFiles/calls/group/calls_group_menu.cpp b/Telegram/SourceFiles/calls/group/calls_group_menu.cpp index d37085b29..aad072371 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_menu.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_menu.cpp @@ -59,7 +59,7 @@ private: const not_null _dummyAction; const style::Menu &_st; const not_null _peer; - std::shared_ptr _userpicView; + Ui::PeerUserpicView _userpicView; Ui::Text::String _text; Ui::Text::String _name; diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.h b/Telegram/SourceFiles/calls/group/calls_group_panel.h index 6dfca8b28..c1d251a50 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.h +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.h @@ -29,7 +29,6 @@ class PowerSaveBlocker; namespace Data { class PhotoMedia; -class CloudImageView; class GroupCall; } // namespace Data diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp index 2b6d91d6d..e4a04f7c5 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp @@ -462,7 +462,7 @@ void Viewport::RendererGL::validateUserpicFrame( tileData.userpicFrame = tile->row()->peer()->generateUserpicImage( tile->row()->ensureUserpicView(), size.width(), - ImageRoundRadius::None); + 0); } void Viewport::RendererGL::paintTile( diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp index 6c67b9fe8..f85929ea1 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp @@ -80,7 +80,7 @@ void Viewport::RendererSW::validateUserpicFrame( tile->row()->peer()->generateUserpicImage( tile->row()->ensureUserpicView(), size.width(), - ImageRoundRadius::None), + 0), kBlurRadius); } diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index 477937cd1..0f21d0121 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -165,6 +165,20 @@ struct FieldAutocomplete::StickerSuggestion { QImage premiumLock; }; +struct FieldAutocomplete::MentionRow { + not_null user; + Ui::Text::String name; + Ui::PeerUserpicView userpic; +}; + +struct FieldAutocomplete::BotCommandRow { + not_null user; + QString command; + QString description; + Ui::PeerUserpicView userpic; + Ui::Text::String descriptionText; +}; + FieldAutocomplete::FieldAutocomplete( QWidget *parent, not_null controller) diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h index 270f59438..a03d4c840 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h @@ -31,7 +31,6 @@ class SessionController; namespace Data { class DocumentMedia; -class CloudImageView; } // namespace Data namespace SendMenu { @@ -131,20 +130,8 @@ private: class Inner; friend class Inner; struct StickerSuggestion; - - struct MentionRow { - not_null user; - Ui::Text::String name; - std::shared_ptr userpic; - }; - - struct BotCommandRow { - not_null user; - QString command; - QString description; - std::shared_ptr userpic; - Ui::Text::String descriptionText; - }; + struct MentionRow; + struct BotCommandRow; using HashtagRows = std::vector; using BotCommandRows = std::vector; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h index e4fd909a7..78448a9cd 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/tabbed_selector.h" #include "mtproto/sender.h" #include "ui/round_rect.h" +#include "ui/userpic_view.h" namespace Ui { class InputField; @@ -21,7 +22,6 @@ namespace Data { class StickersSet; class StickersSetThumbnailView; class DocumentMedia; -class CloudImageView; } // namespace Data namespace Lottie { @@ -73,7 +73,7 @@ struct StickerIcon { ChannelData *megagroup = nullptr; mutable std::shared_ptr thumbnailMedia; mutable std::shared_ptr stickerMedia; - mutable std::shared_ptr megagroupUserpic; + mutable Ui::PeerUserpicView megagroupUserpic; int pixw = 0; int pixh = 0; mutable rpl::lifetime lifetime; diff --git a/Telegram/SourceFiles/data/data_cloud_file.cpp b/Telegram/SourceFiles/data/data_cloud_file.cpp index d99ad6ea3..6e35f2a8d 100644 --- a/Telegram/SourceFiles/data/data_cloud_file.cpp +++ b/Telegram/SourceFiles/data/data_cloud_file.cpp @@ -22,13 +22,6 @@ CloudFile::~CloudFile() { base::take(loader); } -void CloudImageView::set( - not_null session, - QImage image) { - _image.emplace(std::move(image)); - session->notifyDownloaderTaskFinished(); -} - CloudImage::CloudImage() = default; CloudImage::CloudImage( @@ -37,10 +30,6 @@ CloudImage::CloudImage( update(session, data); } -Image *CloudImageView::image() { - return _image ? &*_image : nullptr; -} - void CloudImage::set( not_null session, const ImageWithLocation &data) { @@ -52,11 +41,11 @@ void CloudImage::set( _file.location = ImageLocation(); _file.byteSize = 0; _file.flags = CloudFile::Flag(); - _view = std::weak_ptr(); + _view = std::weak_ptr(); } else if (was != now && (!v::is(was) || v::is(now))) { _file.location = ImageLocation(); - _view = std::weak_ptr(); + _view = std::weak_ptr(); } UpdateCloudFile( _file, @@ -65,9 +54,7 @@ void CloudImage::set( kImageCacheTag, [=](FileOrigin origin) { load(session, origin); }, [=](QImage preloaded, QByteArray) { - if (const auto view = activeView()) { - view->set(session, data.preloaded); - } + setToActive(session, std::move(preloaded)); }); } @@ -81,9 +68,7 @@ void CloudImage::update( kImageCacheTag, [=](FileOrigin origin) { load(session, origin); }, [=](QImage preloaded, QByteArray) { - if (const auto view = activeView()) { - view->set(session, data.preloaded); - } + setToActive(session, std::move(preloaded)); }); } @@ -107,16 +92,14 @@ void CloudImage::load(not_null session, FileOrigin origin) { const auto autoLoading = false; const auto finalCheck = [=] { if (const auto active = activeView()) { - return !active->image(); + return active->isNull(); } else if (_file.flags & CloudFile::Flag::Loaded) { return false; } return !(_file.flags & CloudFile::Flag::Loaded); }; const auto done = [=](QImage result, QByteArray) { - if (const auto active = activeView()) { - active->set(session, std::move(result)); - } + setToActive(session, std::move(result)); }; LoadCloudFile( session, @@ -137,27 +120,37 @@ int CloudImage::byteSize() const { return _file.byteSize; } -std::shared_ptr CloudImage::createView() { +std::shared_ptr CloudImage::createView() { if (auto active = activeView()) { return active; } - auto view = std::make_shared(); + auto view = std::make_shared(); _view = view; return view; } -std::shared_ptr CloudImage::activeView() const { +std::shared_ptr CloudImage::activeView() const { return _view.lock(); } -bool CloudImage::isCurrentView( - const std::shared_ptr &view) const { +bool CloudImage::isCurrentView(const std::shared_ptr &view) const { if (!view) { return empty(); } return !view.owner_before(_view) && !_view.owner_before(view); } +void CloudImage::setToActive( + not_null session, + QImage image) { + if (const auto view = activeView()) { + *view = image.isNull() + ? Image::Empty()->original() + : std::move(image); + session->notifyDownloaderTaskFinished(); + } +} + void UpdateCloudFile( CloudFile &file, const ImageWithLocation &data, diff --git a/Telegram/SourceFiles/data/data_cloud_file.h b/Telegram/SourceFiles/data/data_cloud_file.h index 799a1a688..e71cbe462 100644 --- a/Telegram/SourceFiles/data/data_cloud_file.h +++ b/Telegram/SourceFiles/data/data_cloud_file.h @@ -44,17 +44,6 @@ struct CloudFile final { base::flags flags; }; -class CloudImageView final { -public: - void set(not_null session, QImage image); - - [[nodiscard]] Image *image(); - -private: - std::optional _image; - -}; - class CloudImage final { public: CloudImage(); @@ -79,14 +68,16 @@ public: [[nodiscard]] const ImageLocation &location() const; [[nodiscard]] int byteSize() const; - [[nodiscard]] std::shared_ptr createView(); - [[nodiscard]] std::shared_ptr activeView() const; + [[nodiscard]] std::shared_ptr createView(); + [[nodiscard]] std::shared_ptr activeView() const; [[nodiscard]] bool isCurrentView( - const std::shared_ptr &view) const; + const std::shared_ptr &view) const; private: + void setToActive(not_null session, QImage image); + CloudFile _file; - std::weak_ptr _view; + std::weak_ptr _view; }; diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp index b8ed32698..bd027837b 100644 --- a/Telegram/SourceFiles/data/data_folder.cpp +++ b/Telegram/SourceFiles/data/data_folder.cpp @@ -216,7 +216,7 @@ void Folder::loadUserpic() { void Folder::paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Dialogs::Ui::PaintContext &context) const { paintUserpic( p, diff --git a/Telegram/SourceFiles/data/data_folder.h b/Telegram/SourceFiles/data/data_folder.h index 77805ef25..779c1ba1b 100644 --- a/Telegram/SourceFiles/data/data_folder.h +++ b/Telegram/SourceFiles/data/data_folder.h @@ -57,7 +57,7 @@ public: void loadUserpic() override; void paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Dialogs::Ui::PaintContext &context) const override; void paintUserpic(Painter &p, int x, int y, int size) const; void paintUserpic( diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index 5c87c3656..9e56bca29 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -568,7 +568,7 @@ void ForumTopic::loadUserpic() { void ForumTopic::paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Dialogs::Ui::PaintContext &context) const { const auto &st = context.st; auto position = QPoint(st->padding.left(), st->padding.top()); diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h index 12a4eb26e..e2a631723 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.h +++ b/Telegram/SourceFiles/data/data_forum_topic.h @@ -150,7 +150,7 @@ public: void loadUserpic() override; void paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Dialogs::Ui::PaintContext &context) const override; void clearUserpicLoops(); diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index a296bc72a..25cf34ad2 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -191,7 +191,7 @@ void PeerData::updateNameDelayed( } } _name = newName; - _userpicEmpty = nullptr; + invalidateEmptyUserpic(); auto flags = UpdateFlag::None | UpdateFlag::None; auto oldFirstLetters = base::flat_set(); @@ -231,13 +231,17 @@ not_null PeerData::ensureEmptyUserpic() const { const auto user = asUser(); _userpicEmpty = std::make_unique( Ui::EmptyUserpic::UserpicColor(Data::PeerColorIndex(id)), - user && user->isInaccessible() + ((user && user->isInaccessible()) ? Ui::EmptyUserpic::InaccessibleName() - : name()); + : name())); } return _userpicEmpty.get(); } +void PeerData::invalidateEmptyUserpic() { + _userpicEmpty = nullptr; +} + ClickHandlerPtr PeerData::createOpenLink() { return std::make_shared(this); } @@ -265,50 +269,45 @@ void PeerData::setUserpicPhoto(const MTPPhoto &data) { } } -Image *PeerData::currentUserpic( - std::shared_ptr &view) const { - if (!_userpic.isCurrentView(view)) { - view = _userpic.createView(); - _userpic.load(&session(), userpicOrigin()); +QImage *PeerData::userpicCloudImage(Ui::PeerUserpicView &view) const { + if (!_userpic.isCurrentView(view.cloud)) { + if (!_userpic.empty()) { + view.cloud = _userpic.createView(); + _userpic.load(&session(), userpicOrigin()); + } else { + view.cloud = nullptr; + if (view.empty.null()) { + view.paletteVersion = 0; + } + } } - const auto image = view ? view->image() : nullptr; - if (image) { + if (const auto image = view.cloud.get(); image && !image->isNull()) { _userpicEmpty = nullptr; + return image; } else if (isNotificationsUser()) { - static auto result = Image( - Window::LogoNoMargin().scaledToWidth( - kUserpicSize, - Qt::SmoothTransformation)); + static auto result = Window::LogoNoMargin().scaledToWidth( + kUserpicSize, + Qt::SmoothTransformation); return &result; } - return image; + return nullptr; } void PeerData::paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, int x, int y, int size) const { - if (const auto userpic = currentUserpic(view)) { - const auto rounding = isForum() - ? Images::Option::RoundLarge - : Images::Option::RoundCircle; - p.drawPixmap( - x, - y, - userpic->pix(size, size, { .options = rounding })); - } else if (isForum()) { - ensureEmptyUserpic()->paintRounded( - p, - x, - y, - x + size + x, - size, - st::roundRadiusLarge); - } else{ - ensureEmptyUserpic()->paint(p, x, y, x + size + x, size); - } + const auto cloud = userpicCloudImage(view); + const auto ratio = style::DevicePixelRatio(); + Ui::ValidateUserpicCache( + view, + cloud, + cloud ? nullptr : ensureEmptyUserpic().get(), + size * ratio, + isForum()); + p.drawImage(QRect(x, y, size, size), view.cached); } void PeerData::loadUserpic() { @@ -319,112 +318,76 @@ bool PeerData::hasUserpic() const { return !_userpic.empty(); } -std::shared_ptr PeerData::activeUserpicView() { - return _userpic.empty() ? nullptr : _userpic.activeView(); +Ui::PeerUserpicView PeerData::activeUserpicView() { + return { .cloud = _userpic.empty() ? nullptr : _userpic.activeView() }; } -std::shared_ptr PeerData::createUserpicView() { +Ui::PeerUserpicView PeerData::createUserpicView() { if (_userpic.empty()) { - return nullptr; + return {}; } auto result = _userpic.createView(); _userpic.load(&session(), userpicPhotoOrigin()); - return result; + return { .cloud = result }; } -bool PeerData::useEmptyUserpic( - std::shared_ptr &view) const { - return !currentUserpic(view); +bool PeerData::useEmptyUserpic(Ui::PeerUserpicView &view) const { + return !userpicCloudImage(view); } -InMemoryKey PeerData::userpicUniqueKey( - std::shared_ptr &view) const { +InMemoryKey PeerData::userpicUniqueKey(Ui::PeerUserpicView &view) const { return useEmptyUserpic(view) ? ensureEmptyUserpic()->uniqueKey() : inMemoryKey(_userpic.location()); } -void PeerData::saveUserpic( - std::shared_ptr &view, - const QString &path, - int size) const { - generateUserpicImage(view, size * cIntRetinaFactor()).save(path, "PNG"); -} - -void PeerData::saveUserpicRounded( - std::shared_ptr &view, - const QString &path, - int size) const { - generateUserpicImage( - view, - size * cIntRetinaFactor(), - ImageRoundRadius::Small).save(path, "PNG"); -} - -QPixmap PeerData::genUserpic( - std::shared_ptr &view, - int size) const { - if (const auto userpic = currentUserpic(view)) { - const auto rounding = isForum() - ? Images::Option::RoundLarge - : Images::Option::RoundCircle; - return userpic->pix(size, size, { .options = rounding }); - } - const auto ratio = style::DevicePixelRatio(); - auto result = QImage( - QSize(size, size) * ratio, - QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(ratio); - result.fill(Qt::transparent); - { - Painter p(&result); - paintUserpic(p, view, 0, 0, size); - } - return Ui::PixmapFromImage(std::move(result)); -} - QImage PeerData::generateUserpicImage( - std::shared_ptr &view, - int size) const { - return generateUserpicImage( - view, - size, - isForum() ? ImageRoundRadius::Large : ImageRoundRadius::Ellipse); -} - -QImage PeerData::generateUserpicImage( - std::shared_ptr &view, + Ui::PeerUserpicView &view, int size, - ImageRoundRadius radius) const { - if (const auto userpic = currentUserpic(view)) { - const auto options = (radius == ImageRoundRadius::Ellipse) - ? Images::Option::RoundCircle - : (radius == ImageRoundRadius::Large) - ? Images::Option::RoundLarge - : (radius == ImageRoundRadius::Small) - ? Images::Option::RoundSmall - : Images::Option(); - return userpic->pixNoCache( + std::optional radius) const { + if (const auto userpic = userpicCloudImage(view)) { + auto image = userpic->scaled( { size, size }, - { .options = options }).toImage(); + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + const auto round = [&](int radius) { + return Images::Round( + std::move(image), + Images::CornersMask(radius)); + }; + if (radius == 0) { + return image; + } else if (radius) { + return round(*radius); + } else if (isForum()) { + return round(size * Ui::ForumUserpicRadiusMultiplier()); + } else { + return Images::Circle(std::move(image)); + } } auto result = QImage( QSize(size, size), QImage::Format_ARGB32_Premultiplied); result.fill(Qt::transparent); - { - Painter p(&result); - if (radius == ImageRoundRadius::Ellipse) { - ensureEmptyUserpic()->paint(p, 0, 0, size, size); - } else if (radius == ImageRoundRadius::None) { - ensureEmptyUserpic()->paintSquare(p, 0, 0, size, size); - } else if (radius == ImageRoundRadius::Large) { - const auto radius = st::roundRadiusLarge; - ensureEmptyUserpic()->paintRounded(p, 0, 0, size, size, radius); - } else { - ensureEmptyUserpic()->paintRounded(p, 0, 0, size, size); - } + + Painter p(&result); + if (radius == 0) { + ensureEmptyUserpic()->paintSquare(p, 0, 0, size, size); + } else if (radius) { + ensureEmptyUserpic()->paintRounded(p, 0, 0, size, size, *radius); + } else if (isForum()) { + ensureEmptyUserpic()->paintRounded( + p, + 0, + 0, + size, + size, + size * Ui::ForumUserpicRadiusMultiplier()); + } else { + ensureEmptyUserpic()->paintCircle(p, 0, 0, size, size); } + p.end(); + return result; } diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index fe925ad82..566a1fd4c 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_flags.h" #include "data/notify/data_peer_notify_settings.h" #include "data/data_cloud_file.h" +#include "ui/userpic_view.h" struct BotInfo; class PeerData; @@ -36,13 +37,12 @@ class Forum; class ForumTopic; class Session; class GroupCall; -class CloudImageView; struct ReactionId; -int PeerColorIndex(PeerId peerId); +[[nodiscard]] int PeerColorIndex(PeerId peerId); // Must be used only for PeerColor-s. -PeerId FakePeerIdForJustName(const QString &name); +[[nodiscard]] PeerId FakePeerIdForJustName(const QString &name); class RestrictionCheckResult { public: @@ -264,13 +264,13 @@ public: void setUserpicPhoto(const MTPPhoto &data); void paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, int x, int y, int size) const; void paintUserpicLeft( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, int x, int y, int w, @@ -279,30 +279,14 @@ public: } void loadUserpic(); [[nodiscard]] bool hasUserpic() const; - [[nodiscard]] std::shared_ptr activeUserpicView(); - [[nodiscard]] std::shared_ptr createUserpicView(); - [[nodiscard]] bool useEmptyUserpic( - std::shared_ptr &view) const; - [[nodiscard]] InMemoryKey userpicUniqueKey( - std::shared_ptr &view) const; - void saveUserpic( - std::shared_ptr &view, - const QString &path, - int size) const; - void saveUserpicRounded( - std::shared_ptr &view, - const QString &path, - int size) const; - [[nodiscard]] QPixmap genUserpic( - std::shared_ptr &view, - int size) const; + [[nodiscard]] Ui::PeerUserpicView activeUserpicView(); + [[nodiscard]] Ui::PeerUserpicView createUserpicView(); + [[nodiscard]] bool useEmptyUserpic(Ui::PeerUserpicView &view) const; + [[nodiscard]] InMemoryKey userpicUniqueKey(Ui::PeerUserpicView &view) const; [[nodiscard]] QImage generateUserpicImage( - std::shared_ptr &view, - int size) const; - [[nodiscard]] QImage generateUserpicImage( - std::shared_ptr &view, + Ui::PeerUserpicView &view, int size, - ImageRoundRadius radius) const; + std::optional radius = {}) const; [[nodiscard]] ImageLocation userpicLocation() const { return _userpic.location(); } @@ -332,8 +316,7 @@ public: return _openLink; } - [[nodiscard]] Image *currentUserpic( - std::shared_ptr &view) const; + [[nodiscard]] QImage *userpicCloudImage(Ui::PeerUserpicView &view) const; [[nodiscard]] bool canPinMessages() const; [[nodiscard]] bool canEditMessagesIndefinitely() const; @@ -423,6 +406,7 @@ protected: const QString &newUsername); void updateUserpic(PhotoId photoId, MTP::DcId dcId, bool hasVideo); void clearUserpic(); + void invalidateEmptyUserpic(); private: void fillNames(); diff --git a/Telegram/SourceFiles/data/data_peer_values.cpp b/Telegram/SourceFiles/data/data_peer_values.cpp index ae46d9d6f..4b016d9dd 100644 --- a/Telegram/SourceFiles/data/data_peer_values.cpp +++ b/Telegram/SourceFiles/data/data_peer_values.cpp @@ -515,17 +515,10 @@ bool ChannelHasActiveCall(not_null channel) { rpl::producer PeerUserpicImageValue( not_null peer, int size) { - return PeerUserpicImageValue(peer, size, ImageRoundRadius::Ellipse); -} - -rpl::producer PeerUserpicImageValue( - not_null peer, - int size, - ImageRoundRadius radius) { return [=](auto consumer) { auto result = rpl::lifetime(); struct State { - std::shared_ptr view; + Ui::PeerUserpicView view; rpl::lifetime waiting; InMemoryKey key = {}; bool empty = true; @@ -534,7 +527,7 @@ rpl::producer PeerUserpicImageValue( const auto state = result.make_state(); state->push = [=] { const auto key = peer->userpicUniqueKey(state->view); - const auto loading = state->view && !state->view->image(); + const auto loading = Ui::PeerUserpicLoading(state->view); if (loading && !state->waiting) { peer->session().downloaderTaskFinished( @@ -548,8 +541,7 @@ rpl::producer PeerUserpicImageValue( } state->key = key; state->empty = false; - consumer.put_next( - peer->generateUserpicImage(state->view, size, radius)); + consumer.put_next(peer->generateUserpicImage(state->view, size)); }; peer->session().changes().peerFlagsValue( peer, diff --git a/Telegram/SourceFiles/data/data_peer_values.h b/Telegram/SourceFiles/data/data_peer_values.h index 72374bf0c..0a5d5f398 100644 --- a/Telegram/SourceFiles/data/data_peer_values.h +++ b/Telegram/SourceFiles/data/data_peer_values.h @@ -134,10 +134,6 @@ inline auto PeerFullFlagValue( [[nodiscard]] rpl::producer PeerUserpicImageValue( not_null peer, int size); -[[nodiscard]] rpl::producer PeerUserpicImageValue( - not_null peer, - int size, - ImageRoundRadius radius); [[nodiscard]] const AllowedReactions &PeerAllowedReactions( not_null peer); diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index d568987de..7d3ee694b 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -228,22 +228,27 @@ void UserData::setAccessHash(uint64 accessHash) { if (accessHash == kInaccessibleAccessHashOld) { _accessHash = 0; _flags.add(Flag::Deleted); + invalidateEmptyUserpic(); } else { _accessHash = accessHash; } } void UserData::setFlags(UserDataFlags which) { + if ((which & UserDataFlag::Deleted) + != (flags() & UserDataFlag::Deleted)) { + invalidateEmptyUserpic(); + } _flags.set((flags() & UserDataFlag::Self) | (which & ~UserDataFlag::Self)); } void UserData::addFlags(UserDataFlags which) { - _flags.add(which & ~UserDataFlag::Self); + setFlags(flags() | which); } void UserData::removeFlags(UserDataFlags which) { - _flags.remove(which & ~UserDataFlag::Self); + setFlags(flags() & ~which); } bool UserData::isVerified() const { diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.h b/Telegram/SourceFiles/dialogs/dialogs_entry.h index a8940d2ae..bfb38d6dc 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.h +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.h @@ -25,10 +25,10 @@ class Session; class Forum; class Folder; class ForumTopic; -class CloudImageView; } // namespace Data namespace Ui { +struct PeerUserpicView; } // namespace Ui namespace Dialogs::Ui { @@ -233,7 +233,7 @@ public: virtual void loadUserpic() = 0; virtual void paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Ui::PaintContext &context) const = 0; [[nodiscard]] TimeId chatListTimeId() const { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 51b77d469..d41c86164 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1134,7 +1134,7 @@ void InnerWidget::paintSearchInFilter( void InnerWidget::paintSearchInPeer( Painter &p, not_null peer, - std::shared_ptr &userpic, + Ui::PeerUserpicView &userpic, int top, const Ui::Text::String &text) const { const auto paintUserpic = [&](Painter &p, int x, int y, int size) { @@ -1168,7 +1168,7 @@ void InnerWidget::paintSearchInTopic( Painter &p, const Ui::PaintContext &context, not_null topic, - std::shared_ptr &userpic, + Ui::PeerUserpicView &userpic, int top, const Ui::Text::String &text) const { const auto paintUserpic = [&](Painter &p, int x, int y, int size) { @@ -2846,7 +2846,7 @@ void InnerWidget::searchInChat(Key key, PeerData *from) { _searchFromUserUserpic = _searchFromPeer->createUserpicView(); } else { _cancelSearchFromUser->hide(); - _searchFromUserUserpic = nullptr; + _searchFromUserUserpic = {}; } if (_searchInChat || _searchFromPeer) { refreshSearchInChatLabel(); @@ -2855,7 +2855,7 @@ void InnerWidget::searchInChat(Key key, PeerData *from) { if (const auto peer = _searchInChat.peer()) { _searchInChatUserpic = peer->createUserpicView(); } else { - _searchInChatUserpic = nullptr; + _searchInChatUserpic = {}; } moveCancelSearchButtons(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index dc153f5d5..9a78d7784 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/dragging_scroll_manager.h" #include "ui/effects/animations.h" #include "ui/rp_widget.h" +#include "ui/userpic_view.h" #include "base/flags.h" #include "base/object_ptr.h" @@ -39,7 +40,6 @@ class SessionController; } // namespace Window namespace Data { -class CloudImageView; class Thread; class Folder; class Forum; @@ -340,7 +340,7 @@ private: void paintSearchInPeer( Painter &p, not_null peer, - std::shared_ptr &userpic, + Ui::PeerUserpicView &userpic, int top, const Ui::Text::String &text) const; void paintSearchInSaved( @@ -355,7 +355,7 @@ private: Painter &p, const Ui::PaintContext &context, not_null topic, - std::shared_ptr &userpic, + Ui::PeerUserpicView &userpic, int top, const Ui::Text::String &text) const; template @@ -470,8 +470,8 @@ private: Key _searchInChat; History *_searchInMigrated = nullptr; PeerData *_searchFromPeer = nullptr; - mutable std::shared_ptr _searchInChatUserpic; - mutable std::shared_ptr _searchFromUserUserpic; + mutable Ui::PeerUserpicView _searchInChatUserpic; + mutable Ui::PeerUserpicView _searchFromUserUserpic; Ui::Text::String _searchInChatText; Ui::Text::String _searchFromUserText; RowDescriptor _menuRow; diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index a557aea79..376ca14fe 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -38,11 +38,11 @@ constexpr auto kNoneLayer = 0; void PaintCornerBadgeTTLFrame( QPainter &q, not_null peer, - std::shared_ptr &view, + Ui::PeerUserpicView &view, float64 progress, int photoSize) { const auto ttl = peer->messagesTTL(); - if (!ttl || !view) { + if (!ttl) { return; } using Radius = ImageRoundRadius; @@ -54,7 +54,7 @@ void PaintCornerBadgeTTLFrame( const auto ratio = style::DevicePixelRatio(); const auto fullSize = photoSize; const auto blurredFull = Images::BlurLargeImage( - peer->generateUserpicImage(view, fullSize * ratio, Radius::None), + peer->generateUserpicImage(view, fullSize * ratio, 0), kBlurRadius); const auto partRect = CornerBadgeTTLRect(fullSize); const auto &partSize = partRect.width(); @@ -338,7 +338,7 @@ void Row::PaintCornerBadgeFrame( not_null data, not_null peer, Ui::VideoUserpic *videoUserpic, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Ui::PaintContext &context) { data->frame.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index a8689bf2a..e1ccc435c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text.h" #include "ui/effects/animations.h" #include "ui/unread_badge.h" +#include "ui/userpic_view.h" #include "dialogs/dialogs_key.h" #include "dialogs/ui/dialogs_message_view.h" @@ -20,10 +21,6 @@ namespace style { struct DialogRow; } // namespace style -namespace Data { -class CloudImageView; -} // namespace Data - namespace Ui { class RippleAnimation; } // namespace Ui @@ -69,13 +66,12 @@ public: int outerWidth, const QColor *colorOverride = nullptr) const; - [[nodiscard]] auto userpicView() const - -> std::shared_ptr & { + [[nodiscard]] Ui::PeerUserpicView &userpicView() const { return _userpic; } private: - mutable std::shared_ptr _userpic; + mutable Ui::PeerUserpicView _userpic; mutable std::unique_ptr _ripple; }; @@ -182,7 +178,7 @@ private: not_null data, not_null peer, Ui::VideoUserpic *videoUserpic, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Ui::PaintContext &context); Key _id; diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 02a022823..32d53834e 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -285,9 +285,9 @@ void PaintRow( not_null entry, VideoUserpic *videoUserpic, PeerData *from, - Ui::PeerBadge &fromBadge, + PeerBadge &fromBadge, Fn customEmojiRepaint, - const Ui::Text::String &fromName, + const Text::String &fromName, const HiddenSenderInfo *hiddenSenderInfo, HistoryItem *item, const Data::Draft *draft, @@ -306,8 +306,8 @@ void PaintRow( : context.selected ? st::dialogsBgOver : anim::brush( - st::dialogsBg, - st::dialogsBgOver, + st::dialogsBg, + st::dialogsBgOver, context.childListShown); p.fillRect(geometry, bg); if (!(flags & Flag::TopicJumpRipple)) { @@ -342,7 +342,7 @@ void PaintRow( (flags & Flag::AllowUserOnline) ? history : nullptr, context); } else if (hiddenSenderInfo) { - hiddenSenderInfo->emptyUserpic.paint( + hiddenSenderInfo->emptyUserpic.paintCircle( p, context.st->padding.left(), context.st->padding.top(), diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h index 29ebc80c0..bb637c852 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h @@ -38,8 +38,8 @@ using namespace ::Ui; class VideoUserpic; struct TopicJumpCorners { - Ui::CornersPixmaps normal; - Ui::CornersPixmaps inverted; + CornersPixmaps normal; + CornersPixmaps inverted; QPixmap small; int invertedRadius = 0; int smallKey = 0; // = `-radius` if top right else `radius`. diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp index 353a11300..cdebd9da4 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp @@ -30,7 +30,7 @@ int VideoUserpic::frameIndex() const { void VideoUserpic::paintLeft( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, int x, int y, int w, @@ -133,7 +133,7 @@ void PaintUserpic( Painter &p, not_null peer, Ui::VideoUserpic *videoUserpic, - std::shared_ptr &view, + Ui::PeerUserpicView &view, int x, int y, int outerWidth, diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h b/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h index 3cc332ba8..6c285ce97 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h @@ -12,10 +12,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class Painter; namespace Data { -class CloudImageView; class PhotoMedia; } // namespace Data +namespace Ui { +struct PeerUserpicView; +} // namespace Ui + namespace Dialogs::Ui { using namespace ::Ui; @@ -29,7 +32,7 @@ public: void paintLeft( Painter &p, - std::shared_ptr &view, + PeerUserpicView &view, int x, int y, int w, @@ -54,8 +57,8 @@ private: void PaintUserpic( Painter &p, not_null peer, - Ui::VideoUserpic *videoUserpic, - std::shared_ptr &view, + VideoUserpic *videoUserpic, + PeerUserpicView &view, int x, int y, int outerWidth, diff --git a/Telegram/SourceFiles/editor/editor_crop.cpp b/Telegram/SourceFiles/editor/editor_crop.cpp index 9e3885a28..78a91aa6a 100644 --- a/Telegram/SourceFiles/editor/editor_crop.cpp +++ b/Telegram/SourceFiles/editor/editor_crop.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "editor/editor_crop.h" +#include "ui/userpic_view.h" #include "styles/style_editor.h" #include "styles/style_basic.h" #include "styles/style_dialogs.h" @@ -149,7 +150,7 @@ void Crop::setCropPaint(QRectF &&rect) { _painterPath.addEllipse(_cropPaint); } else if (_data.cropType == EditorData::CropType::RoundedRect) { const auto radius = std::min(_cropPaint.width(), _cropPaint.height()) - * st::roundRadiusLarge / float64(st::defaultDialogRow.photoSize); + * Ui::ForumUserpicRadiusMultiplier(); _painterPath.addRoundedRect(_cropPaint, radius, radius); } else { _painterPath.addRect(_cropPaint); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_filter.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_filter.cpp index 07b062d64..6265c81e4 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_filter.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_filter.cpp @@ -20,10 +20,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_boxes.h" #include "styles/style_chat.h" -namespace Data { -class CloudImageView; -} // namespace Data - namespace AdminLog { namespace { @@ -64,7 +60,7 @@ private: QRect _checkRect; const not_null _user; - std::shared_ptr _userpic; + Ui::PeerUserpicView _userpic; Ui::Text::String _name; QString _statusText; bool _statusOnline = false; diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h index 1eb60a8b1..cf92d2ceb 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h @@ -19,10 +19,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL struct ChatRestrictionsInfo; -namespace Data { -class CloudImageView; -} // namespace Data - namespace Main { class Session; } // namespace Main @@ -38,6 +34,7 @@ enum class PointState : char; namespace Ui { class PopupMenu; class ChatStyle; +struct PeerUserpicView; } // namespace Ui namespace Window { @@ -278,9 +275,8 @@ private: std::map, not_null> _itemsByData; base::flat_map, TimeId> _itemDates; base::flat_set _animatedStickersPlayed; - base::flat_map< - not_null, - std::shared_ptr> _userpics, _userpicsCache; + base::flat_map, Ui::PeerUserpicView> _userpics; + base::flat_map, Ui::PeerUserpicView> _userpicsCache; int _itemsTop = 0; int _itemsWidth = 0; int _itemsHeight = 0; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 0db425b6d..6e9d5e621 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -2262,7 +2262,7 @@ void History::loadUserpic() { void History::paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Dialogs::Ui::PaintContext &context) const { peer->paintUserpic( p, diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 9f189af24..e3c408820 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -398,7 +398,7 @@ public: void loadUserpic() override; void paintUserpic( Painter &p, - std::shared_ptr &view, + Ui::PeerUserpicView &view, const Dialogs::Ui::PaintContext &context) const override; void refreshChatListNameSortKey(); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 3cdcf3091..cc36aee31 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1135,7 +1135,8 @@ void HistoryInner::paintEvent(QPaintEvent *e) { // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { - if (const auto from = view->data()->displayFrom()) { + const auto item = view->data(); + if (const auto from = item->displayFrom()) { Dialogs::Ui::PaintUserpic( p, from, @@ -1146,28 +1147,25 @@ void HistoryInner::paintEvent(QPaintEvent *e) { width(), st::msgPhotoSize, context.paused); - } else if (const auto info = view->data()->hiddenSenderInfo()) { + } else if (const auto info = item->hiddenSenderInfo()) { if (info->customUserpic.empty()) { - info->emptyUserpic.paint( + info->emptyUserpic.paintCircle( p, st::historyPhotoLeft, userpicTop, width(), st::msgPhotoSize); } else { - const auto painted = info->paintCustomUserpic( + auto &userpic = _hiddenSenderUserpics[item->id]; + const auto valid = info->paintCustomUserpic( p, + userpic, st::historyPhotoLeft, userpicTop, width(), st::msgPhotoSize); - if (!painted) { - const auto itemId = view->data()->fullId(); - auto &v = _sponsoredUserpics[itemId.msg]; - if (!info->customUserpic.isCurrentView(v)) { - v = info->customUserpic.createView(); - info->customUserpic.load(&session(), itemId); - } + if (!valid) { + info->customUserpic.load(&session(), item->fullId()); } } } else { diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 43ff3fb45..7a4430524 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -20,7 +20,6 @@ struct ClickHandlerContext; namespace Data { struct Group; -class CloudImageView; } // namespace Data namespace HistoryView { @@ -51,6 +50,7 @@ class PopupMenu; enum class ReportReason; struct ChatPaintContext; class PathShiftGradient; +struct PeerUserpicView; } // namespace Ui namespace Dialogs::Ui { @@ -458,12 +458,9 @@ private: bool _isChatWide = false; base::flat_set> _animatedStickersPlayed; - base::flat_map< - not_null, - std::shared_ptr> _userpics, _userpicsCache; - base::flat_map< - MsgId, - std::shared_ptr> _sponsoredUserpics; + base::flat_map, Ui::PeerUserpicView> _userpics; + base::flat_map, Ui::PeerUserpicView> _userpicsCache; + base::flat_map _hiddenSenderUserpics; base::flat_map< not_null, std::unique_ptr> _videoUserpics; diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 160b05609..c9832365d 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -144,22 +144,31 @@ ClickHandlerPtr HiddenSenderInfo::ForwardClickHandler() { bool HiddenSenderInfo::paintCustomUserpic( Painter &p, + Ui::PeerUserpicView &view, int x, int y, int outerWidth, int size) const { - const auto view = customUserpic.activeView(); - if (const auto image = view ? view->image() : nullptr) { - const auto circled = Images::Option::RoundCircle; - p.drawPixmap( - x, - y, - image->pix(size, size, { .options = circled })); - return true; - } else { - emptyUserpic.paint(p, x, y, outerWidth, size); - return false; + Expects(!customUserpic.empty()); + + auto valid = true; + if (!customUserpic.isCurrentView(view.cloud)) { + view.cloud = customUserpic.createView(); + valid = false; } + const auto image = *view.cloud; + if (image.isNull()) { + emptyUserpic.paintCircle(p, x, y, outerWidth, size); + return valid; + } + Ui::ValidateUserpicCache( + view, + image.isNull() ? nullptr : &image, + image.isNull() ? &emptyUserpic : nullptr, + size * style::DevicePixelRatio(), + false); + p.drawImage(QRect(x, y, size, size), view.cached); + return valid; } void HistoryMessageForwarded::create(const HistoryMessageVia *via) const { diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 9e69f3335..2b04d7784 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -19,6 +19,7 @@ class VoiceSeekClickHandler; namespace Ui { struct ChatPaintContext; class ChatStyle; +struct PeerUserpicView; } // namespace Ui namespace Data { @@ -94,6 +95,7 @@ public: [[nodiscard]] const Ui::Text::String &nameText() const; [[nodiscard]] bool paintCustomUserpic( Painter &p, + Ui::PeerUserpicView &view, int x, int y, int outerWidth, diff --git a/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp b/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp index 60d7994ba..b8bd52464 100644 --- a/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp @@ -139,12 +139,12 @@ rpl::producer GroupCallBarContentByCall( state->someUserpicsNotLoaded = false; for (auto &userpic : state->userpics) { userpic.peer->loadUserpic(); - const auto pic = userpic.peer->genUserpic( + auto image = userpic.peer->generateUserpicImage( userpic.view, userpicSize); userpic.uniqueKey = userpic.peer->userpicUniqueKey(userpic.view); state->current.users.push_back({ - .userpic = pic.toImage(), + .userpic = std::move(image), .userpicKey = userpic.uniqueKey, .id = userpic.peer->id.value, .speaking = userpic.speaking, diff --git a/Telegram/SourceFiles/history/view/history_view_group_call_bar.h b/Telegram/SourceFiles/history/view/history_view_group_call_bar.h index 90814c7f1..fd96caba4 100644 --- a/Telegram/SourceFiles/history/view/history_view_group_call_bar.h +++ b/Telegram/SourceFiles/history/view/history_view_group_call_bar.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "ui/rp_widget.h" +#include "ui/userpic_view.h" namespace Ui { struct GroupCallBarContent; @@ -15,7 +16,6 @@ struct GroupCallBarContent; namespace Data { class GroupCall; -class CloudImageView; } // namespace Data namespace style { @@ -27,7 +27,7 @@ namespace HistoryView { struct UserpicInRow { not_null peer; bool speaking = false; - mutable std::shared_ptr view; + mutable Ui::PeerUserpicView view; mutable InMemoryKey uniqueKey; }; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index d808544ef..edb83f268 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2132,7 +2132,8 @@ void ListWidget::paintEvent(QPaintEvent *e) { // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { - if (const auto from = view->data()->displayFrom()) { + const auto item = view->data(); + if (const auto from = item->displayFrom()) { from->paintUserpicLeft( p, _userpics[from], @@ -2140,28 +2141,25 @@ void ListWidget::paintEvent(QPaintEvent *e) { userpicTop, view->width(), st::msgPhotoSize); - } else if (const auto info = view->data()->hiddenSenderInfo()) { + } else if (const auto info = item->hiddenSenderInfo()) { if (info->customUserpic.empty()) { - info->emptyUserpic.paint( + info->emptyUserpic.paintCircle( p, st::historyPhotoLeft, userpicTop, view->width(), st::msgPhotoSize); } else { - const auto painted = info->paintCustomUserpic( + auto &userpic = _hiddenSenderUserpics[item->id]; + const auto valid = info->paintCustomUserpic( p, + userpic, st::historyPhotoLeft, userpicTop, view->width(), st::msgPhotoSize); - if (!painted) { - const auto itemId = view->data()->fullId(); - auto &v = _sponsoredUserpics[itemId.msg]; - if (!info->customUserpic.isCurrentView(v)) { - v = info->customUserpic.createView(); - info->customUserpic.load(session, itemId); - } + if (!valid) { + info->customUserpic.load(session, item->fullId()); } } } else { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 7d8c435c0..0dbeb7eef 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -29,6 +29,7 @@ class PopupMenu; class ChatTheme; struct ChatPaintContext; enum class TouchScrollState; +struct PeerUserpicView; } // namespace Ui namespace Window { @@ -37,7 +38,6 @@ class SessionController; namespace Data { struct Group; -class CloudImageView; struct Reaction; struct AllowedReactions; } // namespace Data @@ -637,12 +637,9 @@ private: ItemRevealAnimation> _itemRevealAnimations; int _itemsRevealHeight = 0; base::flat_set _animatedStickersPlayed; - base::flat_map< - not_null, - std::shared_ptr> _userpics, _userpicsCache; - base::flat_map< - MsgId, - std::shared_ptr> _sponsoredUserpics; + base::flat_map, Ui::PeerUserpicView> _userpics; + base::flat_map, Ui::PeerUserpicView> _userpicsCache; + base::flat_map _hiddenSenderUserpics; const std::unique_ptr _pathGradient; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index abc076a20..99ee3f907 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1105,10 +1105,10 @@ void Message::paintCommentsButton( auto &entry = list[i]; const auto peer = entry.peer; auto &view = entry.view; - const auto wasView = view.get(); + const auto wasView = view.cloud.get(); if (views->recentRepliers[i] != peer->id || peer->userpicUniqueKey(view) != entry.uniqueKey - || view.get() != wasView) { + || view.cloud.get() != wasView) { return true; } } diff --git a/Telegram/SourceFiles/history/view/history_view_requests_bar.cpp b/Telegram/SourceFiles/history/view/history_view_requests_bar.cpp index 298f43b2a..88af5ad6e 100644 --- a/Telegram/SourceFiles/history/view/history_view_requests_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_requests_bar.cpp @@ -86,12 +86,12 @@ rpl::producer RequestsBarContentByPeer( state->someUserpicsNotLoaded = false; for (auto &userpic : state->userpics) { userpic.peer->loadUserpic(); - const auto pic = userpic.peer->genUserpic( + auto image = userpic.peer->generateUserpicImage( userpic.view, userpicSize); userpic.uniqueKey = userpic.peer->userpicUniqueKey(userpic.view); state->current.users.push_back({ - .userpic = pic.toImage(), + .userpic = std::move(image), .userpicKey = userpic.uniqueKey, .id = userpic.peer->id.value, }); diff --git a/Telegram/SourceFiles/history/view/media/history_view_contact.cpp b/Telegram/SourceFiles/history/view/media/history_view_contact.cpp index c52227287..d33f1ba8a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_contact.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_contact.cpp @@ -96,8 +96,8 @@ Contact::Contact( Contact::~Contact() { history()->owner().unregisterContactView(_userId, _parent); - if (_userpic) { - _userpic = nullptr; + if (!_userpic.null()) { + _userpic = {}; _parent->checkHeavyPart(); } } @@ -177,13 +177,13 @@ void Contact::draw(Painter &p, const PaintContext &context) const { if (_userId) { QRect rthumb(style::rtlrect(st.padding.left(), st.padding.top() - topMinus, st.thumbSize, st.thumbSize, paintw)); if (_contact) { - const auto was = (_userpic != nullptr); + const auto was = !_userpic.null(); _contact->paintUserpic(p, _userpic, rthumb.x(), rthumb.y(), st.thumbSize); - if (!was && _userpic) { + if (!was && !_userpic.null()) { history()->owner().registerHeavyViewPart(_parent); } } else { - _photoEmpty->paint(p, st.padding.left(), st.padding.top() - topMinus, paintw, st.thumbSize); + _photoEmpty->paintCircle(p, st.padding.left(), st.padding.top() - topMinus, paintw, st.thumbSize); } if (context.selected()) { PainterHighQualityEnabler hq(p); @@ -197,7 +197,7 @@ void Contact::draw(Painter &p, const PaintContext &context) const { p.setPen(stm->msgFileThumbLinkFg); p.drawTextLeft(nameleft, linktop, paintw, _link, _linkw); } else { - _photoEmpty->paint(p, st.padding.left(), st.padding.top() - topMinus, paintw, st.thumbSize); + _photoEmpty->paintCircle(p, st.padding.left(), st.padding.top() - topMinus, paintw, st.thumbSize); } const auto namewidth = paintw - nameleft - nameright; @@ -232,11 +232,11 @@ TextState Contact::textState(QPoint point, StateRequest request) const { } void Contact::unloadHeavyPart() { - _userpic = nullptr; + _userpic = {}; } bool Contact::hasHeavyPart() const { - return (_userpic != nullptr); + return !_userpic.null(); } } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_contact.h b/Telegram/SourceFiles/history/view/media/history_view_contact.h index 1d7912eb9..ecca595f2 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_contact.h +++ b/Telegram/SourceFiles/history/view/media/history_view_contact.h @@ -8,10 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "history/view/media/history_view_media.h" - -namespace Data { -class CloudImageView; -} // namespace Data +#include "ui/userpic_view.h" namespace Ui { class EmptyUserpic; @@ -72,7 +69,7 @@ private: QString _fname, _lname, _phone; Ui::Text::String _name; std::unique_ptr _photoEmpty; - mutable std::shared_ptr _userpic; + mutable Ui::PeerUserpicView _userpic; ClickHandlerPtr _linkl; int _linkw = 0; diff --git a/Telegram/SourceFiles/history/view/media/history_view_location.cpp b/Telegram/SourceFiles/history/view/media/history_view_location.cpp index 0fc8f5ad8..f8890ed1b 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_location.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_location.cpp @@ -245,17 +245,16 @@ void Location::draw(Painter &p, const PaintContext &context) const { void Location::validateImageCache( QSize outer, Ui::BubbleRounding rounding) const { + Expects(_media != nullptr); + const auto ratio = style::DevicePixelRatio(); if (_imageCache.size() == (outer * ratio) - && _imageCacheRounding == rounding) { - return; - } - const auto thumbnail = _media->image(); - if (!thumbnail) { + && _imageCacheRounding == rounding + || _media->isNull()) { return; } _imageCache = Images::Round( - thumbnail->original().scaled( + _media->scaled( outer * ratio, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), diff --git a/Telegram/SourceFiles/history/view/media/history_view_location.h b/Telegram/SourceFiles/history/view/media/history_view_location.h index 46f49caf9..ec412fd00 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_location.h +++ b/Telegram/SourceFiles/history/view/media/history_view_location.h @@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Data { class CloudImage; -class CloudImageView; } // namespace Data namespace HistoryView { @@ -81,7 +80,7 @@ private: [[nodiscard]] int fullHeight() const; const not_null _data; - mutable std::shared_ptr _media; + mutable std::shared_ptr _media; Ui::Text::String _title, _description; ClickHandlerPtr _link; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 3402ce431..73913a198 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -46,6 +46,7 @@ struct Photo::Streamed { ::Media::Streaming::Instance instance; ::Media::Streaming::FrameRequest frozenRequest; QImage frozenFrame; + std::array roundingCorners; QImage roundingMask; }; @@ -352,22 +353,66 @@ void Photo::draw(Painter &p, const PaintContext &context) const { } } +void Photo::validateUserpicImageCache(QSize size, bool forum) const { + const auto forumValue = forum ? 1 : 0; + const auto large = _dataMedia->image(PhotoSize::Large); + const auto ratio = style::DevicePixelRatio(); + const auto blurredValue = large ? 0 : 1; + if (_imageCache.size() == (size * ratio) + && _imageCacheForum == forumValue + && _imageCacheBlurred == blurredValue) { + return; + } + auto original = [&] { + if (large) { + return large->original(); + } else if (const auto thumbnail = _dataMedia->image( + PhotoSize::Thumbnail)) { + return thumbnail->original(); + } else if (const auto small = _dataMedia->image( + PhotoSize::Small)) { + return small->original(); + } else if (const auto blurred = _dataMedia->thumbnailInline()) { + return blurred->original(); + } else { + return Image::Empty()->original(); + } + }(); + auto args = Images::PrepareArgs(); + if (blurredValue) { + args = args.blurred(); + } + original = Images::Prepare(std::move(original), size, args); + if (forumValue) { + original = Images::Round( + std::move(original), + Images::CornersMask(std::min(size.width(), size.height()) + * Ui::ForumUserpicRadiusMultiplier() + * style::DevicePixelRatio())); + } else { + original = Images::Circle(std::move(original)); + } + _imageCache = std::move(original); + _imageCacheForum = forumValue; + _imageCacheBlurred = blurredValue; +} + void Photo::validateImageCache( QSize outer, std::optional rounding) const { const auto large = _dataMedia->image(PhotoSize::Large); const auto ratio = style::DevicePixelRatio(); - const auto shouldBeBlurred = !large; + const auto blurredValue = large ? 0 : 1; if (_imageCache.size() == (outer * ratio) && _imageCacheRounding == rounding - && _imageCacheBlurred == shouldBeBlurred) { + && _imageCacheBlurred == blurredValue) { return; } _imageCache = Images::Round( prepareImageCache(outer), MediaRoundingMask(rounding)); _imageCacheRounding = rounding; - _imageCacheBlurred = shouldBeBlurred; + _imageCacheBlurred = blurredValue; } QImage Photo::prepareImageCache(QSize outer) const { @@ -405,17 +450,23 @@ void Photo::paintUserpicFrame( const auto rect = QRect(photoPosition, size); const auto st = context.st; const auto sti = context.imageStyle(); + const auto forum = _parent->data()->history()->isForum(); if (_streamed && _streamed->instance.player().ready() && !_streamed->instance.player().videoSize().isEmpty()) { + const auto ratio = style::DevicePixelRatio(); auto request = ::Media::Streaming::FrameRequest(); - request.outer = size * cIntRetinaFactor(); - request.resize = size * cIntRetinaFactor(); - const auto forum = _parent->data()->history()->isForum(); + request.outer = request.resize = size * ratio; if (forum) { + const auto radius = int(std::min(size.width(), size.height()) + * Ui::ForumUserpicRadiusMultiplier() + * ratio); + if (_streamed->roundingCorners[0].width() != radius) { + _streamed->roundingCorners = Images::CornersMask(radius); + } request.rounding = Images::CornersMaskRef( - Images::CornersMask(ImageRoundRadius::Large)); + _streamed->roundingCorners); } else { if (_streamed->roundingMask.size() != request.outer) { _streamed->roundingMask = Images::EllipseMask(size); @@ -438,28 +489,8 @@ void Photo::paintUserpicFrame( } return; } - const auto pix = [&] { - const auto forum = _parent->data()->history()->isForum(); - const auto args = Images::PrepareArgs{ - .options = (forum - ? Images::Option::RoundLarge - : Images::Option::RoundCircle), - }; - if (const auto large = _dataMedia->image(PhotoSize::Large)) { - return large->pix(size, args); - } else if (const auto thumbnail = _dataMedia->image( - PhotoSize::Thumbnail)) { - return thumbnail->pix(size, args.blurred()); - } else if (const auto small = _dataMedia->image( - PhotoSize::Small)) { - return small->pix(size, args.blurred()); - } else if (const auto blurred = _dataMedia->thumbnailInline()) { - return blurred->pix(size, args.blurred()); - } else { - return QPixmap(); - } - }(); - p.drawPixmap(rect, pix); + validateUserpicImageCache(size, forum); + p.drawImage(rect, _imageCache); if (_data->videoCanBePlayed() && !_streamed) { const auto innerSize = st::msgFileLayout.thumbSize; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index c9aa130e9..c436e7f22 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -129,6 +129,7 @@ private: void validateImageCache( QSize outer, std::optional rounding) const; + void validateUserpicImageCache(QSize size, bool forum) const; [[nodiscard]] QImage prepareImageCache(QSize outer) const; bool videoAutoplayEnabled() const; @@ -150,8 +151,9 @@ private: mutable std::unique_ptr _streamed; mutable QImage _imageCache; mutable std::optional _imageCacheRounding; - int _serviceWidth = 0; - mutable bool _imageCacheBlurred = false; + int _serviceWidth : 30 = 0; + mutable int _imageCacheForum : 1 = 0; + mutable int _imageCacheBlurred : 1 = 0; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp index 184705564..b64aaeb14 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp @@ -181,6 +181,11 @@ struct Poll::CloseInformation { Ui::Animations::Basic radial; }; +struct Poll::RecentVoter { + not_null user; + mutable Ui::PeerUserpicView userpic; +}; + template Poll::SendingAnimation::SendingAnimation( const QByteArray &option, @@ -886,9 +891,9 @@ void Poll::paintRecentVoters( auto created = false; for (auto &recent : _recentVoters) { - const auto was = (recent.userpic != nullptr); + const auto was = !recent.userpic.null(); recent.user->paintUserpic(p, recent.userpic, x, y, size); - if (!was && recent.userpic) { + if (!was && !recent.userpic.null()) { created = true; } const auto paintContent = [&](QPainter &p) { @@ -1499,13 +1504,13 @@ void Poll::clickHandlerPressedChanged( void Poll::unloadHeavyPart() { for (auto &recent : _recentVoters) { - recent.userpic = nullptr; + recent.userpic = {}; } } bool Poll::hasHeavyPart() const { for (auto &recent : _recentVoters) { - if (recent.userpic) { + if (!recent.userpic.null()) { return true; } } diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.h b/Telegram/SourceFiles/history/view/media/history_view_poll.h index 08a79d1f2..d32ae664b 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.h +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.h @@ -12,10 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_poll.h" #include "base/weak_ptr.h" -namespace Data { -class CloudImageView; -} // namespace Data - namespace Ui { class RippleAnimation; class FireworksAnimation; @@ -75,11 +71,7 @@ private: struct SendingAnimation; struct Answer; struct CloseInformation; - - struct RecentVoter { - not_null user; - mutable std::shared_ptr userpic; - }; + struct RecentVoter; QSize countOptimalSize() override; QSize countCurrentSize(int newWidth) override; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index fb9816bf4..616f8741b 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -524,9 +524,9 @@ void InlineList::resolveUserpicsImage(const Button &button) const { for (auto &entry : userpics->list) { const auto peer = entry.peer; auto &view = entry.view; - const auto wasView = view.get(); + const auto wasView = view.cloud.get(); if (peer->userpicUniqueKey(view) != entry.uniqueKey - || view.get() != wasView) { + || view.cloud.get() != wasView) { return true; } } diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h index 88ac5d0ce..bc6a3c37c 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h @@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_message_reaction_id.h" namespace Data { -class CloudImageView; class Reactions; } // namespace Data diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index f13e0d0ca..2d77babdb 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -879,9 +879,17 @@ void Video::prepareThumbnail(QSize size) const { } } } + auto resultThumbnailImage = _documentMedia + ? nullptr + : getResultThumb(fileOrigin()); + const auto resultThumbnail = Image(resultThumbnailImage + ? base::duplicate(*resultThumbnailImage) + : QImage()); const auto thumb = _documentMedia ? _documentMedia->thumbnail() - : getResultThumb(fileOrigin()); + : resultThumbnailImage + ? &resultThumbnail + : nullptr; if (!thumb) { return; } @@ -1245,7 +1253,7 @@ void Contact::prepareThumbnail(int width, int height) const { w = width; } } - _thumb = thumb->pixNoCache( + _thumb = Image(base::duplicate(*thumb)).pixNoCache( QSize(w, h) * style::DevicePixelRatio(), { .options = Images::Option::TransparentBackground, @@ -1403,7 +1411,7 @@ void Article::prepareThumbnail(int width, int height) const { w = width; } } - _thumb = thumb->pixNoCache( + _thumb = Image(base::duplicate(*thumb)).pixNoCache( QSize(w, h) * style::DevicePixelRatio(), { .options = Images::Option::TransparentBackground, diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp index 2d5ba3c26..17eeeed0b 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp @@ -142,7 +142,7 @@ bool ItemBase::hasResultThumb() const { || !_result->_locationThumbnail.empty()); } -Image *ItemBase::getResultThumb(Data::FileOrigin origin) const { +QImage *ItemBase::getResultThumb(Data::FileOrigin origin) const { if (_result && !_thumbnail) { if (!_result->_thumbnail.empty()) { _thumbnail = _result->_thumbnail.createView(); @@ -152,7 +152,9 @@ Image *ItemBase::getResultThumb(Data::FileOrigin origin) const { _result->_locationThumbnail.load(_result->_session, origin); } } - return _thumbnail->image(); + return (_thumbnail && !_thumbnail->isNull()) + ? _thumbnail.get() + : nullptr; } QPixmap ItemBase::getResultContactAvatar(int width, int height) const { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h index d989bc91c..67574f7e0 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h @@ -16,10 +16,6 @@ namespace Ui { class PathShiftGradient; } // namespace Ui -namespace Data { -class CloudImageView; -} // namespace Data - namespace InlineBots { class Result; @@ -126,7 +122,7 @@ protected: DocumentData *getResultDocument() const; PhotoData *getResultPhoto() const; bool hasResultThumb() const; - Image *getResultThumb(Data::FileOrigin origin) const; + QImage *getResultThumb(Data::FileOrigin origin) const; QPixmap getResultContactAvatar(int width, int height) const; int getResultDuration() const; QString getResultUrl() const; @@ -148,7 +144,7 @@ protected: private: not_null _context; - mutable std::shared_ptr _thumbnail; + mutable std::shared_ptr _thumbnail; }; diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 3b95165bd..6cbb29714 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -110,8 +110,9 @@ Session::Session( _user, Data::PeerUpdate::Flag::Photo ) | rpl::start_with_next([=] { - [[maybe_unused]] const auto image = _user->currentUserpic( - _selfUserpicView); + auto view = Ui::PeerUserpicView{ .cloud = _selfUserpicView }; + [[maybe_unused]] const auto image = _user->userpicCloudImage(view); + _selfUserpicView = view.cloud; }, lifetime()); crl::on_main(this, [=] { diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 0f4d2f963..05dbb9ce5 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -32,7 +32,6 @@ class Templates; namespace Data { class Session; class Changes; -class CloudImageView; } // namespace Data namespace Storage { @@ -216,7 +215,7 @@ private: const std::unique_ptr _supportHelper; - std::shared_ptr _selfUserpicView; + std::shared_ptr _selfUserpicView; rpl::variable _premiumPossible = false; rpl::event_stream _termsLockChanges; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index b04066a7b..a2ad42ffd 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -2827,14 +2827,16 @@ void OverlayWidget::initStreamingThumbnail() { _touchbarDisplay.fire(TouchBarItemType::Video); + auto userpicImage = std::optional(); const auto computePhotoThumbnail = [&] { const auto thumbnail = _photoMedia->image(Data::PhotoSize::Thumbnail); if (thumbnail) { return thumbnail; } else if (_peer && _peer->userpicPhotoId() == _photo->id) { - if (const auto view = _peer->activeUserpicView()) { - if (const auto image = view->image()) { - return image; + if (const auto view = _peer->activeUserpicView(); view.cloud) { + if (!view.cloud->isNull()) { + userpicImage.emplace(base::duplicate(*view.cloud)); + return &*userpicImage; } } } @@ -3455,8 +3457,11 @@ void OverlayWidget::validatePhotoCurrentImage() { && !_message && _peer && _peer->hasUserpic()) { - if (const auto view = _peer->activeUserpicView()) { - validatePhotoImage(view->image(), true); + if (const auto view = _peer->activeUserpicView(); view.cloud) { + if (!view.cloud->isNull()) { + auto image = Image(base::duplicate(*view.cloud)); + validatePhotoImage(&image, true); + } } } if (_staticContent.isNull()) { diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index 8bb32c4b3..e6d87f32c 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "lang/lang_keys.h" #include "base/weak_ptr.h" +#include "window/notifications_utilities.h" #include "styles/style_window.h" #include @@ -906,7 +907,7 @@ public: void showNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -1013,7 +1014,7 @@ Manager::Private::Private(not_null manager) void Manager::Private::showNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -1041,12 +1042,8 @@ void Manager::Private::showNotification( } if (!options.hideNameAndPhoto) { - const auto userpic = peer->isSelf() - ? Ui::EmptyUserpic::GenerateSavedMessages(st::notifyMacPhotoSize) - : peer->isRepliesChat() - ? Ui::EmptyUserpic::GenerateRepliesMessages(st::notifyMacPhotoSize) - : peer->genUserpic(userpicView, st::notifyMacPhotoSize); - notification->setImage(userpic.toImage()); + notification->setImage( + Window::Notifications::GenerateUserpic(peer, userpicView)); } auto i = _notifications.find(key); @@ -1183,7 +1180,7 @@ Manager::~Manager() = default; void Manager::doShowNativeNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h index 98ab2b81c..de0c8cad8 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h @@ -22,7 +22,7 @@ protected: void doShowNativeNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h index 718adc1e0..7a5ed2f15 100644 --- a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h +++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h @@ -22,7 +22,7 @@ protected: void doShowNativeNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm index 1cb6a975c..1ab0de030 100644 --- a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm +++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/empty_userpic.h" #include "main/main_session.h" #include "mainwindow.h" +#include "window/notification_utilities.h" #include "styles/style_window.h" #include @@ -189,7 +190,7 @@ public: void showNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -265,7 +266,7 @@ Manager::Private::Private(Manager *manager) void Manager::Private::showNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -302,12 +303,8 @@ void Manager::Private::showNotification( [notification setInformativeText:Q2NSString(msg)]; if (!options.hideNameAndPhoto && [notification respondsToSelector:@selector(setContentImage:)]) { - auto userpic = peer->isSelf() - ? Ui::EmptyUserpic::GenerateSavedMessages(st::notifyMacPhotoSize) - : peer->isRepliesChat() - ? Ui::EmptyUserpic::GenerateRepliesMessages(st::notifyMacPhotoSize) - : peer->genUserpic(userpicView, st::notifyMacPhotoSize); - NSImage *img = Q2NSImage(userpic.toImage()); + NSImage *img = Q2NSImage( + Window::Notifications::GenerateUserpic(peer, userpicView)); [notification setContentImage:img]; } @@ -475,7 +472,7 @@ Manager::~Manager() = default; void Manager::doShowNativeNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, diff --git a/Telegram/SourceFiles/platform/mac/touchbar/items/mac_pinned_chats_item.mm b/Telegram/SourceFiles/platform/mac/touchbar/items/mac_pinned_chats_item.mm index c9978da16..916bf4f2f 100644 --- a/Telegram/SourceFiles/platform/mac/touchbar/items/mac_pinned_chats_item.mm +++ b/Telegram/SourceFiles/platform/mac/touchbar/items/mac_pinned_chats_item.mm @@ -84,7 +84,7 @@ QImage ArchiveUserpic(not_null folder) { auto result = PrepareImage(); Painter paint(&result); - auto view = std::shared_ptr(); + auto view = Ui::PeerUserpicView(); folder->paintUserpic(paint, 0, 0, result.width()); return result; } @@ -161,7 +161,7 @@ TimeId CalculateOnlineTill(not_null peer) { @implementation PinnedDialogsPanel { struct Pin { PeerData *peer = nullptr; - std::shared_ptr userpicView = nullptr; + Ui::PeerUserpicView userpicView; int index = -1; QImage userpic; QImage unreadBadge; diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp index a1f273da1..cd4da2862 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -405,15 +405,13 @@ void Create(Window::Notifications::System *system) { #ifndef __MINGW32__ class Manager::Private { public: - using Type = Window::Notifications::CachedUserpics::Type; - - explicit Private(Manager *instance, Type type); + explicit Private(Manager *instance); bool init(); bool showNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -438,7 +436,7 @@ private: bool showNotificationInTryCatch( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -460,9 +458,8 @@ private: }; -Manager::Private::Private(Manager *instance, Type type) -: _cachedUserpics(type) -, _guarded(std::make_shared(instance)) { +Manager::Private::Private(Manager *instance) +: _guarded(std::make_shared(instance)) { ToastActivations( ) | rpl::start_with_next([=](const ToastActivation &activation) { handleActivation(activation); @@ -657,7 +654,7 @@ void Manager::Private::handleActivation(const ToastActivation &activation) { bool Manager::Private::showNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -692,7 +689,7 @@ std::wstring Manager::Private::ensureSendButtonIcon() { bool Manager::Private::showNotificationInTryCatch( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -870,7 +867,7 @@ void Manager::Private::tryHide(const ToastNotification ¬ification) { Manager::Manager(Window::Notifications::System *system) : NativeManager(system) -, _private(std::make_unique(this, Private::Type::Rounded)) { +, _private(std::make_unique(this)) { } bool Manager::init() { @@ -890,7 +887,7 @@ Manager::~Manager() = default; void Manager::doShowNativeNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.h b/Telegram/SourceFiles/platform/win/notifications_manager_win.h index 0eaaa2e83..675597bc1 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.h +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.h @@ -30,7 +30,7 @@ protected: void doShowNativeNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, diff --git a/Telegram/SourceFiles/profile/profile_block_peer_list.h b/Telegram/SourceFiles/profile/profile_block_peer_list.h index 0ca1027ca..94e654496 100644 --- a/Telegram/SourceFiles/profile/profile_block_peer_list.h +++ b/Telegram/SourceFiles/profile/profile_block_peer_list.h @@ -8,10 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "profile/profile_block_widget.h" - -namespace Data { -class CloudImageView; -} // namespace Data +#include "ui/userpic_view.h" namespace Ui { class RippleAnimation; @@ -33,7 +30,7 @@ public: ~Item(); const not_null peer; - std::shared_ptr userpic; + Ui::PeerUserpicView userpic; Ui::Text::String name; QString statusText; bool statusHasOnlineColor = false; diff --git a/Telegram/SourceFiles/settings/settings_information.cpp b/Telegram/SourceFiles/settings/settings_information.cpp index e2ff0fd44..d6a44f4e1 100644 --- a/Telegram/SourceFiles/settings/settings_information.cpp +++ b/Telegram/SourceFiles/settings/settings_information.cpp @@ -644,7 +644,7 @@ void SetupAccountsWrap( } Ui::RpWidget userpic; - std::shared_ptr view; + Ui::PeerUserpicView view; base::unique_qptr menu; }; const auto state = raw->lifetime().make_state(raw); diff --git a/Telegram/SourceFiles/ui/effects/round_checkbox.cpp b/Telegram/SourceFiles/ui/effects/round_checkbox.cpp index f4d13a65d..3677a620f 100644 --- a/Telegram/SourceFiles/ui/effects/round_checkbox.cpp +++ b/Telegram/SourceFiles/ui/effects/round_checkbox.cpp @@ -360,7 +360,7 @@ RoundImageCheckbox::RoundImageCheckbox( const style::RoundImageCheckbox &st, Fn updateCallback, PaintRoundImage &&paintRoundImage, - Fn roundingRadius) + Fn(int size)> roundingRadius) : _st(st) , _updateCallback(updateCallback) , _paintRoundImage(std::move(paintRoundImage)) @@ -390,8 +390,8 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) const { if (selectionLevel > 0) { const auto radius = _roundingRadius - ? _roundingRadius() - : ImageRoundRadius::Ellipse; + ? _roundingRadius(_st.imageRadius) + : std::optional(); PainterHighQualityEnabler hq(p); p.setOpacity(std::clamp(selectionLevel, 0., 1.)); p.setBrush(Qt::NoBrush); @@ -405,11 +405,10 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) const { _st.imageRadius * 2, _st.imageRadius * 2, outerWidth); - if (radius == ImageRoundRadius::Ellipse) { + if (!radius) { p.drawEllipse(rect); } else { - const auto pxRadius = st::roundRadiusLarge; - p.drawRoundedRect(rect, pxRadius, pxRadius); + p.drawRoundedRect(rect, *radius, *radius); } p.setOpacity(1.); } diff --git a/Telegram/SourceFiles/ui/effects/round_checkbox.h b/Telegram/SourceFiles/ui/effects/round_checkbox.h index b7a788389..461244f95 100644 --- a/Telegram/SourceFiles/ui/effects/round_checkbox.h +++ b/Telegram/SourceFiles/ui/effects/round_checkbox.h @@ -52,7 +52,7 @@ public: const style::RoundImageCheckbox &st, Fn updateCallback, PaintRoundImage &&paintRoundImage, - Fn roundingRadius = nullptr); + Fn(int size)> roundingRadius = nullptr); void paint(Painter &p, int x, int y, int outerWidth) const; float64 checkedAnimationRatio() const; @@ -76,7 +76,7 @@ private: const style::RoundImageCheckbox &_st; Fn _updateCallback; PaintRoundImage _paintRoundImage; - Fn _roundingRadius; + Fn(int size)> _roundingRadius; QPixmap _wideCache; Ui::Animations::Simple _selection; diff --git a/Telegram/SourceFiles/ui/empty_userpic.cpp b/Telegram/SourceFiles/ui/empty_userpic.cpp index 143f11e7b..594fe6707 100644 --- a/Telegram/SourceFiles/ui/empty_userpic.cpp +++ b/Telegram/SourceFiles/ui/empty_userpic.cpp @@ -193,7 +193,7 @@ void PaintInaccessibleAccountInner( } } -[[nodiscard]] QPixmap Generate(int size, Fn callback) { +[[nodiscard]] QImage Generate(int size, Fn callback) { auto result = QImage( QSize(size, size) * style::DevicePixelRatio(), QImage::Format_ARGB32_Premultiplied); @@ -203,7 +203,7 @@ void PaintInaccessibleAccountInner( Painter p(&result); callback(p); } - return Ui::PixmapFromImage(std::move(result)); + return result; } } // namespace @@ -286,7 +286,7 @@ void EmptyUserpic::paint( } } -void EmptyUserpic::paint( +void EmptyUserpic::paintCircle( QPainter &p, int x, int y, @@ -304,9 +304,6 @@ void EmptyUserpic::paintRounded( int outerWidth, int size, int radius) const { - if (!radius) { - radius = st::roundRadiusSmall; - } paint(p, x, y, outerWidth, size, [&] { p.drawRoundedRect(x, y, size, size, radius, radius); }); @@ -338,21 +335,6 @@ void EmptyUserpic::PaintSavedMessages( PaintSavedMessages(p, x, y, outerWidth, size, QBrush(bg), fg); } -void EmptyUserpic::PaintSavedMessagesRounded( - QPainter &p, - int x, - int y, - int outerWidth, - int size) { - auto bg = QLinearGradient(x, y, x, y + size); - bg.setStops({ - { 0., st::historyPeerSavedMessagesBg->c }, - { 1., st::historyPeerSavedMessagesBg2->c } - }); - const auto &fg = st::historyPeerUserpicFg; - PaintSavedMessagesRounded(p, x, y, outerWidth, size, QBrush(bg), fg); -} - void EmptyUserpic::PaintSavedMessages( QPainter &p, int x, @@ -371,42 +353,12 @@ void EmptyUserpic::PaintSavedMessages( PaintSavedMessagesInner(p, x, y, size, fg); } -void EmptyUserpic::PaintSavedMessagesRounded( - QPainter &p, - int x, - int y, - int outerWidth, - int size, - QBrush bg, - const style::color &fg) { - x = style::RightToLeft() ? (outerWidth - x - size) : x; - - PainterHighQualityEnabler hq(p); - p.setBrush(std::move(bg)); - p.setPen(Qt::NoPen); - p.drawRoundedRect( - x, - y, - size, - size, - st::roundRadiusSmall, - st::roundRadiusSmall); - - PaintSavedMessagesInner(p, x, y, size, fg); -} - -QPixmap EmptyUserpic::GenerateSavedMessages(int size) { +QImage EmptyUserpic::GenerateSavedMessages(int size) { return Generate(size, [&](QPainter &p) { PaintSavedMessages(p, 0, 0, size, size); }); } -QPixmap EmptyUserpic::GenerateSavedMessagesRounded(int size) { - return Generate(size, [&](QPainter &p) { - PaintSavedMessagesRounded(p, 0, 0, size, size); - }); -} - void EmptyUserpic::PaintRepliesMessages( QPainter &p, int x, @@ -422,21 +374,6 @@ void EmptyUserpic::PaintRepliesMessages( PaintRepliesMessages(p, x, y, outerWidth, size, QBrush(bg), fg); } -void EmptyUserpic::PaintRepliesMessagesRounded( - QPainter &p, - int x, - int y, - int outerWidth, - int size) { - auto bg = QLinearGradient(x, y, x, y + size); - bg.setStops({ - { 0., st::historyPeerSavedMessagesBg->c }, - { 1., st::historyPeerSavedMessagesBg2->c } - }); - const auto &fg = st::historyPeerUserpicFg; - PaintRepliesMessagesRounded(p, x, y, outerWidth, size, QBrush(bg), fg); -} - void EmptyUserpic::PaintRepliesMessages( QPainter &p, int x, @@ -455,42 +392,12 @@ void EmptyUserpic::PaintRepliesMessages( PaintRepliesMessagesInner(p, x, y, size, fg); } -void EmptyUserpic::PaintRepliesMessagesRounded( - QPainter &p, - int x, - int y, - int outerWidth, - int size, - QBrush bg, - const style::color &fg) { - x = style::RightToLeft() ? (outerWidth - x - size) : x; - - PainterHighQualityEnabler hq(p); - p.setBrush(bg); - p.setPen(Qt::NoPen); - p.drawRoundedRect( - x, - y, - size, - size, - st::roundRadiusSmall, - st::roundRadiusSmall); - - PaintRepliesMessagesInner(p, x, y, size, fg); -} - -QPixmap EmptyUserpic::GenerateRepliesMessages(int size) { +QImage EmptyUserpic::GenerateRepliesMessages(int size) { return Generate(size, [&](QPainter &p) { PaintRepliesMessages(p, 0, 0, size, size); }); } -QPixmap EmptyUserpic::GenerateRepliesMessagesRounded(int size) { - return Generate(size, [&](QPainter &p) { - PaintRepliesMessagesRounded(p, 0, 0, size, size); - }); -} - std::pair EmptyUserpic::uniqueKey() const { const auto first = (uint64(0xFFFFFFFFU) << 32) | anim::getPremultiplied(_colors.color1->c); @@ -510,7 +417,7 @@ QPixmap EmptyUserpic::generate(int size) { result.fill(Qt::transparent); { auto p = QPainter(&result); - paint(p, 0, 0, size, size); + paintCircle(p, 0, 0, size, size); } return Ui::PixmapFromImage(std::move(result)); } diff --git a/Telegram/SourceFiles/ui/empty_userpic.h b/Telegram/SourceFiles/ui/empty_userpic.h index 01539329c..2f9b9856b 100644 --- a/Telegram/SourceFiles/ui/empty_userpic.h +++ b/Telegram/SourceFiles/ui/empty_userpic.h @@ -7,9 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/weak_ptr.h" + namespace Ui { -class EmptyUserpic { +class EmptyUserpic final : public base::has_weak_ptr { public: struct BgColors { const style::color color1; @@ -24,7 +26,7 @@ public: EmptyUserpic(const BgColors &colors, const QString &name); - void paint( + void paintCircle( QPainter &p, int x, int y, @@ -52,12 +54,6 @@ public: int y, int outerWidth, int size); - static void PaintSavedMessagesRounded( - QPainter &p, - int x, - int y, - int outerWidth, - int size); static void PaintSavedMessages( QPainter &p, int x, @@ -66,16 +62,7 @@ public: int size, QBrush bg, const style::color &fg); - static void PaintSavedMessagesRounded( - QPainter &p, - int x, - int y, - int outerWidth, - int size, - QBrush bg, - const style::color &fg); - [[nodiscard]] static QPixmap GenerateSavedMessages(int size); - [[nodiscard]] static QPixmap GenerateSavedMessagesRounded(int size); + [[nodiscard]] static QImage GenerateSavedMessages(int size); static void PaintRepliesMessages( QPainter &p, @@ -83,12 +70,6 @@ public: int y, int outerWidth, int size); - static void PaintRepliesMessagesRounded( - QPainter &p, - int x, - int y, - int outerWidth, - int size); static void PaintRepliesMessages( QPainter &p, int x, @@ -97,16 +78,7 @@ public: int size, QBrush bg, const style::color &fg); - static void PaintRepliesMessagesRounded( - QPainter &p, - int x, - int y, - int outerWidth, - int size, - QBrush bg, - const style::color &fg); - [[nodiscard]] static QPixmap GenerateRepliesMessages(int size); - [[nodiscard]] static QPixmap GenerateRepliesMessagesRounded(int size); + [[nodiscard]] static QImage GenerateRepliesMessages(int size); ~EmptyUserpic(); diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp index 6b199630d..610c2ba27 100644 --- a/Telegram/SourceFiles/ui/special_buttons.cpp +++ b/Telegram/SourceFiles/ui/special_buttons.cpp @@ -354,7 +354,7 @@ void UserpicButton::setupPeerViewers() { ) | rpl::filter([=] { return _waiting; }) | rpl::start_with_next([=] { - if (!_userpicView || _userpicView->image()) { + if (!Ui::PeerUserpicLoading(_userpicView)) { _waiting = false; startNewPhotoShowing(); } @@ -473,12 +473,17 @@ void UserpicButton::paintUserpicFrame(Painter &p, QPoint photoPosition) { : false; auto request = Media::Streaming::FrameRequest(); auto size = QSize{ _st.photoSize, _st.photoSize }; - request.outer = size * cIntRetinaFactor(); - request.resize = size * cIntRetinaFactor(); + const auto ratio = style::DevicePixelRatio(); + request.outer = request.resize = size * ratio; const auto forum = _peer && _peer->isForum(); if (forum) { - request.rounding = Images::CornersMaskRef( - Images::CornersMask(ImageRoundRadius::Large)); + const auto radius = int(_st.photoSize + * Ui::ForumUserpicRadiusMultiplier() + * ratio); + if (_roundingCorners[0].width() != radius) { + _roundingCorners = Images::CornersMask(radius); + } + request.rounding = Images::CornersMaskRef(_roundingCorners); } else { if (_ellipseMask.size() != request.outer) { _ellipseMask = Images::EllipseMask(size); @@ -520,7 +525,7 @@ void UserpicButton::processPeerPhoto() { Expects(_peer != nullptr); _userpicView = _peer->createUserpicView(); - _waiting = _userpicView && !_userpicView->image(); + _waiting = Ui::PeerUserpicLoading(_userpicView); if (_waiting) { _peer->loadUserpic(); } @@ -798,7 +803,7 @@ void UserpicButton::fillShape(QPainter &p, const style::color &color) const { p.setBrush(color); const auto size = _st.photoSize; if (_peer && _peer->isForum()) { - const auto radius = st::roundRadiusLarge; + const auto radius = size * Ui::ForumUserpicRadiusMultiplier(); p.drawRoundedRect(0, 0, size, size, radius, radius); } else { p.drawEllipse(0, 0, size, size); @@ -811,8 +816,8 @@ void UserpicButton::prepareUserpicPixmap() { } auto size = _st.photoSize; _userpicHasImage = _peer - ? (_peer->currentUserpic(_userpicView) || _role != Role::ChangePhoto) - : false; + && (_peer->userpicCloudImage(_userpicView) + || _role != Role::ChangePhoto); _userpic = CreateSquarePixmap(size, [&](Painter &p) { if (_userpicHasImage) { _peer->paintUserpic(p, _userpicView, 0, 0, _st.photoSize); diff --git a/Telegram/SourceFiles/ui/special_buttons.h b/Telegram/SourceFiles/ui/special_buttons.h index a103f8ba2..4a9d95377 100644 --- a/Telegram/SourceFiles/ui/special_buttons.h +++ b/Telegram/SourceFiles/ui/special_buttons.h @@ -11,15 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/tooltip.h" #include "ui/effects/animations.h" #include "ui/effects/cross_line.h" +#include "ui/userpic_view.h" #include "styles/style_window.h" #include "styles/style_widgets.h" class PeerData; -namespace Data { -class CloudImageView; -} // namespace Data - namespace Window { class Controller; class SessionController; @@ -159,7 +156,7 @@ private: ::Window::SessionController *_controller = nullptr; ::Window::Controller *_window = nullptr; PeerData *_peer = nullptr; - std::shared_ptr _userpicView; + PeerUserpicView _userpicView; QString _cropTitle; Role _role = Role::ChangePhoto; bool _notShownYet = true; @@ -169,28 +166,29 @@ private: bool _userpicCustom = false; bool _requestToUpload = false; InMemoryKey _userpicUniqueKey; - Ui::Animations::Simple _a_appearance; + Animations::Simple _a_appearance; QImage _result; QImage _ellipseMask; + std::array _roundingCorners; std::unique_ptr _streamed; PhotoData *_streamedPhoto = nullptr; - base::unique_qptr _menu; + base::unique_qptr _menu; bool _showSavedMessagesOnSelf = false; bool _canOpenPhoto = false; bool _cursorInChangeOverlay = false; bool _changeOverlayEnabled = false; - Ui::Animations::Simple _changeOverlayShown; + Animations::Simple _changeOverlayShown; rpl::event_stream _chosenImages; rpl::event_stream<> _uploadPhotoRequests; }; -class SilentToggle - : public Ui::RippleButton - , public Ui::AbstractTooltipShower { +class SilentToggle final + : public RippleButton + , public AbstractTooltipShower { public: SilentToggle(QWidget *parent, not_null channel); @@ -218,7 +216,7 @@ private: not_null _channel; bool _checked = false; - Ui::Animations::Simple _crossLineAnimation; + Animations::Simple _crossLineAnimation; }; diff --git a/Telegram/SourceFiles/ui/userpic_view.cpp b/Telegram/SourceFiles/ui/userpic_view.cpp new file mode 100644 index 000000000..0e4ef3d13 --- /dev/null +++ b/Telegram/SourceFiles/ui/userpic_view.cpp @@ -0,0 +1,80 @@ +/* +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 "ui/userpic_view.h" + +#include "ui/empty_userpic.h" +#include "ui/image/image_prepare.h" + +namespace Ui { + +float64 ForumUserpicRadiusMultiplier() { + return 0.3; +} + +bool PeerUserpicLoading(const PeerUserpicView &view) { + return view.cloud && view.cloud->isNull(); +} + +void ValidateUserpicCache( + PeerUserpicView &view, + const QImage *cloud, + const EmptyUserpic *empty, + int size, + bool forum) { + Expects(cloud != nullptr || empty != nullptr); + + const auto full = QSize(size, size); + const auto version = style::PaletteVersion(); + const auto forumValue = forum ? 1 : 0; + const auto regenerate = (view.cached.size() != QSize(size, size)) + || (view.forum != forumValue) + || (cloud && !view.empty.null()) + || (empty && empty != view.empty.get()) + || (empty && view.paletteVersion != version); + if (!regenerate) { + return; + } + view.empty = empty; + view.forum = forumValue; + view.paletteVersion = version; + + if (cloud) { + view.cached = cloud->scaled( + full, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + if (forum) { + view.cached = Images::Round( + std::move(view.cached), + Images::CornersMask( + size * Ui::ForumUserpicRadiusMultiplier())); + } else { + view.cached = Images::Circle(std::move(view.cached)); + } + } else { + if (view.cached.size() != full) { + view.cached = QImage(full, QImage::Format_ARGB32_Premultiplied); + } + view.cached.fill(Qt::transparent); + + auto p = QPainter(&view.cached); + if (forum) { + empty->paintRounded( + p, + 0, + 0, + size, + size, + size * Ui::ForumUserpicRadiusMultiplier()); + } else { + empty->paintCircle(p, 0, 0, size, size); + } + } +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/userpic_view.h b/Telegram/SourceFiles/ui/userpic_view.h new file mode 100644 index 000000000..e05162f95 --- /dev/null +++ b/Telegram/SourceFiles/ui/userpic_view.h @@ -0,0 +1,41 @@ +/* +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 "base/weak_ptr.h" + +#include + +namespace Ui { + +class EmptyUserpic; + +[[nodiscard]] float64 ForumUserpicRadiusMultiplier(); + +struct PeerUserpicView { + [[nodiscard]] bool null() const { + return cached.isNull() && !cloud && empty.null(); + } + + QImage cached; + std::shared_ptr cloud; + base::weak_ptr empty; + int paletteVersion : 31 = 0; + int forum : 1 = 0; +}; + +[[nodiscard]] bool PeerUserpicLoading(const PeerUserpicView &view); + +void ValidateUserpicCache( + PeerUserpicView &view, + const QImage *cloud, + const EmptyUserpic *empty, + int size, + bool forum); + +} // namespace Ui diff --git a/Telegram/SourceFiles/window/notifications_manager.h b/Telegram/SourceFiles/window/notifications_manager.h index 57401671c..c33048fcd 100644 --- a/Telegram/SourceFiles/window/notifications_manager.h +++ b/Telegram/SourceFiles/window/notifications_manager.h @@ -15,13 +15,16 @@ class History; namespace Data { class Session; -class CloudImageView; class ForumTopic; class Thread; struct ItemNotification; enum class ItemNotificationType; } // namespace Data +namespace Ui { +struct PeerUserpicView; +} // namespace Ui + namespace Main { class Session; } // namespace Main @@ -392,7 +395,7 @@ protected: virtual void doShowNativeNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, @@ -413,7 +416,7 @@ protected: void doShowNativeNotification( not_null peer, MsgId topicRootId, - std::shared_ptr &userpicView, + Ui::PeerUserpicView &userpicView, MsgId msgId, const QString &title, const QString &subtitle, diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index 67f03b7c3..3f78b9b7a 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -660,7 +660,7 @@ Notification::Notification( auto position = computePosition(st::notifyMinHeight); updateGeometry(position.x(), position.y(), st::notifyWidth, st::notifyMinHeight); - _userpicLoaded = !_userpicView || (_userpicView->image() != nullptr); + _userpicLoaded = !Ui::PeerUserpicLoading(_userpicView); updateNotifyDisplay(); _hideTimer.setSingleShot(true); @@ -1004,7 +1004,7 @@ void Notification::updatePeerPhoto() { return; } _userpicView = _peer->createUserpicView(); - if (_userpicView && !_userpicView->image()) { + if (Ui::PeerUserpicLoading(_userpicView)) { return; } _userpicLoaded = true; @@ -1024,7 +1024,7 @@ void Notification::updatePeerPhoto() { st::notifyPhotoPos.y(), width(), st::notifyPhotoSize); - _userpicView = nullptr; + _userpicView = {}; update(); } diff --git a/Telegram/SourceFiles/window/notifications_manager_default.h b/Telegram/SourceFiles/window/notifications_manager_default.h index 773694f81..ac8b19bda 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.h +++ b/Telegram/SourceFiles/window/notifications_manager_default.h @@ -11,16 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/animations.h" #include "ui/text/text.h" #include "ui/rp_widget.h" +#include "ui/userpic_view.h" #include "base/timer.h" #include "base/binary_guard.h" #include "base/object_ptr.h" #include -namespace Data { -class CloudImageView; -} // namespace Data - namespace Ui { class IconButton; class RoundButton; @@ -290,7 +287,7 @@ private: History *_history = nullptr; Data::ForumTopic *_topic = nullptr; MsgId _topicRootId = 0; - std::shared_ptr _userpicView; + Ui::PeerUserpicView _userpicView; QString _author; Data::ReactionId _reaction; HistoryItem *_item = nullptr; diff --git a/Telegram/SourceFiles/window/notifications_utilities.cpp b/Telegram/SourceFiles/window/notifications_utilities.cpp index 8167f2d4b..418848c05 100644 --- a/Telegram/SourceFiles/window/notifications_utilities.cpp +++ b/Telegram/SourceFiles/window/notifications_utilities.cpp @@ -15,8 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/empty_userpic.h" #include "styles/style_window.h" -namespace Window { -namespace Notifications { +namespace Window::Notifications { namespace { // Delete notify photo file after 1 minute of not using. @@ -24,9 +23,16 @@ constexpr int kNotifyDeletePhotoAfterMs = 60000; } // namespace -CachedUserpics::CachedUserpics(Type type) -: _type(type) -, _clearTimer([=] { clear(); }) { +QImage GenerateUserpic(not_null peer, Ui::PeerUserpicView &view) { + return peer->isSelf() + ? Ui::EmptyUserpic::GenerateSavedMessages(st::notifyMacPhotoSize) + : peer->isRepliesChat() + ? Ui::EmptyUserpic::GenerateRepliesMessages(st::notifyMacPhotoSize) + : peer->generateUserpicImage(view, st::notifyMacPhotoSize); +} + +CachedUserpics::CachedUserpics() +: _clearTimer([=] { clear(); }) { QDir().mkpath(cWorkingDir() + u"tdata/temp"_q); } @@ -37,14 +43,14 @@ CachedUserpics::~CachedUserpics() { } // This works about 1200ms on Windows for a folder with one image O_o - // base::Platform::DeleteDirectory(cWorkingDir() + u"tdata/temp"_q); + //base::Platform::DeleteDirectory(cWorkingDir() + u"tdata/temp"_q); } } QString CachedUserpics::get( const InMemoryKey &key, not_null peer, - std::shared_ptr &view) { + Ui::PeerUserpicView &view) { auto ms = crl::now(); auto i = _images.find(key); if (i != _images.cend()) { @@ -64,21 +70,7 @@ QString CachedUserpics::get( cWorkingDir(), QString::number(base::RandomValue(), 16)); if (key.first || key.second) { - if (peer->isSelf()) { - const auto method = (_type == Type::Rounded) - ? Ui::EmptyUserpic::GenerateSavedMessagesRounded - : Ui::EmptyUserpic::GenerateSavedMessages; - method(st::notifyMacPhotoSize).save(v.path, "PNG"); - } else if (peer->isRepliesChat()) { - const auto method = (_type == Type::Rounded) - ? Ui::EmptyUserpic::GenerateRepliesMessagesRounded - : Ui::EmptyUserpic::GenerateRepliesMessages; - method(st::notifyMacPhotoSize).save(v.path, "PNG"); - } else if (_type == Type::Rounded) { - peer->saveUserpicRounded(view, v.path, st::notifyMacPhotoSize); - } else { - peer->saveUserpic(view, v.path, st::notifyMacPhotoSize); - } + GenerateUserpic(peer, view).save(v.path, "PNG"); } else { LogoNoMargin().save(v.path, "PNG"); } @@ -128,5 +120,4 @@ void CachedUserpics::clear() { } } -} // namespace Notifications -} // namespace Window +} // namespace Window::Notifications diff --git a/Telegram/SourceFiles/window/notifications_utilities.h b/Telegram/SourceFiles/window/notifications_utilities.h index 321504939..81b45f036 100644 --- a/Telegram/SourceFiles/window/notifications_utilities.h +++ b/Telegram/SourceFiles/window/notifications_utilities.h @@ -10,34 +10,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/notifications_manager.h" #include "base/timer.h" -namespace Data { -class CloudImageView; -} // namespace Data +namespace Ui { +struct PeerUserpicView; +} // namespace Ui -namespace Window { -namespace Notifications { +namespace Window::Notifications { + +[[nodiscard]] QImage GenerateUserpic( + not_null peer, + Ui::PeerUserpicView &view); class CachedUserpics : public QObject { public: - enum class Type { - Rounded, - Circled, - }; - - CachedUserpics(Type type); + CachedUserpics(); ~CachedUserpics(); [[nodiscard]] QString get( const InMemoryKey &key, not_null peer, - std::shared_ptr &view); + Ui::PeerUserpicView &view); private: void clear(); void clearInMs(int ms); crl::time clear(crl::time ms); - Type _type = Type::Rounded; struct Image { crl::time until = 0; QString path; @@ -49,5 +46,4 @@ private: }; -} // namesapce Notifications -} // namespace Window +} // namespace Window::Notifications diff --git a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp index c256c1bfc..f30c88d8f 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp @@ -982,7 +982,7 @@ void Generator::paintUserpic(int x, int y, Row::Type type, int index, QString le image.fill(Qt::transparent); { Painter p(&image); - userpic.paintRounded(p, 0, 0, size, size, size / 2); + userpic.paintCircle(p, 0, 0, size, size); } _p->drawImage(rtl() ? (_rect.width() - x - size) : x, y, image); } diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 1d3717bf4..113f7755e 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -278,6 +278,8 @@ PRIVATE ui/empty_userpic.h ui/grouped_layout.cpp ui/grouped_layout.h + ui/userpic_view.cpp + ui/userpic_view.h ui/widgets/fields/special_fields.cpp ui/widgets/fields/special_fields.h ui/widgets/fields/time_part_input_with_placeholder.cpp diff --git a/Telegram/lib_base b/Telegram/lib_base index e8294bbc9..fd3531b70 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit e8294bbc9c7f85e6909c3ed06fe03cfd39869613 +Subproject commit fd3531b70750ffe7ec2213a899409c08c388ce4c diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 22ceaae4e..59a7b94ef 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 22ceaae4ed958d9711965fbe4c1385a7d8c60212 +Subproject commit 59a7b94ef4bb4d4cf6597d53bdacccbf5720e694