From d6ba6ac41edbd859b1d0cb3b773acfd65d9acca8 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 28 Jan 2025 18:26:47 +0300 Subject: [PATCH] Added initial ability to open single typed shared media in window. --- .../SourceFiles/info/info_wrap_widget.cpp | 5 +- Telegram/SourceFiles/info/info_wrap_widget.h | 2 + .../info/media/info_media_buttons.h | 5 +- .../profile/info_profile_inner_widget.cpp | 75 +++++++++++++++++++ Telegram/SourceFiles/window/window.style | 2 + .../SourceFiles/window/window_separate_id.cpp | 13 ++++ .../SourceFiles/window/window_separate_id.h | 16 ++++ .../window/window_session_controller.cpp | 27 +++++++ 8 files changed, 143 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index dbef00afb..212e541f4 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -106,6 +106,8 @@ WrapWidget::WrapWidget( Wrap wrap, not_null memento) : SectionWidget(parent, window, rpl::producer()) +, _isSeparatedWindow( + window->windowId().type == Window::SeparateType::SharedMedia) , _wrap(wrap) , _controller(createController(window, memento->content())) , _topShadow(this) @@ -1044,7 +1046,8 @@ const Ui::RoundRect *WrapWidget::bottomSkipRounding() const { } bool WrapWidget::hasBackButton() const { - return (wrap() == Wrap::Narrow || hasStackHistory()); + return !_isSeparatedWindow + && (wrap() == Wrap::Narrow || hasStackHistory()); } bool WrapWidget::willHaveBackButton( diff --git a/Telegram/SourceFiles/info/info_wrap_widget.h b/Telegram/SourceFiles/info/info_wrap_widget.h index 0ece881a0..815765154 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.h +++ b/Telegram/SourceFiles/info/info_wrap_widget.h @@ -208,6 +208,8 @@ private: void addProfileCallsButton(); void showTopBarMenu(bool check); + const bool _isSeparatedWindow = false; + rpl::variable _wrap; std::unique_ptr _controller; object_ptr _content = { nullptr }; diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.h b/Telegram/SourceFiles/info/media/info_media_buttons.h index 4efdb15f9..363a27953 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.h +++ b/Telegram/SourceFiles/info/media/info_media_buttons.h @@ -96,7 +96,10 @@ inline auto AddButton( Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), MediaText(type), tracker)->entity(); - result->addClickHandler([=] { + result->addClickHandler([=](Qt::MouseButton mouse) { + if (mouse == Qt::RightButton) { + return; + } const auto topic = topicRootId ? peer->forumTopicFor(topicRootId) : nullptr; diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 4e9108fc3..8d8a6b599 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/profile/info_profile_inner_widget.h" +#include "base/call_delayed.h" #include "info/info_memento.h" #include "info/info_controller.h" #include "info/profile/info_profile_widget.h" @@ -29,11 +30,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "api/api_peer_photo.h" #include "window/main_window.h" +#include "window/window_separate_id.h" #include "window/window_session_controller.h" #include "storage/storage_shared_media.h" #include "lang/lang_keys.h" #include "ui/widgets/buttons.h" #include "ui/widgets/checkbox.h" +#include "ui/widgets/popup_menu.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/widgets/box_content_divider.h" @@ -44,10 +47,79 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_shared_media.h" #include "styles/style_info.h" #include "styles/style_boxes.h" +#include "styles/style_menu_icons.h" namespace Info { namespace Profile { +namespace { + +Window::SeparateSharedMediaType ToSeparateType( + Storage::SharedMediaType type) { + using Type = Storage::SharedMediaType; + using SeparatedType = Window::SeparateSharedMediaType; + return (type == Type::Photo) + ? SeparatedType::Photos + : (type == Type::Video) + ? SeparatedType::Videos + : (type == Type::File) + ? SeparatedType::Files + : (type == Type::MusicFile) + ? SeparatedType::Audio + : (type == Type::Link) + ? SeparatedType::Links + : (type == Type::RoundVoiceFile) + ? SeparatedType::Voices + : (type == Type::GIF) + ? SeparatedType::GIF + : SeparatedType::None; +} + +Fn SeparateWindowFactory( + not_null controller, + not_null peer, + Storage::SharedMediaType type) { + const auto separateType = ToSeparateType(type); + if (separateType == Window::SeparateSharedMediaType::None) { + return nullptr; + } + return [=] { + controller->showInNewWindow(Window::SeparateId(separateType, peer)); + }; +} + +void AddContextMenu( + not_null button, + not_null controller, + not_null peer, + Storage::SharedMediaType type) { + const auto callback = SeparateWindowFactory(controller, peer, type); + if (!callback) { + return; + } + button->setAcceptBoth(); + struct State final { + base::unique_qptr menu; + }; + const auto state = button->lifetime().make_state(); + button->addClickHandler([=](Qt::MouseButton mouse) { + if (mouse != Qt::RightButton) { + return; + } + state->menu = base::make_unique_q( + button.get(), + st::popupMenuWithIcons); + state->menu->addAction(tr::lng_context_new_window(tr::now), [=] { + base::call_delayed( + st::popupMenuWithIcons.showDuration, + crl::guard(button, callback)); + }, &st::menuIconNewWindow); + state->menu->popup(QCursor::pos()); + }); +} + +} // namespace + InnerWidget::InnerWidget( QWidget *parent, not_null controller, @@ -160,6 +232,9 @@ object_ptr InnerWidget::setupSharedMedia( _migrated, type, tracker); + if (const auto window = _controller->parentController(); !_topic) { + AddContextMenu(result, window, _peer, type); + } object_ptr( result, icon, diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index 30026da2c..acdda3129 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -321,6 +321,8 @@ ivHeightMin: 480px; ivWidthDefault: 600px; ivHeightDefault: 800px; +maxWidthSharedMediaWindow: 419px; + // Windows specific winQuitIcon: icon {{ "win_quit", windowFg }}; diff --git a/Telegram/SourceFiles/window/window_separate_id.cpp b/Telegram/SourceFiles/window/window_separate_id.cpp index f2ed89183..f46d4bce4 100644 --- a/Telegram/SourceFiles/window/window_separate_id.cpp +++ b/Telegram/SourceFiles/window/window_separate_id.cpp @@ -44,6 +44,13 @@ SeparateId::SeparateId(not_null peer) : SeparateId(SeparateType::Chat, peer->owner().history(peer)) { } +SeparateId::SeparateId(SeparateSharedMediaType type, not_null peer) +: type(SeparateType::SharedMedia) +, sharedMedia(type) +, account(&peer->session().account()) +, sharedMediaLocalPeer(peer) { +} + bool SeparateId::primary() const { return (type == SeparateType::Primary); } @@ -74,4 +81,10 @@ bool SeparateId::hasChatsList() const { || (type == SeparateType::Forum); } +PeerData *SeparateId::sharedMediaPeer() const { + return (type == SeparateType::SharedMedia) + ? sharedMediaLocalPeer + : nullptr; +} + } // namespace Window diff --git a/Telegram/SourceFiles/window/window_separate_id.h b/Telegram/SourceFiles/window/window_separate_id.h index bcbe72860..e031e5400 100644 --- a/Telegram/SourceFiles/window/window_separate_id.h +++ b/Telegram/SourceFiles/window/window_separate_id.h @@ -29,6 +29,18 @@ enum class SeparateType { Chat, Forum, SavedSublist, + SharedMedia, +}; + +enum class SeparateSharedMediaType { + None, + Photos, + Videos, + Files, + Audio, + Links, + Voices, + GIF, }; struct SeparateId { @@ -38,10 +50,13 @@ struct SeparateId { SeparateId(SeparateType type, not_null thread); SeparateId(not_null thread); SeparateId(not_null peer); + SeparateId(SeparateSharedMediaType type, not_null peer); SeparateType type = SeparateType::Primary; + SeparateSharedMediaType sharedMedia = SeparateSharedMediaType::None; Main::Account *account = nullptr; Data::Thread *thread = nullptr; // For types except Main and Archive. + PeerData *sharedMediaLocalPeer = nullptr; [[nodiscard]] bool valid() const { return account != nullptr; @@ -55,6 +70,7 @@ struct SeparateId { [[nodiscard]] Data::Forum *forum() const; [[nodiscard]] Data::Folder *folder() const; [[nodiscard]] Data::SavedSublist *sublist() const; + [[nodiscard]] PeerData *sharedMediaPeer() const; [[nodiscard]] bool hasChatsList() const; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 559b60f00..6a82b2b49 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1189,6 +1189,30 @@ void SessionNavigation::showByInitialId( case SeparateType::Chat: showThread(id.thread, msgId, instant); break; + case SeparateType::SharedMedia: { + Assert(id.sharedMedia != SeparateSharedMediaType::None); + clearSectionStack(instant); + const auto type = (id.sharedMedia == SeparateSharedMediaType::Photos) + ? Storage::SharedMediaType::Photo + : (id.sharedMedia == SeparateSharedMediaType::Videos) + ? Storage::SharedMediaType::Video + : (id.sharedMedia == SeparateSharedMediaType::Files) + ? Storage::SharedMediaType::File + : (id.sharedMedia == SeparateSharedMediaType::Audio) + ? Storage::SharedMediaType::MusicFile + : (id.sharedMedia == SeparateSharedMediaType::Links) + ? Storage::SharedMediaType::Link + : (id.sharedMedia == SeparateSharedMediaType::Voices) + ? Storage::SharedMediaType::RoundVoiceFile + : (id.sharedMedia == SeparateSharedMediaType::GIF) + ? Storage::SharedMediaType::GIF + : Storage::SharedMediaType::Photo; + showSection( + std::make_shared(id.sharedMediaPeer(), type), + instant); + parent->widget()->setMaximumWidth(st::maxWidthSharedMediaWindow); + break; + } case SeparateType::SavedSublist: showSection( std::make_shared(id.sublist()), @@ -1782,6 +1806,9 @@ const rpl::variable &SessionController::shownForum() const { } void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) { + if (windowId().type == SeparateType::SharedMedia) { + return; + } const auto was = _activeChatEntry.current().key.history(); const auto now = row.key.history(); if (was && was != now) {