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);
_chatPreviewKey = key;
_menu = HistoryView::MakeChatPreview(this, key.entry());
if (!_menu) {
auto preview = HistoryView::MakeChatPreview(this, key.entry());
if (!preview.menu) {
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, [=] {
if (_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 "window/themes/window_theme.h"
#include "window/section_widget.h"
#include "window/window_session_controller.h"
#include "styles/style_chat.h"
namespace HistoryView {
@ -36,8 +37,12 @@ class Item final
public:
Item(not_null<Ui::RpWidget*> parent, not_null<Data::Thread*> thread);
not_null<QAction*> action() const override;
bool isEnabled() const override;
[[nodiscard]] not_null<QAction*> action() const override;
[[nodiscard]] bool isEnabled() const override;
[[nodiscard]] rpl::producer<ChatPreviewAction> actions() {
return _actions.events();
}
private:
int contentHeight() const override;
@ -146,6 +151,7 @@ private:
const std::unique_ptr<Ui::ElasticScroll> _scroll;
QPointer<HistoryView::ListWidget> _inner;
rpl::event_stream<ChatPreviewAction> _actions;
QImage _bg;
@ -180,6 +186,22 @@ Item::Item(not_null<Ui::RpWidget*> parent, not_null<Data::Thread*> thread)
using Type = Ui::ElasticScroll::OverscrollType;
_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->refreshViewer();
@ -519,31 +541,36 @@ void Item::listLaunchDrag(
} // namespace
base::unique_qptr<Ui::PopupMenu> MakeChatPreview(
ChatPreview MakeChatPreview(
QWidget *parent,
not_null<Dialogs::Entry*> entry) {
const auto thread = entry->asThread();
if (!thread) {
return nullptr;
return {};
} else if (const auto history = entry->asHistory()) {
if (history->peer->isForum()) {
return nullptr;
return {};
}
}
auto result = base::make_unique_q<Ui::PopupMenu>(
parent,
st::previewMenu);
auto result = ChatPreview{
.menu = base::make_unique_q<Ui::PopupMenu>(
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()) {
const auto weak = Ui::MakeWeak(result.get());
const auto weak = Ui::MakeWeak(menu);
topic->destroyed() | rpl::start_with_next([weak] {
if (const auto strong = weak.data()) {
LOG(("Preview hidden for a destroyed topic."));
strong->hideMenu(true);
}
}, result->lifetime());
}, menu->lifetime());
}
return result;

View file

@ -19,7 +19,17 @@ class PopupMenu;
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,
not_null<Dialogs::Entry*> entry);

View file

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

View file

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