Open chat on exact clicked message from preview.

This commit is contained in:
John Preston 2024-05-03 21:10:14 +04:00
parent cd7cfcdf2f
commit de73d8766c
5 changed files with 80 additions and 14 deletions

View file

@ -2326,10 +2326,34 @@ void InnerWidget::showChatPreview(bool onlyUserpic) {
mousePressReleased(QCursor::pos(), Qt::NoButton, Qt::NoModifier); mousePressReleased(QCursor::pos(), Qt::NoButton, Qt::NoModifier);
_chatPreviewKey = key; _chatPreviewKey = key;
_menu = HistoryView::MakeChatPreview(this, key.entry()); auto preview = HistoryView::MakeChatPreview(this, key.entry());
if (!_menu) { if (!preview.menu) {
return; return;
} }
_menu = std::move(preview.menu);
const auto weakMenu = Ui::MakeWeak(_menu.get());
const auto weakThread = base::make_weak(key.entry()->asThread());
const auto weakController = base::make_weak(_controller);
std::move(
preview.actions
) | rpl::start_with_next([=](HistoryView::ChatPreviewAction action) {
if (const auto controller = weakController.get()) {
if (const auto thread = weakThread.get()) {
const auto itemId = action.openItemId;
const auto owner = &thread->owner();
if (action.openInfo) {
controller->showPeerInfo(thread);
} else if (const auto item = owner->message(itemId)) {
controller->showMessage(item);
} else {
controller->showThread(thread);
}
}
}
if (const auto strong = weakMenu.data()) {
strong->hideMenu();
}
}, _menu->lifetime());
QObject::connect(_menu.get(), &QObject::destroyed, [=] { QObject::connect(_menu.get(), &QObject::destroyed, [=] {
if (_chatPreviewKey) { if (_chatPreviewKey) {
updateDialogRow(RowDescriptor(base::take(_chatPreviewKey), {})); updateDialogRow(RowDescriptor(base::take(_chatPreviewKey), {}));

View file

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/menu/menu_item_base.h" #include "ui/widgets/menu/menu_item_base.h"
#include "window/themes/window_theme.h" #include "window/themes/window_theme.h"
#include "window/section_widget.h" #include "window/section_widget.h"
#include "window/window_session_controller.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
namespace HistoryView { namespace HistoryView {
@ -36,8 +37,12 @@ class Item final
public: public:
Item(not_null<Ui::RpWidget*> parent, not_null<Data::Thread*> thread); Item(not_null<Ui::RpWidget*> parent, not_null<Data::Thread*> thread);
not_null<QAction*> action() const override; [[nodiscard]] not_null<QAction*> action() const override;
bool isEnabled() const override; [[nodiscard]] bool isEnabled() const override;
[[nodiscard]] rpl::producer<ChatPreviewAction> actions() {
return _actions.events();
}
private: private:
int contentHeight() const override; int contentHeight() const override;
@ -146,6 +151,7 @@ private:
const std::unique_ptr<Ui::ElasticScroll> _scroll; const std::unique_ptr<Ui::ElasticScroll> _scroll;
QPointer<HistoryView::ListWidget> _inner; QPointer<HistoryView::ListWidget> _inner;
rpl::event_stream<ChatPreviewAction> _actions;
QImage _bg; QImage _bg;
@ -180,6 +186,22 @@ Item::Item(not_null<Ui::RpWidget*> parent, not_null<Data::Thread*> thread)
using Type = Ui::ElasticScroll::OverscrollType; using Type = Ui::ElasticScroll::OverscrollType;
_scroll->setOverscrollTypes(Type::Real, Type::Real); _scroll->setOverscrollTypes(Type::Real, Type::Real);
_scroll->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
if (e->type() == QEvent::MouseButtonPress) {
const auto relative = Ui::MapFrom(
_inner.data(),
_scroll.get(),
static_cast<QMouseEvent*>(e.get())->pos());
if (const auto view = _inner->lookupItemByY(relative.y())) {
_actions.fire(ChatPreviewAction{
.openItemId = view->data()->fullId(),
});
} else {
_actions.fire(ChatPreviewAction{});
}
}
}, lifetime());
_inner->resizeToWidth(_scroll->width(), _scroll->height()); _inner->resizeToWidth(_scroll->width(), _scroll->height());
_inner->refreshViewer(); _inner->refreshViewer();
@ -519,31 +541,36 @@ void Item::listLaunchDrag(
} // namespace } // namespace
base::unique_qptr<Ui::PopupMenu> MakeChatPreview( ChatPreview MakeChatPreview(
QWidget *parent, QWidget *parent,
not_null<Dialogs::Entry*> entry) { not_null<Dialogs::Entry*> entry) {
const auto thread = entry->asThread(); const auto thread = entry->asThread();
if (!thread) { if (!thread) {
return nullptr; return {};
} else if (const auto history = entry->asHistory()) { } else if (const auto history = entry->asHistory()) {
if (history->peer->isForum()) { if (history->peer->isForum()) {
return nullptr; return {};
} }
} }
auto result = base::make_unique_q<Ui::PopupMenu>( auto result = ChatPreview{
parent, .menu = base::make_unique_q<Ui::PopupMenu>(
st::previewMenu); parent,
st::previewMenu),
};
const auto menu = result.menu.get();
result->addAction(base::make_unique_q<Item>(result.get(), thread)); auto action = base::make_unique_q<Item>(menu, thread);
result.actions = action->actions();
menu->addAction(std::move(action));
if (const auto topic = thread->asTopic()) { if (const auto topic = thread->asTopic()) {
const auto weak = Ui::MakeWeak(result.get()); const auto weak = Ui::MakeWeak(menu);
topic->destroyed() | rpl::start_with_next([weak] { topic->destroyed() | rpl::start_with_next([weak] {
if (const auto strong = weak.data()) { if (const auto strong = weak.data()) {
LOG(("Preview hidden for a destroyed topic.")); LOG(("Preview hidden for a destroyed topic."));
strong->hideMenu(true); strong->hideMenu(true);
} }
}, result->lifetime()); }, menu->lifetime());
} }
return result; return result;

View file

@ -19,7 +19,17 @@ class PopupMenu;
namespace HistoryView { namespace HistoryView {
[[nodiscard]] base::unique_qptr<Ui::PopupMenu> MakeChatPreview( struct ChatPreviewAction {
FullMsgId openItemId;
bool openInfo = false;
};
struct ChatPreview {
base::unique_qptr<Ui::PopupMenu> menu;
rpl::producer<ChatPreviewAction> actions;
};
[[nodiscard]] ChatPreview MakeChatPreview(
QWidget *parent, QWidget *parent,
not_null<Dialogs::Entry*> entry); not_null<Dialogs::Entry*> entry);

View file

@ -1584,6 +1584,10 @@ bool ListWidget::hasSelectRestriction() const {
!= CopyRestrictionType::None; != CopyRestrictionType::None;
} }
Element *ListWidget::lookupItemByY(int y) const {
return strictFindItemByY(y);
}
auto ListWidget::findViewForPinnedTracking(int top) const auto ListWidget::findViewForPinnedTracking(int top) const
-> std::pair<Element*, int> { -> std::pair<Element*, int> {
const auto findScrollTopItem = [&](int top) const auto findScrollTopItem = [&](int top)

View file

@ -344,6 +344,7 @@ public:
[[nodiscard]] bool hasCopyRestrictionForSelected() const; [[nodiscard]] bool hasCopyRestrictionForSelected() const;
[[nodiscard]] bool showCopyRestrictionForSelected(); [[nodiscard]] bool showCopyRestrictionForSelected();
[[nodiscard]] bool hasSelectRestriction() const; [[nodiscard]] bool hasSelectRestriction() const;
[[nodiscard]] Element *lookupItemByY(int y) const;
[[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking( [[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking(
int top) const; int top) const;