Show context menu for topics in new tabs.

This commit is contained in:
John Preston 2025-05-30 12:22:59 +04:00
parent 5b15f377cd
commit abe1962002
7 changed files with 83 additions and 4 deletions

View file

@ -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";

View file

@ -113,6 +113,7 @@ struct EntryState {
Replies,
SavedSublist,
ContextMenu,
SubsectionTabsMenu,
ShortcutMessages,
};

View file

@ -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<Data::Thread*> thread) {
_menu = nullptr;
_menu = base::make_unique_q<Ui::PopupMenu>(
_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();

View file

@ -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<Ui::ScrollArea*> scroll,
not_null<Ui::SubsectionSlider*> slider,
bool vertical);
void showThreadContextMenu(not_null<Data::Thread*> thread);
const not_null<Window::SessionController*> _controller;
const not_null<History*> _history;
base::unique_qptr<Ui::PopupMenu> _menu;
Ui::RpWidget *_horizontal = nullptr;
Ui::RpWidget *_vertical = nullptr;
Ui::RpWidget *_shadow = nullptr;

View file

@ -270,6 +270,10 @@ void SubsectionButton::setActiveShown(float64 activeShown) {
}
}
void SubsectionButton::contextMenuEvent(QContextMenuEvent *e) {
_delegate->buttonContextMenu(this, e);
}
SubsectionSlider::SubsectionSlider(not_null<QWidget*> parent, bool vertical)
: RpWidget(parent)
, _vertical(vertical)
@ -407,6 +411,10 @@ rpl::producer<int> SubsectionSlider::sectionActivated() const {
return _sectionActivated.events();
}
rpl::producer<int> 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<SubsectionButton*> button) {
: 0.;
}
void SubsectionSlider::buttonContextMenu(
not_null<SubsectionButton*> button,
not_null<QContextMenuEvent*> e) {
const auto i = ranges::find(
_tabs,
button.get(),
&std::unique_ptr<SubsectionButton>::get);
Assert(i != end(_tabs));
_sectionContextMenu.fire(int(i - begin(_tabs)));
e->accept();
}
Text::MarkedContext SubsectionSlider::buttonContext() {
return _context;
}

View file

@ -42,6 +42,9 @@ public:
virtual bool buttonPaused() = 0;
virtual float64 buttonActive(not_null<SubsectionButton*> button) = 0;
virtual Text::MarkedContext buttonContext() = 0;
virtual void buttonContextMenu(
not_null<SubsectionButton*> button,
not_null<QContextMenuEvent*> e) = 0;
};
class SubsectionButton : public RippleButton {
@ -60,6 +63,8 @@ public:
protected:
virtual void dataUpdatedHook() = 0;
void contextMenuEvent(QContextMenuEvent *e) override;
const not_null<SubsectionButtonDelegate*> _delegate;
SubsectionTab _data;
float64 _activeShown = 0.;
@ -79,10 +84,14 @@ public:
[[nodiscard]] int sectionsCount() const;
[[nodiscard]] rpl::producer<int> sectionActivated() const;
[[nodiscard]] rpl::producer<int> sectionContextMenu() const;
[[nodiscard]] int lookupSectionPosition(int index) const;
bool buttonPaused() override;
float64 buttonActive(not_null<SubsectionButton*> button) override;
void buttonContextMenu(
not_null<SubsectionButton*> button,
not_null<QContextMenuEvent*> e) override;
Text::MarkedContext buttonContext() override;
[[nodiscard]] not_null<SubsectionButton*> buttonAt(int index);
@ -125,6 +134,7 @@ protected:
bool _reorderAllowed = false;
rpl::event_stream<int> _sectionActivated;
rpl::event_stream<int> _sectionContextMenu;
Fn<bool()> _paused;
};

View file

@ -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.");
}
}