diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 77a065e20f..86ddc9cc3e 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4252,6 +4252,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_seen_reacted#other" = "{count} Reacted"; "lng_context_seen_reacted_none" = "Nobody Reacted"; "lng_context_seen_reacted_all" = "Show All Reactions"; +"lng_context_sent_by" = "Sent by {user}"; "lng_context_set_as_quick" = "Set As Quick"; "lng_context_filter_by_tag" = "Filter by Tag"; "lng_context_tag_add_name" = "Add Name"; diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index c4c689c4b1..230c2ac31b 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -269,6 +269,11 @@ whenReadPadding: margins(34px, 3px, 17px, 4px); whenReadIconPosition: point(8px, 0px); whenReadSkip: 3px; whenReadShowPadding: margins(6px, 0px, 6px, 2px); +whoSentItem: Menu(defaultMenu) { + itemPadding: margins(17px, 3px, 17px, 4px); + itemRightSkip: 0px; + itemStyle: whenReadStyle; +} switchPmButton: RoundButton(defaultBoxButton) { width: 320px; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 20a147fca7..3978655b7b 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -3103,7 +3103,10 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { leaderOrSelf, _controller); } else if (leaderOrSelf) { - HistoryView::MaybeAddWhenEditedForwardedAction(_menu, leaderOrSelf); + HistoryView::MaybeAddWhenEditedForwardedAction( + _menu, + leaderOrSelf, + _controller); } if (_menu->empty()) { diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 39c983ac7d..58e747454a 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1706,6 +1706,10 @@ bool HistoryItem::isSponsored() const { return _flags & MessageFlag::Sponsored; } +bool HistoryItem::canLookupMessageAuthor() const { + return isRegular() && _history->amMonoforumAdmin() && _from->isChannel(); +} + bool HistoryItem::skipNotification() const { if (isSilent() && (_flags & MessageFlag::IsContactSignUp)) { return true; @@ -1713,8 +1717,7 @@ bool HistoryItem::skipNotification() const { if (forwarded->imported) { return true; } - } else if (_history->amMonoforumAdmin() - && from() == _history->peer->monoforumBroadcast()) { + } else if (canLookupMessageAuthor()) { return true; } return false; diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 6a64ccfe4c..55904615ce 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -179,6 +179,7 @@ public: [[nodiscard]] bool isFromScheduled() const; [[nodiscard]] bool isScheduled() const; [[nodiscard]] bool isSponsored() const; + [[nodiscard]] bool canLookupMessageAuthor() const; [[nodiscard]] bool skipNotification() const; [[nodiscard]] bool isUserpicSuggestion() const; [[nodiscard]] BusinessShortcutId shortcutId() const; diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index d156b8fc73..58ea3e210e 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -113,7 +113,8 @@ bool HasEditMessageAction( || (context != Context::History && context != Context::Replies && context != Context::ShortcutMessages - && context != Context::ScheduledTopic)) { + && context != Context::ScheduledTopic + && context != Context::Monoforum)) { return false; } const auto peer = item->history()->peer; @@ -1154,6 +1155,97 @@ void ShowWhoReadInfo( controller->showSection(std::move(memento)); } +[[nodiscard]] rpl::producer> LookupMessageAuthor( + not_null item) { + struct Author { + UserData *user = nullptr; + std::vector> callbacks; + }; + struct Authors { + base::flat_map map; + }; + static auto Cache = base::flat_map, Authors>(); + + const auto channel = item->history()->peer->asChannel(); + const auto session = &channel->session(); + const auto id = item->fullId(); + if (!Cache.contains(session)) { + Cache.emplace(session); + session->lifetime().add([session] { + Cache.remove(session); + }); + } + + return [channel, id](auto consumer) { + const auto session = &channel->session(); + auto &map = Cache[session].map; + auto i = map.find(id); + if (i == end(map)) { + i = map.emplace(id).first; + const auto finishWith = [=](UserData *user) { + auto &entry = Cache[session].map[id]; + entry.user = user; + for (const auto &callback : base::take(entry.callbacks)) { + callback(user); + } + }; + session->api().request(MTPchannels_GetMessageAuthor( + channel->inputChannel, + MTP_int(id.msg.bare) + )).done([=](const MTPUser &result) { + finishWith(session->data().processUser(result)); + }).fail([=] { + finishWith(nullptr); + }).send(); + } else if (const auto user = i->second.user + ; user || i->second.callbacks.empty()) { + if (user) { + consumer.put_next(not_null(user)); + } + return rpl::lifetime(); + } + + auto lifetime = rpl::lifetime(); + const auto done = [=](UserData *result) { + if (result) { + consumer.put_next(not_null(result)); + } + }; + const auto guard = lifetime.make_state(); + i->second.callbacks.push_back(crl::guard(guard, done)); + return lifetime; + }; +} + +[[nodiscard]] base::unique_qptr MakeMessageAuthorAction( + not_null menu, + not_null item, + not_null controller) { + const auto parent = menu->menu(); + const auto user = std::make_shared(nullptr); + const auto action = Ui::Menu::CreateAction( + parent, + tr::lng_contacts_loading(tr::now), + [=] { if (*user) { controller->showPeerInfo(*user); } }); + action->setDisabled(true); + auto lifetime = LookupMessageAuthor( + item + ) | rpl::start_with_next([=](not_null author) { + action->setText( + tr::lng_context_sent_by(tr::now, lt_user, author->name())); + action->setDisabled(false); + *user = author; + }); + auto result = base::make_unique_q( + menu->menu(), + st::whoSentItem, + action, + nullptr, + nullptr); + result->lifetime().add(std::move(lifetime)); + return result; +} + } // namespace ContextMenuRequest::ContextMenuRequest( @@ -1292,7 +1384,7 @@ base::unique_qptr FillContextMenu( if (hasWhoReactedItem) { AddWhoReactedAction(result, list, item, list->controller()); } else if (item) { - MaybeAddWhenEditedForwardedAction(result, item); + MaybeAddWhenEditedForwardedAction(result, item, list->controller()); } return result; @@ -1466,9 +1558,10 @@ void AddSaveSoundForNotifications( }, &st::menuIconSoundAdd); } -void AddWhenEditedForwardedActionHelper( +void AddWhenEditedForwardedAuthorActionHelper( not_null menu, not_null item, + not_null controller, bool insertSeparator) { if (const auto forwarded = item->Get()) { if (!forwarded->story && forwarded->psaType.isEmpty()) { @@ -1489,6 +1582,12 @@ void AddWhenEditedForwardedActionHelper( Api::WhenEdited(item->from(), edited->date))); } } + if (item->canLookupMessageAuthor()) { + if (insertSeparator && !menu->empty()) { + menu->addSeparator(&st::expandedMenuSeparator); + } + menu->addAction(MakeMessageAuthorAction(menu, item, controller)); + } } void AddWhoReactedAction( @@ -1539,7 +1638,11 @@ void AddWhoReactedAction( menu->addSeparator(&st::expandedMenuSeparator); } if (item->history()->peer->isUser()) { - AddWhenEditedForwardedActionHelper(menu, item, false); + AddWhenEditedForwardedAuthorActionHelper( + menu, + item, + controller, + false); menu->addAction(Ui::WhenReadContextAction( menu.get(), Api::WhoReacted(item, context, st::defaultWhoRead, whoReadIds), @@ -1551,14 +1654,19 @@ void AddWhoReactedAction( Data::ReactedMenuFactory(&controller->session()), participantChosen, showAllChosen)); - AddWhenEditedForwardedActionHelper(menu, item, true); + AddWhenEditedForwardedAuthorActionHelper( + menu, + item, + controller, + true); } } void MaybeAddWhenEditedForwardedAction( not_null menu, - not_null item) { - AddWhenEditedForwardedActionHelper(menu, item, true); + not_null item, + not_null controller) { + AddWhenEditedForwardedAuthorActionHelper(menu, item, controller, true); } void AddEditTagAction( diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.h b/Telegram/SourceFiles/history/view/history_view_context_menu.h index 0e14fa8034..fb26345500 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.h +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.h @@ -88,7 +88,8 @@ void AddWhoReactedAction( not_null controller); void MaybeAddWhenEditedForwardedAction( not_null menu, - not_null item); + not_null item, + not_null controller); void ShowWhoReactedMenu( not_null*> menu, QPoint position,