diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 9efcdd8784..877674edd9 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -170,7 +170,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_status" = "group"; "lng_scam_badge" = "SCAM"; "lng_fake_badge" = "FAKE"; -"lng_direct_badge" = "MESSAGES"; +"lng_direct_badge" = "DIRECT"; "lng_remember" = "Remember this choice"; diff --git a/Telegram/SourceFiles/dialogs/dialogs_key.h b/Telegram/SourceFiles/dialogs/dialogs_key.h index 58b0284dcc..de4f99f3ad 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_key.h +++ b/Telegram/SourceFiles/dialogs/dialogs_key.h @@ -113,6 +113,7 @@ struct EntryState { Replies, SavedSublist, ContextMenu, + SubsectionTabsMenu, ShortcutMessages, }; diff --git a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp index 932504952b..f8d664352b 100644 --- a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp +++ b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp @@ -23,13 +23,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "ui/controls/subsection_tabs_slider.h" #include "ui/effects/ripple_animation.h" +#include "ui/widgets/menu/menu_add_action_callback_factory.h" +#include "ui/widgets/menu/menu_add_action_callback.h" #include "ui/text/text_utilities.h" #include "ui/widgets/buttons.h" #include "ui/widgets/discrete_sliders.h" +#include "ui/widgets/popup_menu.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/dynamic_image.h" #include "ui/dynamic_thumbnails.h" +#include "window/window_peer_menu.h" #include "window/window_session_controller.h" #include "styles/style_chat.h" @@ -188,6 +192,12 @@ void SubsectionTabs::setupSlider( } }, slider->lifetime()); + slider->sectionContextMenu() | rpl::start_with_next([=](int index) { + if (index >= 0 && index < _slice.size()) { + showThreadContextMenu(_slice[index].thread); + } + }, slider->lifetime()); + rpl::merge( scroll->scrolls(), _scrollCheckRequests.events(), @@ -363,6 +373,27 @@ void SubsectionTabs::setupSlider( }, scroll->lifetime()); } +void SubsectionTabs::showThreadContextMenu(not_null thread) { + _menu = nullptr; + _menu = base::make_unique_q( + _horizontal ? _horizontal : _vertical, + st::popupMenuExpandedSeparator); + + const auto addAction = Ui::Menu::CreateAddActionCallback(_menu); + Window::FillDialogsEntryMenu( + _controller, + Dialogs::EntryState{ + .key = Dialogs::Key{ thread }, + .section = Dialogs::EntryState::Section::SubsectionTabsMenu, + }, + addAction); + if (_menu->empty()) { + _menu = nullptr; + } else { + _menu->popup(QCursor::pos()); + } +} + void SubsectionTabs::loadMore() { if (const auto forum = _history->peer->forum()) { forum->requestTopics(); diff --git a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h index d198a2fd79..200afe3b35 100644 --- a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h +++ b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/unique_qptr.h" #include "dialogs/dialogs_common.h" class History; @@ -21,6 +22,7 @@ class SessionController; namespace Ui { class RpWidget; +class PopupMenu; class ScrollArea; class SubsectionSlider; } // namespace Ui @@ -83,10 +85,13 @@ private: not_null scroll, not_null slider, bool vertical); + void showThreadContextMenu(not_null thread); const not_null _controller; const not_null _history; + base::unique_qptr _menu; + Ui::RpWidget *_horizontal = nullptr; Ui::RpWidget *_vertical = nullptr; Ui::RpWidget *_shadow = nullptr; diff --git a/Telegram/SourceFiles/ui/controls/subsection_tabs_slider.cpp b/Telegram/SourceFiles/ui/controls/subsection_tabs_slider.cpp index 15691b6e21..fbf6df2d0a 100644 --- a/Telegram/SourceFiles/ui/controls/subsection_tabs_slider.cpp +++ b/Telegram/SourceFiles/ui/controls/subsection_tabs_slider.cpp @@ -270,6 +270,10 @@ void SubsectionButton::setActiveShown(float64 activeShown) { } } +void SubsectionButton::contextMenuEvent(QContextMenuEvent *e) { + _delegate->buttonContextMenu(this, e); +} + SubsectionSlider::SubsectionSlider(not_null parent, bool vertical) : RpWidget(parent) , _vertical(vertical) @@ -407,6 +411,10 @@ rpl::producer SubsectionSlider::sectionActivated() const { return _sectionActivated.events(); } +rpl::producer SubsectionSlider::sectionContextMenu() const { + return _sectionContextMenu.events(); +} + int SubsectionSlider::lookupSectionPosition(int index) const { Expects(index >= 0 && index < _tabs.size()); @@ -472,6 +480,19 @@ float64 SubsectionSlider::buttonActive(not_null button) { : 0.; } +void SubsectionSlider::buttonContextMenu( + not_null button, + not_null e) { + const auto i = ranges::find( + _tabs, + button.get(), + &std::unique_ptr::get); + Assert(i != end(_tabs)); + + _sectionContextMenu.fire(int(i - begin(_tabs))); + e->accept(); +} + Text::MarkedContext SubsectionSlider::buttonContext() { return _context; } diff --git a/Telegram/SourceFiles/ui/controls/subsection_tabs_slider.h b/Telegram/SourceFiles/ui/controls/subsection_tabs_slider.h index 391c51964c..30d35aa190 100644 --- a/Telegram/SourceFiles/ui/controls/subsection_tabs_slider.h +++ b/Telegram/SourceFiles/ui/controls/subsection_tabs_slider.h @@ -42,6 +42,9 @@ public: virtual bool buttonPaused() = 0; virtual float64 buttonActive(not_null button) = 0; virtual Text::MarkedContext buttonContext() = 0; + virtual void buttonContextMenu( + not_null button, + not_null e) = 0; }; class SubsectionButton : public RippleButton { @@ -60,6 +63,8 @@ public: protected: virtual void dataUpdatedHook() = 0; + void contextMenuEvent(QContextMenuEvent *e) override; + const not_null _delegate; SubsectionTab _data; float64 _activeShown = 0.; @@ -79,10 +84,14 @@ public: [[nodiscard]] int sectionsCount() const; [[nodiscard]] rpl::producer sectionActivated() const; + [[nodiscard]] rpl::producer sectionContextMenu() const; [[nodiscard]] int lookupSectionPosition(int index) const; bool buttonPaused() override; float64 buttonActive(not_null button) override; + void buttonContextMenu( + not_null button, + not_null e) override; Text::MarkedContext buttonContext() override; [[nodiscard]] not_null buttonAt(int index); @@ -125,6 +134,7 @@ protected: bool _reorderAllowed = false; rpl::event_stream _sectionActivated; + rpl::event_stream _sectionContextMenu; Fn _paused; }; diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index bef9e3c6c9..026b1246dc 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -495,6 +495,10 @@ void Filler::addToggleTopicClosed() { void Filler::addTogglePin() { if ((!_sublist && !_peer) || (_topic && !_topic->canTogglePinned())) { return; + } else if (_request.section == Section::SubsectionTabsMenu + && !_sublist + && !_topic) { + return; } const auto controller = _controller; const auto filterId = _request.filterId; @@ -602,6 +606,10 @@ void Filler::addToggleFolder() { || !history->owner().chatsFilters().has() || !history->inChatList()) { return; + } else if (_request.section == Section::SubsectionTabsMenu + && !_sublist + && !_topic) { + return; } _addAction(PeerMenuCallback::Args{ .text = tr::lng_filters_menu_add(tr::now), @@ -689,7 +697,9 @@ void Filler::addNewWindow() { } void Filler::addToggleArchive() { - if (!_peer || _topic) { + if (!_peer + || _topic + || _request.section == Section::SubsectionTabsMenu) { return; } const auto peer = _peer; @@ -721,7 +731,7 @@ void Filler::addToggleArchive() { } void Filler::addClearHistory() { - if (_topic) { + if (_topic || _peer->isMonoforum()) { return; } const auto channel = _peer->asChannel(); @@ -1261,7 +1271,8 @@ void Filler::fill() { case Section::Profile: fillProfileActions(); break; case Section::Replies: fillRepliesActions(); break; case Section::Scheduled: fillScheduledActions(); break; - case Section::ContextMenu: fillContextMenuActions(); break; + case Section::ContextMenu: + case Section::SubsectionTabsMenu: fillContextMenuActions(); break; default: Unexpected("_request.section in Filler::fill."); } }