diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index e3240b970..91f1b1569 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1707,10 +1707,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_seen_loading" = "Loading..."; "lng_context_seen_text#one" = "{count} Seen"; "lng_context_seen_text#other" = "{count} Seen"; +"lng_context_seen_text_none" = "Nobody Viewed"; "lng_context_seen_listened#one" = "{count} Listened"; "lng_context_seen_listened#other" = "{count} Listened"; +"lng_context_seen_listened_none" = "Nobody Listened"; "lng_context_seen_watched#one" = "{count} Watched"; "lng_context_seen_watched#other" = "{count} Watched"; +"lng_context_seen_watched_none" = "Nobody Watched"; "lng_send_image_empty" = "Could not send an empty file: {name}"; "lng_send_image_too_large" = "Could not send a file, because it is larger than 1500 MB: {name}"; diff --git a/Telegram/SourceFiles/api/api_who_read.cpp b/Telegram/SourceFiles/api/api_who_read.cpp index ffb1006cb..6886751e4 100644 --- a/Telegram/SourceFiles/api/api_who_read.cpp +++ b/Telegram/SourceFiles/api/api_who_read.cpp @@ -12,9 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_peer.h" #include "data/data_chat.h" #include "data/data_channel.h" +#include "data/data_document.h" #include "data/data_user.h" #include "data/data_changes.h" #include "data/data_session.h" +#include "data/data_media_types.h" #include "main/main_app_config.h" #include "main/main_session.h" #include "main/main_account.h" @@ -26,6 +28,9 @@ namespace Api { namespace { struct Cached { + explicit Cached(UserId unknownFlag) + : list(std::vector{ unknownFlag }) { + } rpl::variable> list; mtpRequestId requestId = 0; }; @@ -33,6 +38,17 @@ struct Cached { struct Context { base::flat_map, Cached> cached; base::flat_map, rpl::lifetime> subscriptions; + + [[nodiscard]] Cached &cache(not_null item) { + const auto i = cached.find(item); + if (i != end(cached)) { + return i->second; + } + return cached.emplace( + item, + Cached(item->history()->session().userId()) + ).first->second; + } }; [[nodiscard]] auto Contexts() @@ -65,10 +81,39 @@ struct Context { return result; } +[[nodiscard]] bool ListUnknown( + const std::vector &list, + not_null item) { + return (list.size() == 1) + && (list.front() == item->history()->session().userId()); +} + +[[nodiscard]] Ui::WhoReadType DetectType(not_null item) { + if (const auto media = item->media()) { + if (!media->webpage()) { + if (const auto document = media->document()) { + if (document->isVoiceMessage()) { + return Ui::WhoReadType::Listened; + } else if (document->isVideoMessage()) { + return Ui::WhoReadType::Watched; + } + } + } + } + return Ui::WhoReadType::Seen; +} + } // namespace bool WhoReadExists(not_null item) { - if (!item->out() || item->unread()) { + if (!item->out()) { + return false; + } + const auto type = DetectType(item); + const auto unseen = (type == Ui::WhoReadType::Seen) + ? item->unread() + : item->isUnreadMedia(); + if (unseen) { return false; } const auto history = item->history(); @@ -122,38 +167,37 @@ rpl::producer> WhoReadIds( context->cached.erase(i); }, context->subscriptions[session]); } - auto &cache = context->cached[item]; - if (!cache.requestId) { + auto &entry = context->cache(item); + if (!entry.requestId) { const auto makeEmpty = [=] { // Special value that marks a validated empty list. return std::vector{ item->history()->session().userId() }; }; - cache.requestId = session->api().request( + entry.requestId = session->api().request( MTPmessages_GetMessageReadParticipants( item->history()->peer->input, MTP_int(item->id) ) ).done([=](const MTPVector &result) { + auto &entry = context->cache(item); + entry.requestId = 0; auto users = std::vector(); users.reserve(std::max(result.v.size(), 1)); for (const auto &id : result.v) { users.push_back(UserId(id)); } - if (users.empty()) { - - } - context->cached[item].list = users.empty() - ? makeEmpty() - : std::move(users); + entry.list = std::move(users); }).fail([=](const MTP::Error &error) { - if (context->cached[item].list.current().empty()) { - context->cached[item].list = makeEmpty(); + auto &entry = context->cache(item); + entry.requestId = 0; + if (ListUnknown(entry.list.current(), item)) { + entry.list = std::vector(); } }).send(); } - return cache.list.value().start_existing(consumer); + return entry.list.value().start_existing(consumer); }; } @@ -165,14 +209,9 @@ rpl::producer WhoRead( context ) | rpl::map([=](const std::vector &users) { const auto owner = &item->history()->owner(); - if (users.empty()) { + if (ListUnknown(users, item)) { return Ui::WhoReadContent{ .unknown = true }; } - const auto nobody = (users.size() == 1) - && (users.front() == owner->session().userId()); - if (nobody) { - return Ui::WhoReadContent(); - } auto participants = ranges::views::all( users ) | ranges::views::transform([&](UserId id) { @@ -187,6 +226,7 @@ rpl::producer WhoRead( }) | ranges::to_vector; return Ui::WhoReadContent{ .participants = std::move(participants), + .type = DetectType(item), }; }); } diff --git a/Telegram/SourceFiles/ui/controls/who_read_context_action.cpp b/Telegram/SourceFiles/ui/controls/who_read_context_action.cpp index 6059ea6fc..a5203a27b 100644 --- a/Telegram/SourceFiles/ui/controls/who_read_context_action.cpp +++ b/Telegram/SourceFiles/ui/controls/who_read_context_action.cpp @@ -121,6 +121,15 @@ Action::Action( paint(p); }, lifetime()); + clicks( + ) | rpl::start_with_next([=] { + if (_content.participants.size() == 1) { + if (const auto onstack = _participantChosen) { + onstack(_content.participants.front().id); + } + } + }, lifetime()); + enableMouseSelecting(); } @@ -129,9 +138,10 @@ void Action::resolveMinWidth() { const auto width = [&](const QString &text) { return _st.itemStyle.font->width(text); }; - const auto maxTextWidth = std::max( + const auto maxTextWidth = std::max({ width(tr::lng_context_seen_text(tr::now, lt_count, 999)), - width(tr::lng_context_seen_listened(tr::now, lt_count, 999))); + width(tr::lng_context_seen_listened(tr::now, lt_count, 999)), + width(tr::lng_context_seen_watched(tr::now, lt_count, 999)) }); const auto maxWidth = _st.itemPadding.left() + maxIconWidth + maxTextWidth @@ -160,7 +170,7 @@ void Action::updateUserpicsFromContent() { } void Action::populateSubmenu() { - if (_content.participants.empty()) { + if (_content.participants.size() < 2) { _parentMenu->removeSubmenu(action()); return; } @@ -172,6 +182,7 @@ void Action::populateSubmenu() { }; submenu->addAction(participant.name, chosen); } + _parentMenu->checkSubmenuShow(); } void Action::paint(Painter &p) { @@ -206,10 +217,16 @@ void Action::refreshText() { : (count == 1) ? _content.participants.front().name : (_content.type == WhoReadType::Watched) - ? tr::lng_context_seen_watched(tr::now, lt_count, count) + ? (count + ? tr::lng_context_seen_watched(tr::now, lt_count, count) + : tr::lng_context_seen_watched_none(tr::now)) : (_content.type == WhoReadType::Listened) - ? tr::lng_context_seen_listened(tr::now, lt_count, count) - : tr::lng_context_seen_text(tr::now, lt_count, count)) }, + ? (count + ? tr::lng_context_seen_listened(tr::now, lt_count, count) + : tr::lng_context_seen_listened_none(tr::now)) + : (count + ? tr::lng_context_seen_text(tr::now, lt_count, count) + : tr::lng_context_seen_text_none(tr::now))) }, MenuTextOptions); } diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 6651d9f9b..f4cf3094c 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 6651d9f9b6fb7ebc9d18e6b3429862477d891b2e +Subproject commit f4cf3094c29e445256bd1c198323d393be4405c1