Implement a special context menu for sender userpic.

This commit is contained in:
John Preston 2024-11-04 16:54:01 +04:00
parent 93c01e5f1e
commit 5f037462ed
14 changed files with 137 additions and 16 deletions

View file

@ -3623,6 +3623,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_make_paid" = "Make This Content Paid";
"lng_context_change_price" = "Change Price";
"lng_context_mention" = "Mention";
"lng_context_search_from" = "Search messages";
"lng_factcheck_title" = "Fact Check";
"lng_factcheck_placeholder" = "Add Facts or Context";
"lng_factcheck_whats_this" = "what's this?";

View file

@ -2204,6 +2204,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto linkPhoneNumber = link
? link->property(kPhoneNumberLinkProperty).toString()
: QString();
const auto linkUserpicPeerId = (link && _dragStateUserpic)
? link->property(kPeerLinkPeerIdProperty).toULongLong()
: 0;
const auto session = &this->session();
_whoReactedMenuLifetime.destroy();
if (!clickedReaction.empty()
@ -2227,6 +2230,14 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
return;
}
_menu = base::make_unique_q<Ui::PopupMenu>(this, st::popupMenuWithIcons);
if (linkUserpicPeerId) {
_widget->fillSenderUserpicMenu(
_menu.get(),
session->data().peer(PeerId(linkUserpicPeerId)));
_menu->popup(e->globalPos());
e->accept();
return;
}
const auto controller = _controller;
const auto addItemActions = [&](
HistoryItem *item,
@ -3938,6 +3949,7 @@ void HistoryInner::mouseActionUpdate() {
TextState dragState;
ClickHandlerHost *lnkhost = nullptr;
auto dragStateUserpic = false;
auto selectingText = (item == _mouseActionItem)
&& (view == Element::Hovered())
&& !_selected.empty()
@ -4033,6 +4045,7 @@ void HistoryInner::mouseActionUpdate() {
// stop enumeration if we've found a userpic under the cursor
if (point.y() >= userpicTop && point.y() < userpicTop + st::msgPhotoSize) {
dragState = TextState(nullptr, view->fromPhotoLink());
dragStateUserpic = true;
_dragStateItem = nullptr;
lnkhost = view;
return false;
@ -4044,6 +4057,7 @@ void HistoryInner::mouseActionUpdate() {
}
}
auto lnkChanged = ClickHandler::setActive(dragState.link, lnkhost);
_dragStateUserpic = dragStateUserpic;
if (lnkChanged || dragState.cursor != _mouseCursorState) {
Ui::Tooltip::Hide();
}

View file

@ -499,6 +499,7 @@ private:
HistoryItem *_dragStateItem = nullptr;
CursorState _mouseCursorState = CursorState();
uint16 _mouseTextSymbol = 0;
bool _dragStateUserpic = false;
bool _pressWasInactive = false;
bool _recountedAfterPendingResizedItems = false;
bool _useCornerReaction = false;

View file

@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/emoji_config.h"
#include "ui/chat/attach/attach_prepare.h"
#include "ui/chat/choose_theme_controller.h"
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/inner_dropdown.h"
#include "ui/widgets/dropdown_menu.h"
@ -5115,7 +5116,10 @@ bool HistoryWidget::updateCmdStartShown() {
return commandsChanged || buttonChanged || textChanged;
}
bool HistoryWidget::searchInChatEmbedded(Dialogs::Key chat, QString query) {
bool HistoryWidget::searchInChatEmbedded(
QString query,
Dialogs::Key chat,
PeerData *searchFrom) {
const auto peer = chat.peer(); // windows todo
if (!peer || Window::SeparateId(peer) != controller()->windowId()) {
return false;
@ -8071,6 +8075,18 @@ void HistoryWidget::editMessage(
setInnerFocus();
}
void HistoryWidget::fillSenderUserpicMenu(
not_null<Ui::PopupMenu*> menu,
not_null<PeerData*> peer) {
const auto inGroup = _peer && (_peer->isChat() || _peer->isMegagroup());
Window::FillSenderUserpicMenu(
controller(),
peer,
(inGroup && _canSendTexts) ? _field.data() : nullptr,
inGroup ? _peer->owner().history(_peer) : Dialogs::Key(),
Ui::Menu::CreateAddActionCallback(menu));
}
void HistoryWidget::hidePinnedMessage() {
Expects(_pinnedBar != nullptr);

View file

@ -211,6 +211,10 @@ public:
not_null<HistoryItem*> item,
const TextSelection &selection);
void fillSenderUserpicMenu(
not_null<Ui::PopupMenu*> menu,
not_null<PeerData*> peer);
[[nodiscard]] FullReplyTo replyTo() const;
bool lastForceReplyReplied(const FullMsgId &replyTo) const;
bool lastForceReplyReplied() const;
@ -263,7 +267,10 @@ public:
[[nodiscard]] rpl::producer<> cancelRequests() const {
return _cancelRequests.events();
}
bool searchInChatEmbedded(Dialogs::Key chat, QString query);
bool searchInChatEmbedded(
QString query,
Dialogs::Key chat,
PeerData *searchFrom = nullptr);
void updateNotifyControls();

View file

@ -329,7 +329,10 @@ void SublistWidget::setInternalState(
restoreState(memento);
}
bool SublistWidget::searchInChatEmbedded(Dialogs::Key chat, QString query) {
bool SublistWidget::searchInChatEmbedded(
QString query,
Dialogs::Key chat,
PeerData *searchFrom) {
const auto sublist = chat.sublist();
if (!sublist || sublist != _sublist) {
return false;

View file

@ -76,7 +76,10 @@ public:
return Window::SectionActionResult::Fallback;
}
bool searchInChatEmbedded(Dialogs::Key chat, QString query) override;
bool searchInChatEmbedded(
QString query,
Dialogs::Key chat,
PeerData *searchFrom = nullptr) override;
// Float player interface.
bool floatPlayerHandleWheelEvent(QEvent *e) override;

View file

@ -744,7 +744,10 @@ void MainWidget::hideSingleUseKeyboard(FullMsgId replyToId) {
_history->hideSingleUseKeyboard(replyToId);
}
void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
void MainWidget::searchMessages(
const QString &query,
Dialogs::Key inChat,
PeerData *searchFrom) {
const auto complex = Data::HashtagWithUsernameFromQuery(query);
if (!complex.username.isEmpty()) {
_controller->showPeerByLink(Window::PeerByLinkInfo{
@ -760,6 +763,7 @@ void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
.inChat = ((tags.empty() || inChat.sublist())
? inChat
: session().data().history(session().user())),
.fromPeer = inChat ? searchFrom : nullptr,
.tags = tags,
.query = tags.empty() ? query : QString(),
};
@ -779,12 +783,15 @@ void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
controller()->session().user());
}
if ((!_mainSection
|| !_mainSection->searchInChatEmbedded(inChat, query))
&& !_history->searchInChatEmbedded(inChat, query)) {
|| !_mainSection->searchInChatEmbedded(query, inChat, searchFrom))
&& !_history->searchInChatEmbedded(query, inChat, searchFrom)) {
const auto account = not_null(&session().account());
if (const auto window = Core::App().windowFor(account)) {
if (const auto controller = window->sessionController()) {
controller->content()->searchMessages(query, inChat);
controller->content()->searchMessages(
query,
inChat,
searchFrom);
controller->widget()->activate();
}
}

View file

@ -163,7 +163,10 @@ public:
void sendBotCommand(Bot::SendCommandRequest request);
void hideSingleUseKeyboard(FullMsgId replyToId);
void searchMessages(const QString &query, Dialogs::Key inChat);
void searchMessages(
const QString &query,
Dialogs::Key inChat,
PeerData *searchFrom = nullptr);
void setChatBackground(
const Data::WallPaper &background,

View file

@ -148,7 +148,10 @@ public:
MsgId messageId) {
return false;
}
virtual bool searchInChatEmbedded(Dialogs::Key chat, QString query) {
virtual bool searchInChatEmbedded(
QString query,
Dialogs::Key chat,
PeerData *searchFrom = nullptr) {
return false;
}

View file

@ -2727,6 +2727,53 @@ bool FillVideoChatMenu(
return has || manager;
}
void FillSenderUserpicMenu(
not_null<SessionController*> controller,
not_null<PeerData*> peer,
Ui::InputField *fieldForMention,
Dialogs::Key searchInEntry,
const PeerMenuCallback &addAction) {
const auto group = (peer->isChat() || peer->isMegagroup());
const auto channel = peer->isChannel();
const auto viewProfileText = group
? tr::lng_context_view_group(tr::now)
: channel
? tr::lng_context_view_channel(tr::now)
: tr::lng_context_view_profile(tr::now);
addAction(viewProfileText, [=] {
controller->showPeerInfo(peer, Window::SectionShow::Way::Forward);
}, channel ? &st::menuIconInfo : &st::menuIconProfile);
const auto showHistoryText = group
? tr::lng_context_open_group(tr::now)
: channel
? tr::lng_context_open_channel(tr::now)
: tr::lng_profile_send_message(tr::now);
addAction(showHistoryText, [=] {
controller->showPeerHistory(peer, Window::SectionShow::Way::Forward);
}, channel ? &st::menuIconChannel : &st::menuIconChatBubble);
const auto username = peer->username();
const auto mention = !username.isEmpty() || peer->isUser();
if (const auto guard = mention ? fieldForMention : nullptr) {
addAction(tr::lng_context_mention(tr::now), crl::guard(guard, [=] {
if (!username.isEmpty()) {
fieldForMention->insertTag('@' + username);
} else {
fieldForMention->insertTag(
peer->shortName(),
PrepareMentionTag(peer->asUser()));
}
}), &st::menuIconUsername);
}
if (searchInEntry) {
addAction(tr::lng_context_search_from(tr::now), [=] {
controller->searchInChat(searchInEntry, peer);
}, &st::menuIconSearch);
}
}
bool IsUnreadThread(not_null<Data::Thread*> thread) {
return thread->chatListBadgesState().unread;
}

View file

@ -34,6 +34,7 @@ namespace Dialogs {
class MainList;
struct EntryState;
struct UnreadState;
class Key;
} // namespace Dialogs
namespace ChatHelpers {
@ -64,6 +65,13 @@ bool FillVideoChatMenu(
Dialogs::EntryState request,
const PeerMenuCallback &addAction);
void FillSenderUserpicMenu(
not_null<SessionController*> controller,
not_null<PeerData*> peer,
Ui::InputField *fieldForMention,
Dialogs::Key searchInEntry,
const PeerMenuCallback &addAction);
void MenuAddMarkAsReadAllChatsAction(
not_null<Window::SessionController*> controller,
const PeerMenuCallback &addAction);

View file

@ -1175,14 +1175,17 @@ void SessionNavigation::showPollResults(
showSection(std::make_shared<Info::Memento>(poll, contextId), params);
}
void SessionNavigation::searchInChat(Dialogs::Key inChat) {
searchMessages(QString(), inChat);
void SessionNavigation::searchInChat(
Dialogs::Key inChat,
PeerData *searchFrom) {
searchMessages(QString(), inChat, searchFrom);
}
void SessionNavigation::searchMessages(
const QString &query,
Dialogs::Key inChat) {
parentController()->content()->searchMessages(query, inChat);
Dialogs::Key inChat,
PeerData *searchFrom) {
parentController()->content()->searchMessages(query, inChat, searchFrom);
}
auto SessionNavigation::showToast(Ui::Toast::Config &&config)

View file

@ -247,8 +247,11 @@ public:
FullMsgId contextId,
const SectionShow &params = SectionShow());
void searchInChat(Dialogs::Key inChat);
void searchMessages(const QString &query, Dialogs::Key inChat);
void searchInChat(Dialogs::Key inChat, PeerData *searchFrom = nullptr);
void searchMessages(
const QString &query,
Dialogs::Key inChat,
PeerData *searchFrom = nullptr);
void resolveBoostState(not_null<ChannelData*> channel);